DiffMessage: successfully finish extended integration test

now we're able to inject flocks of Borg into the alpha quadrant by diff message
This commit is contained in:
Fischlurch 2017-08-13 05:17:16 +02:00
parent 3b547ce3d0
commit 5ea80f39cb
4 changed files with 165 additions and 84 deletions

View file

@ -28,6 +28,7 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/sync.hpp"
#include "lib/sync-classlock.hpp"
#include "backend/thread-wrapper.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "gui/ctrl/state-manager.hpp"
@ -46,13 +47,18 @@
#include "lib/luid.h"
#include "lib/util.hpp"
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using lib::Sync;
using lib::ClassLock;
using backend::ThreadJoinable;
using lib::iter_stl::dischargeToSnapshot;
using lib::IterQueue;
using lib::IterStack;
using std::function;
using util::contains;
using util::isnil;
using util::_Fmt;
@ -89,11 +95,13 @@ namespace test {
namespace {// test data...
// --------random-dispatch-test------
uint const MAX_RAND_NUMBS = 200;
uint const MAX_RAND_BORGS = 500;
uint const MAX_RAND_DELAY = 1000;
// --------random-dispatch-test------
// --------random-diff-test------
uint const MAX_RAND_BORGS = 100; // stay below 400, verification export grows quadratic
uint const MAX_RAND_NUMBS = 500;
uint const MAX_RAND_DELAY = 5000; // throttle generation, since diff application is slower
// --------random-diff-test------
int generator_instances = 0;
}
@ -110,13 +118,14 @@ namespace test {
* This test enacts the fundamental generic communication patterns
* to verify the messaging behaviour
* - attaching a \ref BusTerm
* - generating a command invocation
* - detaching on element destruction
* - generate a command invocation
* - argument passing
* - capture a _state mark_
* - replay a _state mark_
* - cast messages and error states downstream
* - generic operating of interface states
* - detaching on element destruction
* - multithreaded integration test of diff mutation
*
* @see AbstractTangible_test
* @see gui::model::Tangible
@ -134,7 +143,7 @@ namespace test {
replayStateMark();
verifyNotifications();
clearStates();
pushDiff(); ///////////////////////////////////////////////////////////////////////////TICKET #1066
pushDiff();
}
@ -532,18 +541,22 @@ namespace test {
}
/** @test integration test of mutation by diff message
/**
* @test integration test of mutation by diff message
* Since this test focuses on the bus side of standard interactions,
* it seems indicated to emulate the complete invocation situation,
* which involves passing thread boundraries. The main thread running
* this test shall enact the role of the UI event thread (since the
* UI-Bus in the real application is confined to this UI thread).
* Thus we'll start another thread to enact the role of the Session,
* to produce a diff message and "cast" it towards the UI.
* to produce diff messages and "cast" them towards the UI.
* @note a defining property of this whole interaction is the fact that
* the diff is _pulled asynchronously,_ which means the actual diff
* generation happens on callback from the UI. Access to any "session"
* data needs to be protected by lock in such a situation.
* the diff is _pulled asynchronously,_ which means the actual diff
* generation happens on callback from the UI. Access to any "session"
* data needs to be protected by lock in such a situation.
*/
void
pushDiff()
@ -555,6 +568,7 @@ namespace test {
, ThreadJoinable
{
// shared data
uint64_t borgChecksum_ = 0;
IterStack<uint> sessionBorgs_;
// access to shared session data
@ -562,18 +576,19 @@ namespace test {
scheduleBorg (uint id)
{
Lock sync(this);
borgChecksum_ += id;
sessionBorgs_.push(id);
cout << "Sess: scheduledBorgs... "<<util::join(sessionBorgs_)<<"\n";
}
auto
dispatchBorgs()
{
Lock sync(this);
cout << "Sess: discharge "<<sessionBorgs_.size()<<" Borgs... \n";
return dischargeToSnapshot (sessionBorgs_);
}
/**
* Independent heap allocated diff generator.
* Implements the IterSource<DiffStep> interface
@ -587,14 +602,22 @@ namespace test {
, TreeDiffLanguage
, DiffSource
{
uint id_;
uint generatorID_;
SessionThread& theCube_;
IterQueue<DiffStep> steps_;
BorgGenerator (SessionThread& motherShip, uint id)
: id_{id}
: generatorID_{id}
, theCube_{motherShip}
{ }
{
ClassLock<BorgGenerator> sync;
++generator_instances;
}
~BorgGenerator()
{
ClassLock<BorgGenerator> sync;
--generator_instances;
}
/* == Interface IterSource<DiffStep> == */
@ -603,61 +626,62 @@ namespace test {
firstResult () override
{
REQUIRE (not steps_);
cout << "Gen-"<<id_<<": makeDiff...\n";
auto plannedBorgs = theCube_.dispatchBorgs();
uint max = plannedBorgs.size();
uint cur = 0;
_Fmt borgName{"%d of %d |%03d|"};
cout << "Gen-"<<id_<<": make......."<<max<<" Borg!\n";
steps_.feed(after(Ref::ATTRIBS));
for (uint id : plannedBorgs)
_Fmt borgName{"%d of %d ≺%03d.gen%03d≻"};
steps_.feed (after(Ref::ATTRIBS)); // important: retain all existing attributes
for (uint id : plannedBorgs) // Generate diff to inject a flock of Borg
{
GenNode borg = MakeRec().genNode(borgName % ++cur % max % id);
steps_.feed(ins(borg));
steps_.feed(mut(borg));
steps_.feed( ins(GenNode{"borgID", int(id)}));
steps_.feed(emu(borg));
GenNode borg = MakeRec().genNode(borgName % ++cur % max % id % generatorID_);
steps_.feed (ins(borg));
steps_.feed (mut(borg)); // open nested scope for this Borg
steps_.feed ( ins(GenNode{"borgID", int(id)}));
steps_.feed (emu(borg)); // close nested scope
}
steps_.feed(after(Ref::END));
cout << "Gen-"<<id_<<": made.......diff|||\n";
steps_.feed (after(Ref::END)); // important: fast-forward and accept already existing Borgs
return & *steps_;
return & *steps_; // the IterSource protocol requires us to return a ptr to current element
}
virtual void
nextResult (DiffStep*& pos) override
{
if (!pos) return;
if (steps_) ++steps_;
if (steps_)
pos = & *steps_;
pos = & *steps_; // pointer to current element
else
pos = 0;
cout << "Gen-"<<id_<<": iter......."<<pos<<"\n";
pos = NULL; // signal iteration end
}
};
/** launch the session thread and start injecting Borg */
SessionThread(function<void(DiffMessage&&)> notifyGUI)
/**
* launch the Session Thread and start injecting Borg
*/
SessionThread(function<void(DiffSource*)> notifyGUI)
: ThreadJoinable{"BusTerm_test: asynchronous diff mutation"
, [=]() {
uint cnt = rand() % MAX_RAND_BORGS;
cout << "Sess: produce "<<cnt<<" Borg...\n";
for (uint i=0; i<cnt; ++i)
{
uint delay = rand() % MAX_RAND_DELAY;
cout << "Sess: delay... "<<delay<<"...\n";
usleep (delay);
uint id = rand() % MAX_RAND_NUMBS;
usleep (delay);
scheduleBorg (id);
notifyGUI (DiffMessage {new BorgGenerator{*this, i}});
notifyGUI (new BorgGenerator{*this, i});
}
}}
{ }
};
EventLog nexusLog = gui::test::Nexus::startNewLog();
MockElm rootMock("alpha zero");
@ -667,6 +691,8 @@ namespace test {
CHECK ("Quadrant" == rootMock.attrib["α"]);
CHECK (isnil (rootMock.scope));
CHECK (0 == generator_instances);
// The final part in the puzzle is to dispatch the diff messages into the UI
// In the real application, this operation is provided by the NotificationService.
@ -674,14 +700,12 @@ namespace test {
// performed on the UI event thread.
auto& uiBus = gui::test::Nexus::testUI();
CallQueue uiDispatcher;
auto notifyGUI = [&](DiffMessage&& diff)
auto notifyGUI = [&](DiffSource* diffGenerator)
{
cout << "Sess: notifyUI\n";
uiDispatcher.feed ([&, diff]()
uiDispatcher.feed ([&, diffGenerator]()
{
// apply and consume diff message stored within closure
cout << "GUI : apply Diff\n";
uiBus.change (rootID, move(unConst(diff)));
uiBus.change (rootID, DiffMessage{diffGenerator});
});
};
@ -690,20 +714,53 @@ namespace test {
//----start-multithreaded-mutation---
SessionThread session{notifyGUI};
usleep (2 * MAX_RAND_DELAY);
cout << "GUI : while...remaining "<<uiDispatcher.size()<<"\n";
while (not isnil(uiDispatcher))
{
cout << "GUI : do...delay="<<MAX_RAND_DELAY<<"\n";
usleep (MAX_RAND_DELAY);
cout << "GUI : do...dispatch\n";
usleep (100);
uiDispatcher.invoke();
cout << "GUI : do...remaining "<<uiDispatcher.size()<<"\n";
}
cout << "TEST: Joint.......\n";
session.join();
//------end-multithreaded-mutation---
// now verify rootMock has been properly assimilated...
uint generatedBorgs = rootMock.scope.size();
// root and all Borg child nodes are connected to the UI-Bus
CHECK (1 + generatedBorgs == gui::test::Nexus::size());
uint64_t borgChecksum = 0;
for (uint i=0; i<generatedBorgs; ++i)
{
MockElm& borg = *rootMock.scope[i];
CHECK (contains (borg.attrib, "borgID"));
string borgID = borg.attrib["borgID"];
borgChecksum += lexical_cast<int> (borgID);
string childID = borg.getID().getSym();
CHECK (contains (childID, borgID));
CHECK (contains (childID, " of ")); // e.g. "3 of 5"
CHECK (nexusLog.verifyCall("routeAdd").arg(rootMock.getID(), memLocation(rootMock)) // rootMock was attached to Nexus
.beforeCall("change") .argMatch(rootMock.getID(), // diff message sent via UI-Bus
"after.+_ATTRIBS_.+" // verify diff pattern generated for each Borg
"ins.+"+childID+".+"
"mut.+"+childID+".+"
"ins.+borgID.+"+borgID+".+"
"emu.+"+childID)
.beforeCall("routeAdd").arg(borg.getID(), memLocation(borg)) // Borg was inserted as child and attached to Nexus
.beforeEvent("applied diff to "+string(rootMock.getID()))
);
}
CHECK (rootMock.attrib["α"] == "Quadrant"); // attribute alpha was preserved while injecting all those Borg
// sanity checks
CHECK (borgChecksum == session.borgChecksum_); // no Borgs got lost
CHECK (0 == generator_instances); // no generator instance leaks
cout << "____Event-Log_________________\n"
<< util::join(rootMock.getLog(), "\n")
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
@ -711,10 +768,13 @@ namespace test {
cout << "____Nexus-Log_________________\n"
<< util::join(nexusLog, "\n")
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
cout << "Attrib: " + util::join(rootMock.attrib)
<< "\nChildz: "+ util::join(rootMock.scope)
<< ".!.\n";
}
static string
memLocation (Tangible& uiElm)
{
return lib::idi::instanceTypeID (&uiElm);
}
};

View file

@ -389,6 +389,12 @@ namespace test{
return testNexus().getLog().clear();
}
size_t
Nexus::size()
{
return testNexus().size();
}
/**
* install a closure (custom handler function)

View file

@ -87,6 +87,8 @@ namespace test{
static lib::test::EventLog const& getLog();
static lib::test::EventLog const& startNewLog();
static size_t size();
/* == allow to set custom handlers for commands and state changes == */

View file

@ -926,7 +926,7 @@
<node CREATED="1502402004383" ID="ID_1491065212" MODIFIED="1502403195803" TEXT="generisch bleiben?">
<icon BUILTIN="button_cancel"/>
</node>
<node CREATED="1502402012558" FOLDED="true" ID="ID_1846096533" MODIFIED="1502551047319" TEXT="IterSource verwenden">
<node CREATED="1502402012558" FOLDED="true" ID="ID_1846096533" MODIFIED="1502594103870" TEXT="IterSource verwenden">
<linktarget COLOR="#2579a2" DESTINATION="ID_1846096533" ENDARROW="Default" ENDINCLINATION="-5;149;" ID="Arrow_ID_896931950" SOURCE="ID_636092614" STARTARROW="None" STARTINCLINATION="158;5;"/>
<icon BUILTIN="forward"/>
<node CREATED="1502402691844" ID="ID_286774751" MODIFIED="1502403195804" TEXT="Diskussion">
@ -5551,7 +5551,8 @@
</node>
</node>
</node>
<node CREATED="1448658633478" HGAP="99" ID="ID_314439240" MODIFIED="1448658665728" TEXT="Design" VSHIFT="13">
<node CREATED="1448658633478" HGAP="99" ID="ID_314439240" MODIFIED="1502593945567" TEXT="Design" VSHIFT="13">
<icon BUILTIN="button_ok"/>
<node CREATED="1448658692023" ID="ID_339186676" MODIFIED="1487275490536">
<richcontent TYPE="NODE"><html>
<head>
@ -5813,8 +5814,8 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#990000" CREATED="1455422030995" HGAP="35" ID="ID_1455265273" MODIFIED="1502453247050" TEXT="mutation" VSHIFT="7">
<icon BUILTIN="pencil"/>
<node CREATED="1455422030995" HGAP="35" ID="ID_1455265273" MODIFIED="1502593856566" TEXT="mutation" VSHIFT="7">
<icon BUILTIN="button_ok"/>
<node CREATED="1455666294927" FOLDED="true" ID="ID_373207685" MODIFIED="1488423342665" TEXT="Ausgangspunkt">
<node CREATED="1455666301630" ID="ID_933452284" MODIFIED="1455666310209" TEXT="Element-Protokoll steht"/>
<node CREATED="1455666310701" ID="ID_571166725" MODIFIED="1455666314472" TEXT="Bus-Semantik steht"/>
@ -10869,8 +10870,8 @@
</node>
</node>
</node>
<node CREATED="1473352396906" HGAP="-48" ID="ID_392196966" MODIFIED="1502453253062" TEXT="Integration" VSHIFT="25">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1473352396906" FOLDED="true" HGAP="-48" ID="ID_392196966" MODIFIED="1502594174004" TEXT="Integration" VSHIFT="25">
<icon BUILTIN="button_ok"/>
<node CREATED="1473352465473" ID="ID_158999012" MODIFIED="1502453392316" TEXT="in Tangible">
<icon BUILTIN="button_ok"/>
<node CREATED="1475250911087" FOLDED="true" ID="ID_1042895809" MODIFIED="1488423308115" TEXT="zu kl&#xe4;ren">
@ -10973,7 +10974,7 @@
</node>
<node CREATED="1475439403514" ID="ID_1619035258" MODIFIED="1502453694045" TEXT="Entscheidung">
<icon BUILTIN="yes"/>
<node CREATED="1502453744365" ID="ID_452337305" MODIFIED="1502453752074" TEXT="Schritt-1">
<node CREATED="1502453744365" FOLDED="true" ID="ID_452337305" MODIFIED="1502593828994" TEXT="Schritt-1">
<icon BUILTIN="button_cancel"/>
<node CREATED="1475439416185" ID="ID_963854956" MODIFIED="1475444176904" TEXT="Builder-Funktion nicht sinnvoll">
<richcontent TYPE="NOTE"><html>
@ -11033,7 +11034,7 @@
</node>
</node>
</node>
<node CREATED="1502453753155" ID="ID_89098030" MODIFIED="1502550725294" TEXT="Schritt-2">
<node CREATED="1502453753155" FOLDED="true" ID="ID_89098030" MODIFIED="1502593827355" TEXT="Schritt-2">
<linktarget COLOR="#bdbad3" DESTINATION="ID_89098030" ENDARROW="Default" ENDINCLINATION="821;-1406;" ID="Arrow_ID_554743885" SOURCE="ID_1584846573" STARTARROW="None" STARTINCLINATION="1459;870;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1502453814499" ID="ID_727706359" MODIFIED="1502453827917" TEXT="Puffer-Ansatz...">
@ -11267,12 +11268,13 @@
</node>
</node>
</node>
<node CREATED="1473352470896" HGAP="21" ID="ID_864450713" MODIFIED="1502453269037" TEXT="Unit-Tests" VSHIFT="18">
<node CREATED="1473352470896" HGAP="21" ID="ID_864450713" MODIFIED="1502593433790" TEXT="Unit-Tests" VSHIFT="18">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1473352475375" ID="ID_731425414" MODIFIED="1475546284267" TEXT="AbstractTangible_test">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1473352482502" ID="ID_1891838260" MODIFIED="1502551116965" TEXT="BusTerm_test">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1473352482502" ID="ID_1891838260" MODIFIED="1502593427480" TEXT="BusTerm_test">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1502453280050" ID="ID_60387485" MODIFIED="1502550710929" TEXT="DiffMessage_test">
<linktarget COLOR="#71e5ac" DESTINATION="ID_60387485" ENDARROW="Default" ENDINCLINATION="50;-12;" ID="Arrow_ID_1384671312" SOURCE="ID_667427572" STARTARROW="None" STARTINCLINATION="12;195;"/>
@ -11293,7 +11295,8 @@
</node>
</node>
</node>
<node CREATED="1448658726090" HGAP="18" ID="ID_37610818" MODIFIED="1488423307195" TEXT="Commands" VSHIFT="36">
<node CREATED="1448658726090" FOLDED="true" HGAP="18" ID="ID_37610818" MODIFIED="1502593932772" TEXT="Commands" VSHIFT="36">
<icon BUILTIN="button_ok"/>
<node CREATED="1448658755071" FOLDED="true" ID="ID_1033500384" MODIFIED="1492442088651" TEXT="wie definieren">
<icon BUILTIN="help"/>
<node CREATED="1448658974985" ID="ID_974207484" MODIFIED="1448658989011" TEXT="Definition braucht Session-Modell"/>
@ -11397,8 +11400,9 @@
<node CREATED="1448683525822" ID="ID_1395068730" MODIFIED="1448683529258" TEXT="Gesten"/>
</node>
</node>
<node CREATED="1448691191042" HGAP="35" ID="ID_1710578352" MODIFIED="1492442109121" TEXT="Lebenszyklus" VSHIFT="-1">
<node CREATED="1448691191042" FOLDED="true" HGAP="35" ID="ID_1710578352" MODIFIED="1502593917871" TEXT="Lebenszyklus" VSHIFT="-1">
<font NAME="SansSerif" SIZE="13"/>
<icon BUILTIN="go"/>
<node CREATED="1448691210544" ID="ID_242337741" MODIFIED="1448691218906" TEXT="Command-Skript: im Code"/>
<node CREATED="1448691219614" FOLDED="true" ID="ID_992447056" MODIFIED="1488423342548" TEXT="Bildungs-Regeln: ebenda">
<node CREATED="1448691243259" ID="ID_692910736" MODIFIED="1448691256433" TEXT="Frage: wie injizieren">
@ -11484,7 +11488,8 @@
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
<node CREATED="1492443650460" FOLDED="true" ID="ID_223885519" MODIFIED="1492443754375" TEXT="einfacher direkter Aufruf">
<node CREATED="1492443650460" FOLDED="true" ID="ID_223885519" MODIFIED="1502593908678" TEXT="einfacher direkter Aufruf">
<icon BUILTIN="button_ok"/>
<node CREATED="1492443656859" ID="ID_1242818576" MODIFIED="1492443663663" TEXT="Tangible / Bus-Term"/>
<node CREATED="1492443664602" ID="ID_263362527" MODIFIED="1492443679390" TEXT="reine Command-ID">
<richcontent TYPE="NOTE"><html>
@ -16718,7 +16723,7 @@
</node>
<node CREATED="1502452581379" HGAP="11" ID="ID_1651893758" MODIFIED="1502453059637" TEXT="Darstellung" VSHIFT="17">
<linktarget COLOR="#afb1bd" DESTINATION="ID_1651893758" ENDARROW="Default" ENDINCLINATION="-1257;0;" ID="Arrow_ID_1786455458" SOURCE="ID_1500100371" STARTARROW="None" STARTINCLINATION="1858;0;"/>
<node CREATED="1502452597604" ID="ID_172363215" MODIFIED="1502550991915" TEXT="DiffMessage">
<node CREATED="1502452597604" FOLDED="true" ID="ID_172363215" MODIFIED="1502593538120" TEXT="DiffMessage">
<icon BUILTIN="button_ok"/>
<node CREATED="1502454531772" ID="ID_445867436" MODIFIED="1502454536184" TEXT="abstrakter Iterator"/>
<node CREATED="1502454536636" ID="ID_643452930" MODIFIED="1502454542390" TEXT="opaque generation context"/>
@ -16729,7 +16734,7 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1502452625232" ID="ID_328973433" MODIFIED="1502454510192" TEXT="Diagnose">
<node CREATED="1502452625232" FOLDED="true" ID="ID_328973433" MODIFIED="1502593535897" TEXT="Diagnose">
<icon BUILTIN="button_ok"/>
<node CREATED="1502454361347" ID="ID_1601614353" MODIFIED="1502550968543" TEXT="toString">
<icon BUILTIN="button_ok"/>
@ -16848,10 +16853,11 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1443740566042" ID="ID_632827470" MODIFIED="1443740575356" TEXT="Baum-Diff">
<node CREATED="1443740576744" FOLDED="true" ID="ID_335386387" MODIFIED="1488423342669" TEXT="Anwenden">
<icon BUILTIN="pencil"/>
<node CREATED="1443741563019" FOLDED="true" HGAP="-20" ID="ID_1944319966" MODIFIED="1488423342552" TEXT="Demo-Beispiel" VSHIFT="8">
<node CREATED="1443740566042" ID="ID_632827470" MODIFIED="1502593717967" TEXT="Baum-Diff">
<icon BUILTIN="prepare"/>
<node CREATED="1443740576744" ID="ID_335386387" MODIFIED="1502593705932" TEXT="Anwenden">
<icon BUILTIN="button_ok"/>
<node CREATED="1443741563019" FOLDED="true" HGAP="-20" ID="ID_1944319966" MODIFIED="1502593559590" TEXT="Demo-Beispiel" VSHIFT="8">
<icon BUILTIN="button_ok"/>
<node CREATED="1443741578993" ID="ID_318844233" MODIFIED="1443741582069" TEXT="INIT"/>
<node CREATED="1443741591616" ID="ID_1102292452" MODIFIED="1443741607633" TEXT="INS + MUT _THIS_"/>
@ -16859,12 +16865,12 @@
<node CREATED="1443741736636" ID="ID_1110914687" MODIFIED="1443741738320" TEXT="PERM"/>
<node CREATED="1443741711120" ID="ID_1289424857" MODIFIED="1443741714651" TEXT="Rekursion"/>
</node>
<node CREATED="1443740607172" FOLDED="true" HGAP="21" ID="ID_1836453078" MODIFIED="1488423342552" TEXT="INIT" VSHIFT="14">
<node CREATED="1443740607172" FOLDED="true" HGAP="21" ID="ID_1836453078" MODIFIED="1502593680525" TEXT="INIT" VSHIFT="14">
<node CREATED="1443740625649" ID="ID_1466659920" MODIFIED="1443740670333" TEXT="Attribute + Kinder"/>
<node CREATED="1443740621098" ID="ID_987166264" MODIFIED="1443740625134" TEXT="nur Kinder"/>
<node CREATED="1443740615699" ID="ID_93430092" MODIFIED="1443740679948" TEXT="Attribute"/>
</node>
<node CREATED="1443741317885" FOLDED="true" ID="ID_1933201882" MODIFIED="1488423342552" TEXT="NAV">
<node CREATED="1443741317885" FOLDED="true" ID="ID_1933201882" MODIFIED="1502593731159" TEXT="NAV">
<node CREATED="1443741324236" FOLDED="true" ID="ID_1812765289" MODIFIED="1488423308120" TEXT="PICK">
<node CREATED="1443741332691" ID="ID_1059350985" MODIFIED="1443741335518" TEXT="Attribut"/>
<node CREATED="1443741337786" ID="ID_70415473" MODIFIED="1443741342997" TEXT="letztes Attribut"/>
@ -16914,9 +16920,9 @@
</node>
<node CREATED="1443741637530" ID="ID_397839136" MODIFIED="1443741640949" TEXT="Teilbaum"/>
</node>
<node CREATED="1443741106905" FOLDED="true" ID="ID_1001938821" MODIFIED="1488423342552" TEXT="PERM">
<node CREATED="1443741106905" FOLDED="true" ID="ID_1001938821" MODIFIED="1502593732198" TEXT="PERM">
<node CREATED="1443741110392" ID="ID_513982563" MODIFIED="1443741112764" TEXT="Attribut"/>
<node CREATED="1443741113584" FOLDED="true" ID="ID_1631505651" MODIFIED="1488423308120" TEXT="Kind">
<node CREATED="1443741113584" FOLDED="true" ID="ID_1631505651" MODIFIED="1502593696467" TEXT="Kind">
<node CREATED="1443741137141" ID="ID_300777204" MODIFIED="1443741140008" TEXT="normal"/>
<node CREATED="1443741140596" ID="ID_1663721251" MODIFIED="1443741147135" TEXT="mitten in Attribut-Zone"/>
<node CREATED="1443741147491" ID="ID_1992350599" MODIFIED="1443741152822" TEXT="am Ende der Attribut-Zone"/>
@ -16935,12 +16941,19 @@
<node CREATED="1443741229984" ID="ID_926730195" MODIFIED="1443741233636" TEXT="nach FIND"/>
</node>
</node>
<node CREATED="1460753406868" FOLDED="true" HGAP="-18" ID="ID_289459316" MODIFIED="1488423342552" TEXT="Spezialf&#xe4;lle" VSHIFT="25">
<node CREATED="1460753417178" FOLDED="true" ID="ID_1333254858" MODIFIED="1488423308121" TEXT="native bindings">
<node CREATED="1460753406868" HGAP="-18" ID="ID_289459316" MODIFIED="1502593581651" TEXT="Spezialf&#xe4;lle" VSHIFT="25">
<node COLOR="#338800" CREATED="1460753417178" FOLDED="true" ID="ID_1333254858" MODIFIED="1502593725943" TEXT="native bindings">
<linktarget COLOR="#639ad5" DESTINATION="ID_1333254858" ENDARROW="Default" ENDINCLINATION="1091;0;" ID="Arrow_ID_709688381" SOURCE="ID_534213210" STARTARROW="None" STARTINCLINATION="1150;185;"/>
<node CREATED="1460753433312" ID="ID_94456036" MODIFIED="1460753443667" TEXT="Binden an Collection von Primitiven"/>
<node CREATED="1460753444735" ID="ID_1100731476" MODIFIED="1460753459897" TEXT="Binden an Collection von intelligenten Spezialtypen"/>
<node CREATED="1460753460940" ID="ID_677690723" MODIFIED="1460753484941" TEXT="Komposit aus Attribut-Bindung und Kinder-Collection-Bindung"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1460753433312" ID="ID_94456036" MODIFIED="1502593626008" TEXT="Binden an Collection von Primitiven">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1460753444735" ID="ID_1100731476" MODIFIED="1502593621731" TEXT="Binden an Collection von intelligenten Spezialtypen">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1460753460940" ID="ID_677690723" MODIFIED="1502593616768" TEXT="Komposit aus Attribut-Bindung und Kinder-Collection-Bindung">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>