process node behavior for legacy Berloga-YED format

This commit is contained in:
Alexey Fedoseev
2024-04-12 17:16:23 +03:00
parent b719676a44
commit 71ff69e838
3 changed files with 254 additions and 11 deletions

View File

@@ -93,15 +93,21 @@ int cyberiada_stack_free(CyberiadaStack** stack)
int cyberiada_list_add(CyberiadaList** list, const char* key, void* data) int cyberiada_list_add(CyberiadaList** list, const char* key, void* data)
{ {
CyberiadaList* new_item; CyberiadaList *item, *new_item;
if (!list) { if (!list) {
return -1; return -1;
} }
new_item = (CyberiadaList*)malloc(sizeof(CyberiadaList)); new_item = (CyberiadaList*)malloc(sizeof(CyberiadaList));
new_item->key = key; new_item->key = key;
new_item->data = data; new_item->data = data;
new_item->next = *list; new_item->next = NULL;
*list = new_item; if (!*list) {
*list = new_item;
} else {
item = *list;
while (item->next) item = item->next;
item->next = new_item;
}
return 0; return 0;
} }

View File

@@ -122,6 +122,7 @@
/* HSM action constants */ /* HSM action constants */
#define CYBERIADA_SINGLE_NEWLINE "\n"
#define CYBERIADA_NEWLINE "\n\n" #define CYBERIADA_NEWLINE "\n\n"
#define CYBERIADA_NEWLINE_RN "\r\n\r\n" #define CYBERIADA_NEWLINE_RN "\r\n\r\n"
#define CYBERIADA_ACTION_TRIGGER_ENTRY "entry" #define CYBERIADA_ACTION_TRIGGER_ENTRY "entry"
@@ -137,6 +138,9 @@
#define CYBERIADA_ACTION_SPACES_REGEXP "^\\s*$" #define CYBERIADA_ACTION_SPACES_REGEXP "^\\s*$"
/*#define CYBERIADA_ACTION_NEWLINE_REGEXP "^([^\n]*(\n[ \t\r]*[^\\s])?)*\n\\s*\n(.*)?$" /*#define CYBERIADA_ACTION_NEWLINE_REGEXP "^([^\n]*(\n[ \t\r]*[^\\s])?)*\n\\s*\n(.*)?$"
#define CYBERIADA_ACTION_NL_REGEXP_MATCHES 4*/ #define CYBERIADA_ACTION_NL_REGEXP_MATCHES 4*/
#define CYBERIADA_ACTION_LEGACY_REGEXP "^\\s*(\\w((\\w| |\\.)*\\w)?(\\(\\w+\\))?)\\s*(\\[([^]]+)\\])?\\s*/"
#define CYBERIADA_ACTION_LEGACY_MATCHES 7
#define CYBERIADA_ACTION_LEGACY_MATCH_TRIGGER 1
/* CybediadaML metadata constants */ /* CybediadaML metadata constants */
@@ -544,6 +548,7 @@ static CyberiadaAction* cyberiada_new_action(CyberiadaActionType type,
static regex_t cyberiada_edge_action_regexp; static regex_t cyberiada_edge_action_regexp;
static regex_t cyberiada_node_action_regexp; static regex_t cyberiada_node_action_regexp;
static regex_t cyberiada_node_legacy_action_regexp;
/*static regex_t cyberiada_newline_regexp;*/ /*static regex_t cyberiada_newline_regexp;*/
static regex_t cyberiada_spaces_regexp; static regex_t cyberiada_spaces_regexp;
@@ -557,6 +562,10 @@ static int cyberiada_init_action_regexps(void)
ERROR("cannot compile edge action regexp\n"); ERROR("cannot compile edge action regexp\n");
return CYBERIADA_ASSERT; return CYBERIADA_ASSERT;
} }
if (regcomp(&cyberiada_node_legacy_action_regexp, CYBERIADA_ACTION_LEGACY_REGEXP, REG_EXTENDED)) {
ERROR("cannot compile edge action regexp\n");
return CYBERIADA_ASSERT;
}
/* if (regcomp(&cyberiada_newline_regexp, CYBERIADA_ACTION_NEWLINE_REGEXP, REG_EXTENDED)) { /* if (regcomp(&cyberiada_newline_regexp, CYBERIADA_ACTION_NEWLINE_REGEXP, REG_EXTENDED)) {
ERROR("cannot compile new line regexp\n"); ERROR("cannot compile new line regexp\n");
return CYBERIADA_ASSERT; return CYBERIADA_ASSERT;
@@ -572,6 +581,7 @@ static int cyberiada_free_action_regexps(void)
{ {
regfree(&cyberiada_edge_action_regexp); regfree(&cyberiada_edge_action_regexp);
regfree(&cyberiada_node_action_regexp); regfree(&cyberiada_node_action_regexp);
regfree(&cyberiada_node_legacy_action_regexp);
/* regfree(&cyberiada_newline_regexp);*/ /* regfree(&cyberiada_newline_regexp);*/
regfree(&cyberiada_spaces_regexp); regfree(&cyberiada_spaces_regexp);
return CYBERIADA_NO_ERROR; return CYBERIADA_NO_ERROR;
@@ -769,7 +779,7 @@ static int cyberiada_decode_state_block_action(const char* text, CyberiadaAction
return CYBERIADA_NO_ERROR; return CYBERIADA_NO_ERROR;
} }
static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** action) static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** actions)
{ {
int res; int res;
size_t buffer_len; size_t buffer_len;
@@ -779,7 +789,7 @@ static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** ac
buffer = utf8_encode(text, strlen(text), &buffer_len); buffer = utf8_encode(text, strlen(text), &buffer_len);
next = buffer; next = buffer;
*action = NULL; *actions = NULL;
while (*next) { while (*next) {
start = next; start = next;
@@ -822,7 +832,7 @@ static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** ac
continue ; continue ;
} }
if ((res = cyberiada_decode_state_block_action(start, action)) != CYBERIADA_NO_ERROR) { if ((res = cyberiada_decode_state_block_action(start, actions)) != CYBERIADA_NO_ERROR) {
ERROR("error while decoding state block %s: %d\n", start, res); ERROR("error while decoding state block %s: %d\n", start, res);
return res; return res;
} }
@@ -833,6 +843,71 @@ static int cyberiada_decode_state_actions(const char* text, CyberiadaAction** ac
return CYBERIADA_NO_ERROR; return CYBERIADA_NO_ERROR;
} }
static int cyberiada_decode_state_actions_yed(const char* text, CyberiadaAction** actions)
{
int res;
char *buffer, *next, *start, *block;
size_t buffer_len;
CyberiadaList *sections_list = NULL, *list;
regmatch_t pmatch[CYBERIADA_ACTION_LEGACY_MATCHES];
buffer = utf8_encode(text, strlen(text), &buffer_len);
next = buffer;
*actions = NULL;
while (*next) {
start = next;
while (*start && isspace(*start)) start++;
res = regexec(&cyberiada_node_legacy_action_regexp, start,
CYBERIADA_ACTION_LEGACY_MATCHES, pmatch, 0);
if (res != 0 && res != REG_NOMATCH) {
ERROR("newline regexp error %d\n", res);
res = CYBERIADA_ACTION_FORMAT_ERROR;
break;
}
if (res == 0) {
/*DEBUG("add start: '%s'\n", start);*/
list = sections_list;
cyberiada_list_add(&sections_list, start, NULL);
if (list) {
block = (char*)list->key;
while (*block) {
if (block == start) {
*(block - 1) = 0;
break;
}
block++;
}
}
}
block = strstr(start, CYBERIADA_SINGLE_NEWLINE);
if (block) {
next = block + 1;
} else {
next = start + strlen(start);
}
res = CYBERIADA_NO_ERROR;
}
/*DEBUG("text: %s\n", text);*/
for (list = sections_list; list; list = list->next) {
start = (char*)list->key;
/* DEBUG("section: '%s'\n", start);*/
if ((res = cyberiada_decode_state_block_action(start, actions)) != CYBERIADA_NO_ERROR) {
ERROR("error while decoding state block %s: %d\n", start, res);
break;
}
res = CYBERIADA_NO_ERROR;
}
free(buffer);
cyberiada_list_free(&sections_list);
return res;
}
static int cyberiada_graph_add_sibling_node(CyberiadaNode* sibling, CyberiadaNode* new_node) static int cyberiada_graph_add_sibling_node(CyberiadaNode* sibling, CyberiadaNode* new_node)
{ {
CyberiadaNode* node = sibling; CyberiadaNode* node = sibling;
@@ -1505,7 +1580,7 @@ static GraphProcessorState handle_new_edge(xmlNode* xml_node,
GRAPHML_ID_ATTRIBUTE) != CYBERIADA_NO_ERROR) { GRAPHML_ID_ATTRIBUTE) != CYBERIADA_NO_ERROR) {
buffer[0] = 0; buffer[0] = 0;
} }
DEBUG("add edge '%s' '%s' -> '%s'\n", buffer, source_buffer, target_buffer); /* DEBUG("add edge '%s' '%s' -> '%s'\n", buffer, source_buffer, target_buffer); */
cyberiada_graph_add_edge(sm, buffer, source_buffer, target_buffer); cyberiada_graph_add_edge(sm, buffer, source_buffer, target_buffer);
return gpsEdge; return gpsEdge;
} }
@@ -1700,9 +1775,9 @@ static GraphProcessorState handle_node_action(xmlNode* xml_node,
cyberiada_copy_string(&(current->comment_data->body), cyberiada_copy_string(&(current->comment_data->body),
&(current->comment_data->body_len), buffer); &(current->comment_data->body_len), buffer);
} else { } else {
/* DEBUG("Set node %s action %s\n", current->id, buffer); */ DEBUG("Set node %s action %s\n", current->id, buffer);
if (cyberiada_decode_state_actions(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) { if (cyberiada_decode_state_actions_yed(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) {
ERROR("cannot decode node action\n"); ERROR("cannot decode yed node action\n");
return gpsInvalid; return gpsInvalid;
} }
} }
@@ -2236,7 +2311,7 @@ static GraphProcessorState handle_node_data(xmlNode* xml_node,
} else { } else {
/* DEBUG("Set node %s action %s\n", current->id, buffer); */ /* DEBUG("Set node %s action %s\n", current->id, buffer); */
if (cyberiada_decode_state_actions(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) { if (cyberiada_decode_state_actions(buffer, &(current->actions)) != CYBERIADA_NO_ERROR) {
ERROR("Cannot decode node action\n"); ERROR("Cannot decode cyberiada node action\n");
return gpsInvalid; return gpsInvalid;
} }
} }

View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="utf-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" yed:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd" SchemeName="Автобортник" entryPosition="-1573,862 1002,069">
<key attr.name="Description" attr.type="string" for="graph" id="d0" />
<key for="port" id="d1" yfiles.type="portgraphics" />
<key for="port" id="d2" yfiles.type="portgeometry" />
<key for="port" id="d3" yfiles.type="portuserdata" />
<key attr.name="url" attr.type="string" for="node" id="d4" />
<key attr.name="description" attr.type="string" for="node" id="d5" />
<key for="node" id="d6" yfiles.type="nodegraphics" />
<key for="graphml" id="d7" yfiles.type="resources" />
<key attr.name="url" attr.type="string" for="edge" id="d8" />
<key attr.name="description" attr.type="string" for="edge" id="d9" />
<key for="edge" id="d10" yfiles.type="edgegraphics" />
<graph edgedefault="directed" id="G">
<data key="d0" xml:space="preserve" />
<node id="">
<data key="d6">
<y:GenericNode configuration="com.yworks.bpmn.Event.withShadow">
<y:Geometry x="-1628" y="748" width="10" height="10" />
<y:Fill color="#333333" color2="#000000" transparent="false" />
<y:BorderStyle color="#000000" type="line" width="1.0" />
<y:NodeLabel />
</y:GenericNode>
</data>
</node>
<node id="n0" yfiles.foldertype="group">
<data key="d4" xml:space="preserve" />
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry x="-786" y="492" width="517" height="770" />
<y:Fill color="#F5F5F5" transparent="false" />
<y:BorderStyle color="#000000" type="line" width="1.0" />
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="bold" hasLineColor="false" height="22" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="517" x="0" xml:space="preserve" y="0">Бой</y:NodeLabel>
<y:NodeLabel alignment="left" autoSizePolicy="node_size" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="770" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="517" x="0" xml:space="preserve" y="0">entry/
exit/
</y:NodeLabel>
<y:Shape type="roundrectangle" />
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false" />
<y:NodeBounds considerNodeLabelSize="true" />
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0" />
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0" />
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0:">
<node id="n0::n1">
<data key="d6">
<y:GenericNode>
<y:Geometry x="-788" y="645" width="413" height="208" />
<y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false" />
<y:BorderStyle color="#000000" type="line" width="1.0" />
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#B7C9E3" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="15" fontStyle="bold" hasLineColor="false" height="22" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">Сближение</y:NodeLabel>
<y:NodeLabel alignment="left" autoSizePolicy="content" configuration="com.yworks.entityRelationship.label.name" fontFamily="Consolas" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="208" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">entry/
МодульДвижения.ДвигатьсяКЦели()
exit/
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n0::n2">
<data key="d6">
<y:GenericNode>
<y:Geometry x="-784" y="311" width="413" height="208" />
<y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false" />
<y:BorderStyle color="#000000" type="line" width="1.0" />
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#B7C9E3" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="15" fontStyle="bold" hasLineColor="false" height="22" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">Атака</y:NodeLabel>
<y:NodeLabel alignment="left" autoSizePolicy="content" configuration="com.yworks.entityRelationship.label.name" fontFamily="Consolas" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="208" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">entry/
ОружиеЦелевое.АтаковатьЦель()
exit/
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n3">
<data key="d6">
<y:GenericNode>
<y:Geometry x="-1573" y="738" width="413" height="288" />
<y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false" />
<y:BorderStyle color="#000000" type="line" width="1.0" />
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#B7C9E3" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="15" fontStyle="bold" hasLineColor="false" height="22" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">Скан</y:NodeLabel>
<y:NodeLabel alignment="left" autoSizePolicy="content" configuration="com.yworks.entityRelationship.label.name" fontFamily="Consolas" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="288" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="413" x="0" xml:space="preserve" y="0">entry/
Сенсор.ПоискВрагаПоДистанции(мин)
exit/
Сенсор.ОстановкаПоиска()
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<edge source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">АнализаторЦели.ЦельПотеряна/
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" /></y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
<edge source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">АнализаторЦели.ЦельУничтожена/
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" /></y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
<edge source="n3" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">Сенсор.ЦельПолучена/
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" /></y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
<edge source="n0::n1" target="n0::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">ОружиеЦелевое.ЦельВошлаВЗонуАтаки/
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" /></y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
<edge source="n0::n2" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">ОружиеЦелевое.ЦельВышлаИзЗоныАтаки/
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" /></y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
<edge source="" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0" sy="0" tx="0" ty="0" />
<y:LineStyle color="#000000" type="line" width="1.0" />
<y:Arrows source="none" target="standard" />
<y:EdgeLabel alignment="center" backgroundColor="#F5F5F5" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="centered" modelPosition="center" preferredPlacement="center_on_edge" ratio="5.0" textColor="#000000" verticalTextPosition="bottom" visible="false" xml:space="preserve">
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" placement="center" side="on_edge" sideReference="relative_to_edge_flow" />
</y:EdgeLabel>
</y:PolyLineEdge>
</data>
</edge>
</graph>
</graphml>