Job-Planning: provide stub implementation for NOP job (see #1296)
- can now create a Job from JobTicket::NIL - on invocation this Job will to nothing Only when the first real output backend is implemented, we can decide if this simplistic implementation is enough, or if an empty output must be explicitly generated...
This commit is contained in:
parent
fef0c05b64
commit
f6fbc15e5f
9 changed files with 244 additions and 22 deletions
|
|
@ -47,7 +47,7 @@ lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr)
|
|||
|
||||
|
||||
void*
|
||||
lumiera_uid_ptr_get (lumiera_uid* luid)
|
||||
lumiera_uid_ptr_get (const lumiera_uid* luid)
|
||||
{
|
||||
return *(void**)luid;
|
||||
}
|
||||
|
|
@ -103,13 +103,13 @@ lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src)
|
|||
|
||||
|
||||
int
|
||||
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb)
|
||||
lumiera_uid_eq (const lumiera_uid* luida, const lumiera_uid* luidb)
|
||||
{
|
||||
return !memcmp (luida, luidb, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
lumiera_uid_hash (lumiera_uid* luid)
|
||||
lumiera_uid_hash (const lumiera_uid* luid)
|
||||
{
|
||||
return *(size_t*)luid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
* Retrieve a generic pointer stored in a luid
|
||||
*/
|
||||
void*
|
||||
lumiera_uid_ptr_get (lumiera_uid* luid);
|
||||
lumiera_uid_ptr_get (const lumiera_uid* luid);
|
||||
|
||||
/**
|
||||
* Generate a new luid
|
||||
|
|
@ -126,13 +126,13 @@ lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src);
|
|||
* Test 2 luid's for equality
|
||||
*/
|
||||
int
|
||||
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb);
|
||||
lumiera_uid_eq (const lumiera_uid* luida, const lumiera_uid* luidb);
|
||||
|
||||
|
||||
/**
|
||||
* Generate a hash sum over an luid
|
||||
*/
|
||||
size_t
|
||||
lumiera_uid_hash (lumiera_uid* luid);
|
||||
lumiera_uid_hash (const lumiera_uid* luid);
|
||||
|
||||
#endif /*LIB_LUID_H*/
|
||||
|
|
|
|||
|
|
@ -31,22 +31,27 @@
|
|||
|
||||
|
||||
#include "steam/engine/job-ticket.hpp"
|
||||
#include "vault/engine/nop-job-functor.hpp"
|
||||
#include "lib/depend.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
namespace steam {
|
||||
namespace engine {
|
||||
|
||||
namespace { // Details...
|
||||
|
||||
lib::Depend<vault::engine::NopJobFunctor> nopFunctor;
|
||||
} // (END) Details...
|
||||
|
||||
|
||||
// using mobject::Placement;
|
||||
// using mobject::session::Effect;
|
||||
using vault::engine::JobParameter;
|
||||
using vault::engine::JobClosure;
|
||||
using vault::engine::JobParameter;
|
||||
using vault::engine::JobClosure;
|
||||
|
||||
using lib::HashVal;
|
||||
using lib::HashVal;
|
||||
|
||||
using lib::unConst;
|
||||
|
||||
|
||||
class FrameJobClosure
|
||||
|
|
@ -104,21 +109,29 @@ using lib::HashVal;
|
|||
const JobTicket JobTicket::NOP{}; //////////////////////////////////////////////////////////////TICKET #725 : do we actually need that for the final data structure?
|
||||
|
||||
|
||||
/** */
|
||||
/**
|
||||
* Generate a render job to invoke the render network configuration
|
||||
* as defined and backing this JobTicket. The generated job descriptor record
|
||||
* will include a specific InvocationInstanceID, which factors in the nominal
|
||||
* frame time, but also the specific backing render configuration.
|
||||
* The actual implementation of the job functionality will be delegated
|
||||
* to the JobClosure, which was set up for this Segment and JobTiket
|
||||
* after the last Builder run created this part of the render network.
|
||||
*/
|
||||
Job
|
||||
JobTicket::createJobFor (FrameCoord coordinates)
|
||||
JobTicket::createJobFor (FrameCoord coordinates) const
|
||||
{
|
||||
Time nominalTime = coordinates.absoluteNominalTime;
|
||||
if (isnil (provision_))
|
||||
{
|
||||
|
||||
{ //////////////////////////////////////////////////////////////////////////////////TICKET #1296 : can we get away just with a do-nothing functor?
|
||||
return Job(nopFunctor(), InvocationInstanceID(), nominalTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
REQUIRE (this->isValid(), "Attempt to generate render job for incomplete or unspecified render plan.");
|
||||
REQUIRE (coordinates.channelNr < provision_.size(), "Inconsistent Job planning; channel beyond provision");
|
||||
Provision& provision = provision_[coordinates.channelNr];
|
||||
JobClosure& functor = static_cast<JobClosure&> (provision.jobFunctor); /////////////////////////TICKET #1295 : fix actual interface down to JobFunctor (after removing C structs)
|
||||
Time nominalTime = coordinates.absoluteNominalTime;
|
||||
Provision const& provision = provision_[coordinates.channelNr];
|
||||
JobClosure& functor = static_cast<JobClosure&> (unConst(provision.jobFunctor)); ////////////////TICKET #1295 : fix actual interface down to JobFunctor (after removing C structs)
|
||||
InvocationInstanceID invoKey{timeHash (nominalTime, provision.invocationSeed)};
|
||||
|
||||
return Job(functor, invoKey, nominalTime);
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ using lib::LUID;
|
|||
ExplorationState startExploration() const;
|
||||
ExplorationState discoverPrerequisites (uint channelNr =0) const;
|
||||
|
||||
Job createJobFor (FrameCoord coordinates);
|
||||
Job createJobFor (FrameCoord coordinates) const;
|
||||
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
|
||||
#include "vault/engine/job.h"
|
||||
#include "vault/engine/nop-job-functor.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
|
@ -69,6 +70,7 @@ namespace engine {
|
|||
JobFunctor::~JobFunctor() { }
|
||||
JobClosure::~JobClosure() { } ///< @deprecated 4/23 refactoring to retract C-structs from the Scheduler interface
|
||||
|
||||
NopJobFunctor::NopJobFunctor() { }
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
|
||||
#include "lib/llist.h"
|
||||
#include "lib/hash-value.h"
|
||||
#include "lib/luid.h"
|
||||
#include "lib/time.h"
|
||||
|
||||
|
||||
|
|
@ -126,6 +126,18 @@ union InvocationInstanceID
|
|||
struct { int32_t a,b;
|
||||
int64_t t;
|
||||
} part;
|
||||
|
||||
friend bool
|
||||
operator== (InvocationInstanceID const& l, InvocationInstanceID const& r)
|
||||
{
|
||||
return lumiera_uid_eq (&l.luid, &r.luid);
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!= (InvocationInstanceID const& l, InvocationInstanceID const& r)
|
||||
{
|
||||
return not (l == r);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
107
src/vault/engine/nop-job-functor.hpp
Normal file
107
src/vault/engine/nop-job-functor.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
NOP-JOB-FUNCTOR.hpp - a render job to do nothing
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2023, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file nop-job-functor.hpp
|
||||
** Generic implementation of a JobFunctor to perform no calculations.
|
||||
** Shall be used whenever playback or rendering must be implemented
|
||||
** over a part of the effective timeline with no model at all.
|
||||
** @todo WIP draft for the »Playback Vertical Slice« 4/2023
|
||||
** @warning not clear if this solution is feasible ///////////////////////////////////////////////////////TICKET #1296 : do we need to produce "empty output" explicitly?
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VAULT_ENGINE_NOP_JOB_FUNCTOR_H
|
||||
#define VAULT_ENGINE_NOP_JOB_FUNCTOR_H
|
||||
|
||||
|
||||
|
||||
#include "lib/hash-standard.hpp"
|
||||
#include "vault/engine/job.h"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
|
||||
namespace vault {
|
||||
namespace engine{
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::HashVal;
|
||||
|
||||
|
||||
/**
|
||||
* Stub implementation of the JobFunctor interface
|
||||
* for a render job _to do nothing at all_
|
||||
* @todo WIP as of 4/2023
|
||||
*/
|
||||
class NopJobFunctor
|
||||
: public JobClosure
|
||||
{
|
||||
|
||||
/* === JobFunctor Interface === */
|
||||
|
||||
JobKind
|
||||
getJobKind() const
|
||||
{
|
||||
return META_JOB;
|
||||
}
|
||||
|
||||
bool
|
||||
verify (Time, InvocationInstanceID) const
|
||||
{
|
||||
return true; // always happy
|
||||
}
|
||||
|
||||
InvocationInstanceID
|
||||
buildInstanceID (HashVal) const override
|
||||
{
|
||||
return InvocationInstanceID();
|
||||
}
|
||||
|
||||
size_t
|
||||
hashOfInstance (InvocationInstanceID invoKey) const override
|
||||
{
|
||||
std::hash<size_t> hashr;
|
||||
HashVal res = hashr (invoKey.frameNumber);
|
||||
lib::hash::combine (res, hashr (invoKey.part.t));
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
invokeJobOperation (JobParameter) override
|
||||
{
|
||||
/* NOP */
|
||||
}
|
||||
|
||||
void
|
||||
signalFailure (JobParameter, JobFailureReason) override
|
||||
{
|
||||
///////////TODO do we ever need to notify anyone? can this even happen?
|
||||
}
|
||||
|
||||
public:
|
||||
NopJobFunctor();
|
||||
};
|
||||
|
||||
|
||||
}} // namespace vault::engine
|
||||
#endif /*VAULT_ENGINE_NOP_JOB_FUNCTOR_H*/
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include "steam/engine/mock-dispatcher.hpp"
|
||||
#include "vault/engine/dummy-job.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "vault/engine/nop-job-functor.hpp"
|
||||
|
||||
#include "lib/format-cout.hpp"///////////////////////TODO
|
||||
|
||||
|
|
@ -115,9 +116,18 @@ namespace test {
|
|||
void
|
||||
verify_MockJobTicket()
|
||||
{
|
||||
FrameCoord coord;
|
||||
coord.absoluteNominalTime = lib::test::randTime();
|
||||
|
||||
// build a render job to do nothing....
|
||||
Job nopJob = JobTicket::NOP.createJobFor(coord);
|
||||
CHECK (INSTANCEOF (vault::engine::NopJobFunctor, static_cast<JobClosure*> (nopJob.jobClosure))); //////////TICKET #1295 : fix actual interface down to JobFunctor (after removing C structs)
|
||||
CHECK (nopJob.parameter.nominalTime == coord.absoluteNominalTime);
|
||||
CHECK (nopJob.parameter.invoKey == InvocationInstanceID());
|
||||
|
||||
MockJobTicket mockTicket;
|
||||
CHECK (mockTicket.discoverPrerequisites().empty());
|
||||
Job mockJob = mockTicket.createJobFor (FrameCoord{});
|
||||
Job mockJob = mockTicket.createJobFor (coord);
|
||||
CHECK (mockTicket.verify_associated (mockJob));
|
||||
TODO ("cover details of MockJobTicket");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69824,8 +69824,8 @@
|
|||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682204997554" ID="ID_599701197" MODIFIED="1682205023588" TEXT="Prerequisites hinzufügen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682868258074" ID="ID_1743148920" MODIFIED="1682868285655" TEXT="Job aus Ticket erstellen und ausführbar machen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1682868258074" ID="ID_1743148920" MODIFIED="1682898174253" TEXT="Job aus Ticket erstellen und ausführbar machen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1682885817579" ID="ID_1080671855" MODIFIED="1682886037986" TEXT="Hash für Zeitwerte definieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -69859,6 +69859,17 @@
|
|||
<node COLOR="#338800" CREATED="1682885673339" ID="ID_1525753166" MODIFIED="1682885692857" TEXT="Instance-Hash: hier den Seed einfach durchreichen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1682890776694" ID="ID_1533405151" MODIFIED="1682898136722" TEXT="NOP-Job Stub">
|
||||
<linktarget COLOR="#7b88b2" DESTINATION="ID_1533405151" ENDARROW="Default" ENDINCLINATION="-1179;197;" ID="Arrow_ID_1853160081" SOURCE="ID_10757245" STARTARROW="None" STARTINCLINATION="445;-24;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1682890841485" ID="ID_774211693" MODIFIED="1682890856303" TEXT="für den Fall JobTicket::NIL"/>
|
||||
<node COLOR="#338800" CREATED="1682898128631" ID="ID_1765265251" MODIFIED="1682898138153" TEXT="per lib::Depend einbinden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1682898161611" ID="ID_98710848" MODIFIED="1682898165898" TEXT="im Test verifiziert">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682627654491" ID="ID_1371147624" MODIFIED="1682627673234" TEXT="Marker definieren und sichtbar machen">
|
||||
<linktarget COLOR="#48417c" DESTINATION="ID_1371147624" ENDARROW="Default" ENDINCLINATION="-48;56;" ID="Arrow_ID_1753796050" SOURCE="ID_1110039315" STARTARROW="None" STARTINCLINATION="-284;-8;"/>
|
||||
|
|
@ -70357,6 +70368,19 @@
|
|||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682622220974" ID="ID_136220191" MODIFIED="1682622223749" TEXT="NIL-Ticket?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682887222315" ID="ID_786532593" MODIFIED="1682887238132" TEXT="brauche generischen NOP-Job">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1682890662127" ID="ID_952568490" MODIFIED="1682890669817" TEXT="#1296 NOP job">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682890725729" ID="ID_10757245" MODIFIED="1682898144599" TEXT="vorerst mal als JobFunctor-Stub implementieren">
|
||||
<arrowlink COLOR="#7b88b2" DESTINATION="ID_1533405151" ENDARROW="Default" ENDINCLINATION="-1179;197;" ID="Arrow_ID_1853160081" STARTARROW="None" STARTINCLINATION="445;-24;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1682890675172" ID="ID_1935070165" MODIFIED="1682890762548" TEXT="nicht klar ob das Output-Protokoll einfach "leer" laufen kann">
|
||||
<icon BUILTIN="bell"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682626547198" ID="ID_1401129193" MODIFIED="1682626582171" TEXT=" macht ein const JobTicket Sinn?">
|
||||
<icon BUILTIN="help"/>
|
||||
|
|
@ -70791,6 +70815,59 @@
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682892551985" ID="ID_479084448" MODIFIED="1682892564322" TEXT="Interface">
|
||||
<icon BUILTIN="bell"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682892569091" ID="ID_506216512" MODIFIED="1682892588596">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
welcher Teil muß wirklich<i> flexibel</i> sein?
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682892594378" ID="ID_470552795" MODIFIED="1682892605477" TEXT="fragwürdig">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1682892640709" ID="ID_587647024" MODIFIED="1682892640709" TEXT="HashVal hashOfInstance(InvocationInstanceID)"/>
|
||||
<node CREATED="1682892668386" ID="ID_893041429" MODIFIED="1682892668386" TEXT="bool verify (Time, InvocationInstanceID)">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682892726514" ID="ID_231285908" MODIFIED="1682892847128" TEXT="führt das nicht zu einer gefählichen zyklischen Verkopplung?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...denn von den grundsätzlichen Abhängigkeiten her weiß nicht einmal ein JobTicket, in welchem Segment es hängt; auch ProcNodes könnten theoretisch sogar in mehreren Segmenten hängen ⟹ es schreint mehr als fragwürdig, ob ein JobFunktor überhaupt im Stande ist, eine inhaltlich sinnvolle verifikation zu machen (über das Prüfen auf null-Pointer hinaus)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1682892700196" ID="ID_113377758" MODIFIED="1682892700196" TEXT="void signalFailure (JobParameter,JobFailureReason)">
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682892704686" ID="ID_1226594521" MODIFIED="1682892718331" TEXT="macht das nicht beser Layer-2 im Scheduler?">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1682892868892" ID="ID_1825787555" MODIFIED="1682892871994" TEXT="void invokeJobOperation (JobParameter parameter)">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682892874899" ID="ID_1605821761" MODIFIED="1682892883021" TEXT="könnte man die generisch implementieren?">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1682892899276" ID="ID_1612087262" MODIFIED="1682892909242" TEXT="JobKind getJobKind()">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1682892925095" ID="ID_1576147260" MODIFIED="1682892975170" TEXT="InvocationInstanceID buildInstanceID(HashVal)">
|
||||
<arrowlink COLOR="#4d4eb0" DESTINATION="ID_1493396541" ENDARROW="Default" ENDINCLINATION="-46;-58;" ID="Arrow_ID_1838720811" STARTARROW="None" STARTINCLINATION="148;9;"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1682040531781" ID="ID_913436563" MODIFIED="1682040539889" TEXT="offene Fragen">
|
||||
|
|
@ -70801,6 +70878,7 @@
|
|||
<linktarget COLOR="#b75269" DESTINATION="ID_1713196934" ENDARROW="Default" ENDINCLINATION="-871;-27;" ID="Arrow_ID_865176706" SOURCE="ID_782813898" STARTARROW="None" STARTINCLINATION="-1263;70;"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1682810738487" ID="ID_1493396541" MODIFIED="1682810875535" TEXT="#1295 draft job invocation parameter representation">
|
||||
<linktarget COLOR="#b22e63" DESTINATION="ID_1493396541" ENDARROW="Default" ENDINCLINATION="-1383;-51;" ID="Arrow_ID_847435526" SOURCE="ID_48632766" STARTARROW="None" STARTINCLINATION="-753;40;"/>
|
||||
<linktarget COLOR="#4d4eb0" DESTINATION="ID_1493396541" ENDARROW="Default" ENDINCLINATION="-46;-58;" ID="Arrow_ID_1838720811" SOURCE="ID_1576147260" STARTARROW="None" STARTINCLINATION="148;9;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue