ChainSearch: backtracking verified -- finished

This commit is contained in:
Fischlurch 2018-09-16 00:26:46 +02:00
parent 84399aa407
commit 1683439b32
4 changed files with 117 additions and 79 deletions

View file

@ -24,7 +24,7 @@
/** @file iter-chain-search.hpp
** Evaluation mechanism to apply a sequence of conditions onto a linear search.
** This search algorithm is implemented on top of a tree expanding (monadic) filter pipeline,
** to allow for backtracking. The intention is not to combine the individual conditions, but
** to allow for backtracking. The intention is not just to combine the individual conditions, but
** rather to apply them one by one. After finding a match for the first condition, we'll search
** for the next condition _starting at the position of the previous match_. In the most general
** case, this immediate progression down the search chain might be too greedy; it could be that
@ -36,10 +36,10 @@
** ## Design
**
** The IterChainSearch component is built as a processing pipeline, based on the
** [Tree-Explorer framework](\ref iter-tree-explorer.hpp). This yields several benefits, yet also
** imposes some drawbacks. Without much effort, we get a extremely flexible and configurable
** solution, with acceptable / moderate performance. The result automatically adapts to a wide
** array of data sources; it is possible (and even intended) to attach it on top of an already
** [Tree-Explorer framework](\ref iter-tree-explorer.hpp). This yields several benefits, but
** imposes some drawbacks. Without much effort, we get an extremely flexible and configurable
** solution, with acceptable / moderate performance. The result automatically adapts to a huge
** selection of data sources; it is possible (and is even intended) to attach it on top of an
** existing on-demand data processing pipeline. The "source" can itself be a "state core" and
** we may install suitable filter predicates to possibly collaborate with the internals of
** such a state core. Yet we may also confine ourselves to pure functions and value processing.
@ -47,9 +47,9 @@
** The obvious downside of such an approach is its complexity in terms of code to understand.
** The collaboration between several layers in a filter pipeline can be intricate, leading to
** chains of layered similar functions calling each other. Most of these abstractions and
** decorations will be removed by the compiler and optimiser, typically leading to long
** decorations will be resolved by the compiler and optimiser, typically leading to long
** compilation times and rather large size of the generated code (which in debugging mode
** with full type information can even become excessively huge).
** with full type information can even become excessively large).
**
** Some caveats
** - the resulting pipeline is copyable, and it is typically moved out from a builder
@ -63,10 +63,11 @@
** functions still accessible. The only functions meant to be used in
** builder style are the IterChainSearch::search() variations.
** - if you copy, the embedded state is copied alongside, but not
** any external state referred by it.
** any further external state referred by it.
**
** @see IterChainSearch_test
** @see IterCursor_test
** @see iter-adapter.hpp
** @see iter-tree-explorer.hpp
** @see [usage example](event-log.hpp)
**
*/
@ -110,7 +111,7 @@ namespace iter {
buildExplorer (SRC&& dataSource)
{
return buildSearchFilter (forward<SRC> (dataSource))
.expand ([](auto it){ return it; }); // child iterator starts as copy of current level iterator
.expand ([](auto it){ return it; }); // child iterator starts as copy of current level iterator
}
/**
@ -128,6 +129,7 @@ namespace iter {
using Filter = decltype( buildSearchFilter(std::declval<SRC>()).asIterator() );
using Pipeline = decltype( buildExplorer (std::declval<SRC>()) );
/** each step in the chain is a functor to reconfigure the underlying filter */
using StepFunctor = std::function<void(Filter&)>;
};
@ -137,13 +139,13 @@ namespace iter {
/**
/*********************************************************************************************************//**
* Iterator based linear search mechanism, with the ability to perform consecutive search with backtracking.
* The IterChainSearch can be configured with a sequence of search goals (filter conditions), and will apply
* these in succession on the underlying iterator. It will search _by linear search_ for the first hit of the
* first condition, and then continue to search _from there_ matching on the second condition, and so on.
* After the first combination of matches is exhausted, the search will backtrack and try to evaluate
* the next combination, leading to a tree of search solutions.
* the next combination, leading to a tree of on-demand search solutions.
*/
template<class SRC>
class IterChainSearch
@ -177,7 +179,7 @@ namespace iter {
explicit
IterChainSearch (SEQ&& srcData)
: _Base{buildExplorer (forward<SEQ> (srcData))}
{ // mark initial pristine state
{ // mark initial pristine state
_Base::disableFilter();
}
@ -216,7 +218,7 @@ namespace iter {
* to possibly change its configuration.
* @note the given functor, lambda or function reference will be wrapped and adapted
* to conform to the required function signature. When using a generic lambda,
* the argument type `Filter&` is assumed
* the argument type `Filter&` is used for instantiation
* @remarks the additional chained search condition given here will be applied _after_
* matching all other conditions already in the filter chain. Each such condition
* is used to _filter_ the underlying source iterator, i.e. pull it until finding
@ -235,7 +237,7 @@ namespace iter {
if (_Base::isDisabled())
nextStep (*this); // apply first step immediately
else
else // (implicitly enables the base filter)
{
stepChain_.emplace_back (move (nextStep)); // append all further steps into the chain...
this->iterNext(); // then establish invariant:
@ -295,14 +297,15 @@ namespace iter {
/* ==== convenient builder free function ==== */
/** setup a chain search configuration by suitably wrapping the given container.
* @return a TreeEplorer, which is an Iterator to yield all the source elements,
* but may also be used to build an processing pipeline.
* @return an IterChainSearch instantiation, which is an Iterator to yield all the
* source elements, but can be outfitted with a sequence of filter conditions,
* to be applied to the underlying source one by one.
* @param srcData either a »Lumiera Forward Iterator«, a _reference_ to a STL
* container, or a [»State Core«](\ref lib::IterStateWrapper) object.
* @warning if you capture the result of this call by an auto variable,
* be sure to understand that invoking any further builder operation on
* TreeExplorer will invalidate that variable (by moving it into the
* augmented iterator returned from such builder call).
* @param srcData either a »Lumiera Forward Iterator«, a _reference_ to a STL
* container, or a [»State Core«](\ref lib::IterStateWrapper) object.
*/
template<class SRC>
inline auto

View file

@ -719,7 +719,7 @@ namespace lib {
invariant() const
{
return not hasChildren()
or *expansions_;
or expansions_->isValid();
}
void

View file

@ -28,9 +28,9 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/format-util.hpp" /////////////////////////////TODO necessary?
#include "lib/format-cout.hpp" /////////////////////////////TODO necessary?
#include "lib/format-util.hpp"
#include "lib/iter-chain-search.hpp"
#include "lib/iter-cursor.hpp"
#include "lib/util.hpp"
#include <vector>
@ -80,18 +80,22 @@ namespace test{
///////////////////////////////////////////////////TODO WIP
#define SHOW_TYPE(_TY_) \
cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() <<endl;
#define SHOW_EXPR(_XX_) \
cout << "Probe " << STRINGIFY(_XX_) << " ? = " << _XX_ <<endl;
///////////////////////////////////////////////////TODO WIP
/*****************************************************************//**
* @test verify a setup for consecutive searches with backtracking.
* - demonstrate simple consecutive matches and iterator behaviour
* - clear the filter underway and thus return to simple iteration
* - set up two conditions, the second one capturing state at the
* point where the first one matches
* - wrap a lib::IterCursor, which allows to toggle the search
* direction underway; this creates a situation where the
* first options picked do not lead to a successful solution,
* so the search has to track back, try further options and
* in each case re-apply all the following consecutive
* search conditions.
*
* @see iter-chain-search.hpp
* @see iter-cursor.hpp
@ -156,7 +160,7 @@ namespace test{
search.addStep([](auto& filter)
{ // Note: pick the current value at the point
string currVal = *filter; // where the 2nd filter step is (re)applied
string currVal = *filter; // where the 2nd filter step is (re)applied
filter.setNewFilter ([=](string const& val) // ...and bake this value into the lambda closure
{
return val != currVal;
@ -171,7 +175,6 @@ namespace test{
"bacon-tomato-and-" // any non-spam behind the 3rd spam
"tomato-and" // any non-spam behind the 4th spam
""); // and any non-spam behind the final spam
}
@ -187,6 +190,32 @@ namespace test{
void
backtracking ()
{
using Cursor = IterCursor<decltype(SPAM.begin())>;
auto search = chainSearch(Cursor{SPAM.begin(), SPAM.end()})
.search("spam")
.addStep([](auto& filter)
{
filter.switchBackwards(); // switch search direction without moving the cursor
filter.flipFilter(); // flip from match on "spam" to match on non-spam
})
.addStep([](auto& filter)
{ // filter is still configured to search non-spam backwards
++filter; // just "advance" this filter by one step (backward)
});
CHECK (materialise (search) // Layer-0: 1-3 spam fail altogether, too greedy. Try 4rd spam....
// Layer-1: turn back, toggle to non-spam, find bacon
== "sausage-" // Layer-2: non-spam and one step further backwards yields sausage
//
// BACKTRACK to Layer-0: pick 5th (and last) spam...
// Layer-1: turn back, toggle to non-spam, find "and"
"tomato-bacon-sausage-" // Layer-2: non-spam and one step back yields tomato, next bacon, next sausage.
// BACKTRACK to Layer-1: take previous one, which is tomato
"bacon-sausage-" // Layer-2: non-spam and one step further back yields bacon, then next sausage.
// BACKTRACK to Layer-1: take previous non-spam, which is bacon
"sausage" // Layer-2: non-spam and one step further back yields sausage.
""); // BACKTRACK to Layer-1: exhausted, BACKTRACK to Layer-0: exhausted. Done.
}
};

View file

@ -30764,7 +30764,11 @@
<node CREATED="1535891156816" ID="ID_679300718" MODIFIED="1535891164631" TEXT="ist komplex">
<icon BUILTIN="smiley-neutral"/>
<node CREATED="1535939100410" ID="ID_1893557511" MODIFIED="1535939107373" TEXT="aber von einer Art, die mir gef&#xe4;llt"/>
<node CREATED="1535939111640" ID="ID_1649632412" MODIFIED="1535939115932" TEXT="war bisher gut wartbar"/>
<node CREATED="1535939111640" ID="ID_1649632412" MODIFIED="1535939115932" TEXT="war bisher gut wartbar">
<node CREATED="1537050257419" HGAP="27" ID="ID_1397772054" MODIFIED="1537050286364" TEXT="naja...." VSHIFT="5">
<arrowlink DESTINATION="ID_913930564" ENDARROW="Default" ENDINCLINATION="-274;-41;" ID="Arrow_ID_1572610374" STARTARROW="None" STARTINCLINATION="-127;28;"/>
</node>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1514328717684" ID="ID_137835978" MODIFIED="1535892401183" TEXT="neuer Anlauf IterExplorer II">
@ -31259,7 +31263,8 @@
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1536409302285" FOLDED="true" ID="ID_913930564" MODIFIED="1536533161341" TEXT="extrem komplexe Typen">
<node COLOR="#338800" CREATED="1536409302285" FOLDED="true" ID="ID_913930564" MODIFIED="1537050286364" TEXT="extrem komplexe Typen">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_913930564" ENDARROW="Default" ENDINCLINATION="-274;-41;" ID="Arrow_ID_1572610374" SOURCE="ID_1397772054" STARTARROW="None" STARTINCLINATION="-127;28;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1536409316172" ID="ID_1468538186" MODIFIED="1536409340127" TEXT="Call-Traces sind nahezu unlesbar">
<richcontent TYPE="NOTE"><html>
@ -31709,9 +31714,9 @@
<node CREATED="1535894029921" ID="ID_152779506" MODIFIED="1535894037411" TEXT="den Stack schrittweise hochsteigen"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1535894097279" ID="ID_1801538785" MODIFIED="1536018600721" TEXT="als eigene Lib-Klasse bauen">
<node COLOR="#338800" CREATED="1535894097279" FOLDED="true" ID="ID_1801538785" MODIFIED="1537050317551" TEXT="als eigene Lib-Klasse bauen">
<linktarget COLOR="#23408f" DESTINATION="ID_1801538785" ENDARROW="Default" ENDINCLINATION="20;-55;" ID="Arrow_ID_1048873840" SOURCE="ID_1910123172" STARTARROW="None" STARTINCLINATION="-120;0;"/>
<icon BUILTIN="pencil"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1535894115317" ID="ID_1507592237" MODIFIED="1536018340937" TEXT="Design-Frage: wie konkret?">
<icon BUILTIN="help"/>
<node CREATED="1536018209730" ID="ID_1130583934" MODIFIED="1536018221348" TEXT="nur das generische Auswertungs-Schema"/>
@ -31720,8 +31725,8 @@
<node CREATED="1536018293535" ID="ID_361886715" MODIFIED="1536018315757" TEXT="Abk&#xfc;rzung f&#xfc;r direkten Wert-equality-Match"/>
<node CREATED="1536018276593" ID="ID_1222260775" MODIFIED="1536018287299" TEXT="prekonfigurierte Builder-Funktionen f&#xfc;r Standardf&#xe4;lle"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018364845" ID="ID_1351452920" MODIFIED="1536329770737" TEXT="Implementierung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1536018364845" ID="ID_1351452920" MODIFIED="1537050037422" TEXT="Implementierung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018375244" ID="ID_1906913554" MODIFIED="1536717634181" TEXT="Kern: Explore-Mechanismus">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018644456" ID="ID_477475522" MODIFIED="1536329729458" TEXT="Signatur der Explore-Funktion festlegen">
@ -31904,7 +31909,7 @@
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1536018406232" ID="ID_1330264339" MODIFIED="1536326484790" TEXT="Schritte als Funktoren">
<node COLOR="#338800" CREATED="1536018406232" FOLDED="true" ID="ID_1330264339" MODIFIED="1537050129790" TEXT="Schritte als Funktoren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018684754" FOLDED="true" ID="ID_1076606298" MODIFIED="1536326570743" TEXT="geeignete Signatur f&#xfc;r die Schritt-Funktoren">
<icon BUILTIN="button_ok"/>
@ -32108,7 +32113,7 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1536018923378" ID="ID_1163666446" MODIFIED="1536717626552" TEXT="Pipeline konstruieren">
<node COLOR="#338800" CREATED="1536018923378" FOLDED="true" ID="ID_1163666446" MODIFIED="1537050128222" TEXT="Pipeline konstruieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018931433" ID="ID_1532889609" MODIFIED="1536717484882" TEXT="treeExplorer-Konfiguration">
<arrowlink COLOR="#65a7b1" DESTINATION="ID_1044555993" ENDARROW="Default" ENDINCLINATION="70;92;" ID="Arrow_ID_575633930" STARTARROW="None" STARTINCLINATION="149;-3;"/>
@ -32172,7 +32177,34 @@
</node>
</node>
</node>
<node CREATED="1536357666667" ID="ID_886527146" MODIFIED="1536357671758" TEXT="Design-Kritik">
<node COLOR="#338800" CREATED="1536018420398" ID="ID_41628967" MODIFIED="1537050023015" TEXT="Adaptieren der Quell-Datensequenz">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018880168" ID="ID_1619721301" MODIFIED="1536326442522" TEXT="macht normalerweise TreeExplorer">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1619721301" ENDARROW="Default" ENDINCLINATION="129;0;" ID="Arrow_ID_1721152439" SOURCE="ID_1700266521" STARTARROW="None" STARTINCLINATION="76;-5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1536018887223" ID="ID_832237706" MODIFIED="1537050024641" TEXT="speziell: gear switch">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1536018442123" ID="ID_829730232" MODIFIED="1536329759111" TEXT="Abk&#xfc;rzung f&#xfc;r direkten Match">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018985450" ID="ID_1700266521" MODIFIED="1536329755895" TEXT="Wert-Typ deduzieren">
<arrowlink DESTINATION="ID_1619721301" ENDARROW="Default" ENDINCLINATION="129;0;" ID="Arrow_ID_1721152439" STARTARROW="None" STARTINCLINATION="76;-5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1536019008151" ID="ID_29813547" MODIFIED="1536329757422" TEXT="equality comparision in Lambda">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1536018471975" ID="ID_1115030606" MODIFIED="1537050027130" TEXT="Variante f&#xfc;r bidirektionale Suche">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018956285" ID="ID_128441804" MODIFIED="1537050078736" TEXT="einfach CursorGear als Quelle verwenden">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1536357666667" FOLDED="true" ID="ID_886527146" MODIFIED="1537050144836" TEXT="Design-Kritik">
<icon BUILTIN="button_ok"/>
<node CREATED="1536357672802" ID="ID_2301559" MODIFIED="1536357696186" TEXT="aktuelles Design ist minimalistisch aber nicht elegant">
<icon BUILTIN="yes"/>
</node>
@ -32213,8 +32245,8 @@
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536357878006" ID="ID_1225195123" MODIFIED="1536358257081" TEXT="Aufr&#xe4;umen und nachr&#xfc;sten">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1536357878006" ID="ID_1225195123" MODIFIED="1537050011562" TEXT="Aufr&#xe4;umen und nachr&#xfc;sten">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536357891412" FOLDED="true" ID="ID_942897075" MODIFIED="1536717539462" TEXT="den Basis-Layer eliminieren">
<linktarget COLOR="#4471b4" DESTINATION="ID_942897075" ENDARROW="Default" ENDINCLINATION="37;-79;" ID="Arrow_ID_537236489" SOURCE="ID_1163131751" STARTARROW="None" STARTINCLINATION="30;44;"/>
<icon BUILTIN="button_ok"/>
@ -32321,9 +32353,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536958590136" ID="ID_1848331022" MODIFIED="1536958932753" TEXT="Refactoring Pipeline-Struktur">
<node COLOR="#338800" CREATED="1536958590136" ID="ID_1848331022" MODIFIED="1537050002466" TEXT="Refactoring Pipeline-Struktur">
<linktarget COLOR="#81445a" DESTINATION="ID_1848331022" ENDARROW="Default" ENDINCLINATION="72;-412;" ID="Arrow_ID_1608996048" SOURCE="ID_1302534828" STARTARROW="None" STARTINCLINATION="672;68;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1536958603857" ID="ID_610488133" MODIFIED="1536958622137" TEXT="das urspr&#xfc;ngliche Implementierungs-Konzept scheitert">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
@ -32462,9 +32494,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1537022195013" ID="ID_1801625619" MODIFIED="1537022214939" TEXT="Korrektheit der Auswertungs-Logik">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1537022206627" ID="ID_983878679" MODIFIED="1537043798684" TEXT="mit komplexem Funktor">
<node COLOR="#338800" CREATED="1537022195013" ID="ID_1801625619" MODIFIED="1537050004022" TEXT="Korrektheit der Auswertungs-Logik">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1537022206627" FOLDED="true" ID="ID_983878679" MODIFIED="1537050008982" TEXT="mit komplexem Funktor">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1537022226504" ID="ID_1825074472" MODIFIED="1537024319743" TEXT="faul?">
<richcontent TYPE="NOTE"><html>
@ -32502,41 +32534,15 @@
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1537022216506" ID="ID_794497840" MODIFIED="1537022219986" TEXT="mit Backtracking">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018420398" ID="ID_41628967" MODIFIED="1536326452308" TEXT="Adaptieren der Quell-Datensequenz">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1536018880168" ID="ID_1619721301" MODIFIED="1536326442522" TEXT="macht normalerweise TreeExplorer">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1619721301" ENDARROW="Default" ENDINCLINATION="129;0;" ID="Arrow_ID_1721152439" SOURCE="ID_1700266521" STARTARROW="None" STARTINCLINATION="76;-5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018887223" ID="ID_832237706" MODIFIED="1536326437258" TEXT="speziell: gear switch">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node COLOR="#338800" CREATED="1536018442123" ID="ID_829730232" MODIFIED="1536329759111" TEXT="Abk&#xfc;rzung f&#xfc;r direkten Match">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018985450" ID="ID_1700266521" MODIFIED="1536329755895" TEXT="Wert-Typ deduzieren">
<arrowlink DESTINATION="ID_1619721301" ENDARROW="Default" ENDINCLINATION="129;0;" ID="Arrow_ID_1721152439" STARTARROW="None" STARTINCLINATION="76;-5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1536019008151" ID="ID_29813547" MODIFIED="1536329757422" TEXT="equality comparision in Lambda">
<node COLOR="#338800" CREATED="1537022216506" ID="ID_794497840" MODIFIED="1537050005604" TEXT="mit Backtracking">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018471975" ID="ID_1115030606" MODIFIED="1536018481902" TEXT="Variante f&#xfc;r bidirektionale Suche">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018956285" ID="ID_128441804" MODIFIED="1536018975076" TEXT="in CursorGear einwickeln">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1535894132587" ID="ID_1888561007" MODIFIED="1536018524436" TEXT="Unit-Test: IterChainSearch_test">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1535894132587" ID="ID_1888561007" MODIFIED="1537050042593" TEXT="Unit-Test: IterChainSearch_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1536018569210" ID="ID_1083474400" MODIFIED="1536018578102" TEXT="Test-Fixture">
<icon BUILTIN="button_ok"/>
<node CREATED="1536018580388" ID="ID_186304417" MODIFIED="1536018584425" TEXT="lovely spam">
@ -32549,11 +32555,11 @@
<node COLOR="#338800" CREATED="1536018539621" ID="ID_1857591081" MODIFIED="1536717648741" TEXT="simpleSearch()">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018544936" ID="ID_1750921303" MODIFIED="1536018557580" TEXT="chainedIteration()">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1536018544936" ID="ID_1750921303" MODIFIED="1537050039988" TEXT="chainedIteration()">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1536018552912" ID="ID_385004210" MODIFIED="1536018557955" TEXT="backtracking()">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1536018552912" ID="ID_385004210" MODIFIED="1537050041216" TEXT="backtracking()">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>