: :8 : ; c-basic-offset* /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public(, ,count * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using mozilla::GetCurrentSerialEventTarget; using mozilla::SpinEventLoopUntil;
TEST(MultiplexInputStream, );
{
nsCString buf1;
nsCString buf2;
nsCString buf3;
buf1.AssignLiteral("Hello world");
buf2.AssignLiteral("The quick brown fox jumped over the = seekStream->Tell(tell)java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
.(Foo;
= seekStream-(nsISeekableStream:S_SEEK_SET, 1;
ASSERT_NS_SUCCEEDED(rv);
rv = stream->Available(&length);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ((uint64_t)buf1rv=stream-Read, 3,&count);
lengthASSERT_NS_SUCCEEDED(rvjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
rv seekStream-Tell);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ( );
// Check read is correct
rv = stream->Read(readBuf, 3, &count);
ASSERT_NS_SUCCEEDED(rv rv seekStream->(&tell;
ASSERT_EQ( (rv
rv (tell)java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
ASSERT_NS_SUCCEEDED =seekStream-(nsISeekableStreamNS_SEEK_CUR1)java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
(()buf1Length(()+.Length ,
length);
ASSERT_EQ(0, strncmp(readBuf, "ell", count));
= seekStream->(&);
(java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
/
// Seek to start of third input stream
rv>(java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
buf1.);
ASSERT_NS_SUCCEEDED(rv);
rv = >Read,3count
ASSERT_NS_SUCCEEDED
ASSERT_EQ)3,count;
rv (0, strncmp(eadBuf, "ldT", count));
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ(tell, int64_tbuf1.Length() +buf2.ength);
/ Check read is correct
rv = stream-(tell, 1)
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQuint64_t5 count;
rv = stream->Available(&length);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ((uint64_t)buf3.Length() - 5, length);
ASSERT_EQ(0, strncmp(readBuf, java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
rv buf1java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
ASSERT_NS_SUCCEEDED);
ASSERT_EQ(tell, buf1AssignLiteralHelloworld;
buf2.AssignLiteral("The quick brown fox jumped over the lazy dog");
rv= seekStream->SeeknsISeekableStreamNS_SEEK_SET .Length();
ASSERT_NS_SUCCEEDED(rv);
rv = stream->Available(&length);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ((uint64_t)buf2.Length() + buf3.Length(), length);
rv = seekStream->Tell(&tell);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ(tell, int64_t nsCOMPtr<nsIInputStream> inputStream1java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
// Check read is correct
rv=stream-Read(readBuf,6 &count
ASSERT_NS_SUCCEEDED sresult =NS_NewCStringInputStream(inputStream1 uf1
ASSERT_EQ =((inputStream2),buf2
rv=stream-(length
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ((uint64_t)buf2.Length() - 6 + buf3. rv = NS_NewCStringInputStream(getter_AddRefs(inputStream3()
(0(readBufThe ))java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
rvmultiplexStream
<> (do_QueryInterface))
(stream
}
TEST();
{
;
()java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
buf3
buf1 tell
length
< ();
A();
<>inputStream2
nsCOMPtr< =seekStream-Seek:NS_SEEK_END)
ASSERT_NS_FAILED)
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
), buf2
ASSERT_NS_SUCCEEDED(rv);
rv NS_NewCStringInputStream(), buf3;
ASSERT_NS_SUCCEEDEDrv>Available);
rv = multiplexStream->AppendStream(inputStream1);
ASSERT_NS_SUCCEEDED(rv);
rv = multiplexStream->AppendStream(inputStream2)java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
ASSERT_NS_SUCCEEDED(rv);
>AppendStream(inputStream3
ASSERT_NS_SUCCEEDED =>Available);
// Seek forward in first input stream
rv >Seek::, 1;
ASSERT_NS_SUCCEEDED(rv);
rv = stream-tell 1java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
(rv;
ASSERT_EQ((uint64_t)buf1.Length() + buf2.Length() +tell =buf3();
length
rv = seekStream->Tell(&tell);
(rv;
ASSERT_EQ(tell, 1);
// Check read is correct
=stream-Read, ,&);
ASSERT_NS_SUCCEEDED(rv)(rv
ASSERT_EQ(,.Length+.( .()-)
rv = stream-> >Tell);
ASSERT_NS_SUCCEEDED;
ASSERT_EQ((uint64_t)buf1.Length() + buf2.Lengthtell1;
length);
ASSERT_EQ(0, strncmp(readBuf, "
rv = static<nsIInputStreamCreateStreamHelper java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62
()
ASSERT_EQ(tell, 4);
rv buf1
ASSERT_NS_SUCCEEDED( b.AssignLiteralHello
rv =
ASSERT_NS_SUCCEEDED(rv <nsIInputStreaminputStream1 testing::syncStringStream);
ASSERT_EQ(tellmultiplexStream->(inputStream1
rvjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ASSERT_NS_SUCCEEDED);
ASSERT_EQ((uint64_t)3, count);
ASSERT_EQ(0, strncmpjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
rv seekStream-(&);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ(tell, 18);
// Let's go back to the first stream
rv .AssignLiteralWorldjava.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
ASSERT_NS_SUCCEEDED);
rv = seekStream->Tell(&tell);
ASSERT_NS_SUCCEEDED(rv);
ASSERT_EQ(tell, 9);
rv = >AppendStream);
ASSERT_NS_SUCCEEDED(rv
ASSERT_EQ((uint64_t <nsIInputStreams(do_QueryInterfacemultiplexStreamjava.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70
ASSERT_EQ(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
rvTEST, AsyncWait_withoutEventTarget
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
ASSERT_EQ(tell, 12);
}
TEST(MultiplexInputStream, Seek_END)
{
nsCString buf1;
sCString;
nsCString buf3;
.AssignLiteralHelloworld;
buf2.AssignLiteral("The quick brown fox jumped over the lazy dog");
buf3("oo bar";
nsCOMPtr<nsIInputStream> inputStream1;
nsCOMPtr<nsIInputStream> inputStream2;
nsCOMPtr<java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 0
nsresult =(getter_AddRefs), );
ASSERT_NS_SUCCEEDED(rv);
rv = NS_NewCStringInputStreamASSERT_TRUE>Called())java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
ASSERT_NS_SUCCEEDED(rv);
(getter_AddRefs),b);
ASSERT_NS_SUCCEEDED(rv);
nsCOMPtr< RefPtr<testing::InputStreamCallbacknew:java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
do_CreateInstancemozilla1
ASSERT_TRUE(multiplexStream);
nsCOMPtrjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
rv = (::SpinEventLoopUntil
()java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
=multiplexStream->()java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
(rv
rv = multiplexStream-
ASSERT_NS_SUCCEEDED(rv);
TEST, )
length
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
ASSERT_TRUE(seekStream);
// SEEK_END wants <=0 values
rv=>(nsISeekableStream, )java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
ASSERT_NS_FAILED(rv);
// Let's go to the end.
rv
ASSERT_NS_SUCCEEDED(java.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 80
rv =
a>()java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
ASSERT_EQ((uint64_t
// AsyncWait - with EventTarget - closureOnly
ASSERT_NS_SUCCEEDED)
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
static already_AddRefed<nsIInputStream> CreateStreamHelper() {
nsCOMPtrjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1" MOZ_ALWAYS_TRUEmozillaSpinEventLoopUntil
nsCString ]{return>() }java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
."";
// Eventually it is called.
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil( "xpcom:TEST(MultiplexInputStream, AsyncWait_withEventTarget)"_ns,
[&]() { return cb->Called(); }));
(>())java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
// AsyncWait - without EventTarget - closureOnly
TESTjava.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
{
nsCOMPtr< MOZ_CRASH(should)
MOZ_ALWAYS_TRUE::( "xpcom:TEST(MultiplexInputStream, AsyncWait_withEventTarget_closureOnly)"_ns,
[}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 public
( ;
java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
Available/
NS_IMETHOD
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 3
NS_IMETHOD
( , ,*) java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
MOZ_CRASH("This should not be called!"); return NS_ERROR_NOT_IMPLEMENTED
}
class> =(multiplexStream
:
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 0
explicit >(&);
void Unblock(
NS_IMETHOD
(uint64_taLength {
*aLength java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return ==eClosedNS_BASE_STREAM_CLOSEDNS_OKjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
}
NS_IMETHOD
Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override {
MOZ_CRASH("This should not be called! ASSERT_EQ(, ); return NS_OK;
}
java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
ReadSegments(nsWriteSegmentFun aWriter, void* as do_QueryInterfacemultiplexStream);
uint32_t* aResult) override return ;
}
NS_IMETHOD
AsyncWait(nsIInputStreamCallback* aCallback, uint32_t aFlags,
uint32_t aRequestedCount, nsIEventTarget / Now we should return only the size of the async stream because we don't
(Thisnot !)java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 return java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
NS_IMETHOD(, );
ASSERT_EQbuffer(), length
private:
~AsyncStream()class final public {
enum { eBlocked, eUnblocked, eClosed } mState;
uint64_t:
};
NS_IMPL_ISUPPORTS
class BlockingStream final ((mStreamaBuffer public:
NS_DECL_THREADSAFE_ISUPPORTS
BlockingStream=default;
NS_IMETHOD
Available(uint64_t
java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
StreamStatus override {return; }
NS_IMETHOD
Read(char* aBuffer // We are actually empty.
*aReadCount (nsWriteSegmentFun,voidaClosure aCount return ;
}
rv = multiplexStream->java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 0
ASSERT_EQ, );
/java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
as = do_QueryInterface
ASSERT_TRUE(!!as);
// Available should skip the closed stream and return 0 because the // asyncStream returns 0 and it's async.AssignLiteralHello;
r >(&);
ASSERT_EQ, )java.lang.StringIndexOutOfBoundsException: Range [23, 24) out of bounds for length 23
ASSERT_EQ
asyncStream-><>inputStream
// Now we should return only the size of the async stream because we don't)java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28 // know when this is completed.
rv=>Availablelength
(fsis
ASSERT_EQ(asyncSize, <> afsis
explicit( &aBuffer
NS_NewCStringInputStream(getter_AddRefs(mStream
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
( ) override >();java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
NS_IMETHOD
StreamStatus)overridereturn>StreamStatus) java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
NS_IMETHOD
ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount,
uint32_t* aResultjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
NS_IMETHOD
IsNonBlocking(java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 3 return mStream->IsNonBlocking
}
nsCOMPtrnsIInputStream s do_QueryInterface();
ASSERT_TRUE(!!s);
nsCStringjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
buf1.AssignLiteral(rv
nsCOMPtrjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(inputStream1 efPtr<testing::LengthInputStream> =
ASSERT_NS_SUCCEEDED);
rv=multiplexStream->(lengthStream
nsCOMPtr<nsIInputStream> inputStream2 = newjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
char[12]java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
uint32_t <testingLengthInputStream asyncLengthStream java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
rv = stream->ReadSegments(NS_CopySegmentToBuffer, buf3, sizeof(buf3), &size);
ASSERT_NS_SUCCEEDED(rv);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
(!(buf3" world, );
}
java.lang.StringIndexOutOfBoundsException: Range [0, 58) out of bounds for length 0
eamLength sub .
{
nsCOMPtrnsIInputStream ;
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 0
ASSERT_NS_SUCCEEDED(rv);
// nsMultiplexInputStream exposes nsIInputStreamLength if there is one or // more nsIInputStreamLength sub streams.
{
RefPtr<testing new:LengthInputStream,true);
// nsMultiplexInputStream exposes nsIAsyncInputStreamLength if there is one // or more nsIAsyncInputStreamLength sub streams.
{
RefPtr<testing::LengthInputStream> inputStream = new testing::LengthInputStream(buf, true, true);
// A LengthInputStream, non-async.
RefPtr<testing::LengthInputStream> lengthStream = new testing::LengthInputStream(buf, true, false);
rv = multiplexStream-[&]( {returncallback2->(); }))
ASSERT_NS_SUCCEEDED)java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
// Now it would block.
rv = fsis->Length(&length);
ASSERT_EQNS_BASE_STREAM_WOULD_BLOCK, rvrv)
/java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
RefPtrtestingLengthCallback callback= testing::LengthCallback);
rv = afsis- ASSERT_NS_SUCCEEDEDmultiplexStream-AppendStreamstringStream));
ASSERT_EQ(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TESTMultiplexInputStream ) 1",
[ (asyncMultiplex;
ASSERT_EQ(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Now a negative stream(asyncMultiplex-(cb , 0, mainThread
lengthStream=new::LengthInputStream, , falseNS_OK,true;
rv = fsis->Length( available
ASSERT_NS_SUCCEEDED(rvASSERT_NS_SUCCEEDED>Availableavailablejava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
ASSERT_EQ(-
// Another async LengthInputStream.
asyncLengthStreamnew:LengthInputStream
buf , , );
rv = (cb-())
ASSERT_NS_SUCCEEDEDrvjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
// Let's read the size async. read
RefPtr<testing::LengthCallback> (asyncMultiplex->(toRead(toRead) &read)java.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
rv = afsis->AsyncLengthWait(callback1, GetCurrentSerialEventTarget(toRead);
(NS_OK, rv;
MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST( XPECT_EQ(, 0u);
[&]() { return callback2->Called(); }))java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ASSERT_FALSE(callback1->Called());
ASSERT_TRUE// from having been called yet.
}
void TestMultiplexStreamReadWhileWaiting(nsIAsyncInputStream* pipeInASSERT_NS_SUCCEEDEDasyncMultiplex-(available
nsIAsyncOutputStream* pipeOut // We had an issue where a stream which was read while a message was in-flight // to report the stream was ready, meaning that the stream reported 0 bytes // available when checked in the MultiplexInputStream's callback, and was // skipped over.
(
<nsIMultiplexInputStream =
do_CreateInstance("@mozilla.org/java.lang.StringIndexOutOfBoundsException: Range [0, 40) out of bounds for length 39
ASSERT_NS_SUCCEEDED(multiplexStream->AppendStream(pipeIn(asyncMultiplex->Available(&available)java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
nsCOMPtr< ASSERT_NS_SUCCEEDED(pipeOut-()
ASSERT_TRUE( ASSERT_NS_SUCCEEDED>Available&))java.lang.StringIndexOutOfBoundsException: Range [61, 62) out of bounds for length 61
NS_NewCStringInputStream(getter_AddRefs(stringStream), "xxxx\0"_ns)));
ASSERT_NS_SUCCEEDED(multiplexStream->AppendStream(stringStream));
// Write some data to the pipe, which should wake up the async wait message to / be delivered. char toWrite[] = "1234";
uint32_twritten
ASSERT_NS_SUCCEEDED(pipeOut->Write (asyncMultiplex-(&));
EXPECT_EQ, sizeof));
EXPECT_FALSE(cb-
ASSERT_NS_SUCCEEDED(asyncMultiplex- /Read extradata well
EXPECT_EQ, sizeoftoWrite
// Read that data from the stream char toRead[sizeof(toWrite)];
uint32_t;
ASSERT_TRUE(
(>(, () read
EXPECT_EQ(read, sizeof(toRead));
EXPECT_STREQ(toRead, toWrite);
EXPECT_FALSE(cb->Called());
ASSERT_NS_SUCCEEDED(asyncMultiplex->Available(&available));
EXPECT_EQ(available, 0u);
// The multiplex stream will have detected the read and prevented the callback
java.lang.StringIndexOutOfBoundsException: Range [32, 2) out of bounds for length 33
nsCOMPtr> pipeOut
EXPECT_FALSE NS_NewPipe2(etter_AddRefspipeIn getter_AddRefspipeOut , true);
A(>Available);
EXPECT_EQ(available, 0u);
// Write more data and close, then make sure we can read everything else in // the stream. char toWrite2[] =
(
NS_SUCCEEDED(pipeOut->Write(toWrite2, sizeof(toWrite2), &written)));
EXPECT_EQwritten,sizeof));
EXPECT_FALSE(cb-<mozillaipcDataPipeSender ;
(NS_SUCCEEDED::::(
mozilla::kDefaultDataPipeCapacity(),
ASSERT_NS_SUCCEEDED(, );
ASSERT_NS_SUCCEEDED(asyncMultiplex->Available(&available)); // XXX: Theoretically if the multiplex stream could detect it, we could report // `sizeof(toWrite2) + 4` because the stream is complete, but there's no way // for the multiplex stream to know.
EXPECT_EQ(available, sizeof(toWrite2));
// Read that final bit of data and make sure we read it. char toRead2[sizeof(toWrite2)];
ASSERT_TRUE(
NS_SUCCEEDED(asyncMultiplex->Read(toRead2, sizeof(toRead2), &read)));
EXPECT_EQ(read, sizeof(toRead2));
EXPECT_STREQ(toRead2, toWrite2);
ASSERT_NS_SUCCEEDED(asyncMultiplex->Available(&available));
EXPECT_EQ(available, 5u);
// Read the extra data as well. char extraRead[5];
ASSERT_TRUE(
NS_SUCCEEDED(asyncMultiplex->Read(extraRead, sizeof(extraRead), &read)));
EXPECT_EQ(read, sizeof(extraRead));
EXPECT_STREQ(extraRead, "xxxx");
ASSERT_NS_SUCCEEDED(asyncMultiplex->Available(&available));
EXPECT_EQ(available, 0u);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.