Skip to content

Instantly share code, notes, and snippets.

@kenwebb
Last active August 30, 2018 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenwebb/8e94a77fe8077659a80286f77a482b9a to your computer and use it in GitHub Desktop.
Save kenwebb/8e94a77fe8077659a80286f77a482b9a to your computer and use it in GitHub Desktop.
Buffy 2
<?xml version="1.0" encoding="UTF-8"?>
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Thu Aug 30 2018 08:09:13 GMT-0400 (Eastern Daylight Time)-->
<XholonWorkbook>
<Notes><![CDATA[
Xholon
------
Title: Buffy 2
Description:
Url: http://www.primordion.com/Xholon/gwt/
InternalName: 8e94a77fe8077659a80286f77a482b9a based on a75eda653fab84ef2ae67ac98406a4e8
Keywords:
My Notes
--------
July 10, 2018
Ceptre example - Buffy
- characters are all avatars
To make "willow" the system avatar
----------------------------------
// right-click willow in the d3cp or other GUI, and select Edit > Log Browser Console
// go to Dev Tools console, right-click the new item in the console window, and select "Store as global variable" (which will probably be called "temp1")
var willow = temp1;
var ava = xh.avatar(); // buffy is the current avatar
ava.action("who");
willow.action("who;");
xh.avatar(willow);
willow.action("who;");
ava.action("who");
Can do this from inside a XholonConsole on the characters node
--------------------------------------------------------------
<script>
var ava = this.parent().xpath("Avatar[@roleName='tara']");
ava.println(ava);
$wnd.xh.avatar(ava);
</script>
Or paste this in as lastChild of any Avatar (use Xholon clipboard)
-------------------------------------------
<script>
$wnd.xh.avatar(this.parent());
</script>
Or
--
<script>this.parent().action("system;");</script>
GraphViz - To repeat this Xholon export:
--------
$wnd.xh.xport("Graphviz", $wnd.xh.root().parent().xpath("Chameleon/PhysicalSystem/placez"), '{"gvFileExt":".gv","gvGraph":"digraph","layout":"dot","edgeOp":"->","gvCluster":"","shouldShowStateMachineEntities":false,"filter":"--Behavior,Script","nameTemplateNodeId":"R^^^^^","nameTemplateNodeLabel":"R^^^^^","shouldQuoteLabels":true,"shouldShowLinks":true,"shouldShowLinkLabels":true,"shouldSpecifyLayout":true,"maxLabelLen":-1,"shouldColor":true,"defaultNodeColor":"#f0f8ff","bgGraphColor":"white","shouldSpecifyShape":true,"shape":"box","shouldSpecifySize":true,"size":"20","shouldSpecifyFontname":true,"fontname":"Courier","shouldSpecifyArrowhead":true,"arrowhead":"vee","shouldSpecifyStylesheet":true,"stylesheet":"Xholon.css","shouldSpecifyRankdir":false,"rankdir":"LR","shouldDisplayGraph":true,"outputFormat":"svg"}');
To run ceptre on my computer:
----------------------------
cd ~/ceptre
./ceptre-bin examples/buffy.cep
July 13
- I've been experimenting with the json-rules-engine library. I think I understand it better now, and will start a new version of Buffy.
- "Buffy" is the old version
How to deal with ' character (ex: C' )
----------------------------
So far, I am able to use the standard apostrophe (single quote ') in rules.
If I later have problems using ', then:
- see https://gist.githubusercontent.com/kenwebb/063bc93c7c5deb1a16c75d84b2170a58/raw/34a856b51a5176fd09652f847cf7480cf33fd345/xholonWorkbook.xml
dslLine = dslLine.replace(/'/g, "′"); // replace the apostrophe (single quote) with the unicode prime character U+2032 ′
References
----------
(1) https://github.com/chrisamaphone/interactive-lp
This is the source repository for Ceptre, a tiny logic programming language for prototyping rulesets that you can run, interact with, and analyze.
(2) https://github.com/chrisamaphone/interactive-lp/blob/master/examples/buffy.cep
(3) http://www.buffyworld.com/buffy/transcripts/
transcripts of all 7 buffy seasons
(4) https://duckduckgo.com/?q=JSON+formatter&atb=v61-7__&ia=answer
JSON formatter, pretty printer
]]></Notes>
<_-.XholonClass>
<PhysicalSystem/>
<!-- character : type. see ref [2] -->
<character superClass="Avatar"/>
<characters/>
<characterPreds/>
<!-- place : type. see ref [2] -->
<place/>
<placez/>
<!-- adjacent place place : bwd. see ref [2] -->
<AdjacentPlaces/>
<CharacterCharacterPreds/>
<CharacterCharacterStates/>
<Context/>
<stage superClass="JsonRulesEngineRecipeBook"/> <!-- base.Stage is already a Xholon .java class, so "stage" needs to be lowercase -->
<StageRunner/>
<!-- experimental: try to parse Ceptre syntax into JavaScript objects -->
<stageCeptre/>
<StageCeptreRunner/>
</_-.XholonClass>
<xholonClassDetails>
<Avatar><Color>green</Color></Avatar>
<placez><Color>white</Color></placez>
<place><Color>orange</Color></place>
</xholonClassDetails>
<PhysicalSystem>
<!-- see ref [2] -->
<characters chosenOne="buffy"><Attribute_String><![CDATA[
buffy : character.
willow : character.
xander : character.
anya : character.
tara : character.
giles : character.
dawn : character.
spike : character.
villain : character.
]]></Attribute_String></characters>
<!-- set these predicates to false for each character, see ref [2] -->
<characterPreds><Attribute_String><![CDATA[
npc character : pred.
evil character : pred.
witch character : pred.
slayer character : pred.
watcher character : pred.
weak character : pred.
strong character : pred.
]]></Attribute_String></characterPreds>
<!-- set these predicates to false for each character, see ref [2] -->
<CharacterCharacterPreds><Attribute_String><![CDATA[
friends character character : pred.
crush character character : pred.
dating character character : pred.
dislike character character : pred.
hunting character character : pred.
hurt_by character character : pred.
]]></Attribute_String></CharacterCharacterPreds>
<!-- see ref [2] -->
<placez><Attribute_String><![CDATA[
crypt : place.
graveyard : place.
buffy_house : place.
magic_box : place.
villain_lair : place.
high_school : place.
]]></Attribute_String></placez>
<!-- set of adjacent places, see ref [2] -->
<AdjacentPlaces><Attribute_String><![CDATA[
adjacent crypt graveyard.
adjacent graveyard crypt.
adjacent crypt magic_box.
adjacent magic_box crypt.
adjacent graveyard buffy_house.
adjacent buffy_house graveyard.
adjacent buffy_house magic_box.
adjacent magic_box buffy_house.
adjacent magic_box graveyard.
adjacent graveyard magic_box.
adjacent magic_box villain_lair.
adjacent villain_lair magic_box.
adjacent buffy_house villain_lair.
adjacent villain_lair buffy_house.
adjacent buffy_house high_school.
adjacent high_school magic_box.
]]></Attribute_String></AdjacentPlaces>
<!-- % states resulting from one character acting on another, see ref [2] -->
<CharacterCharacterStates><Attribute_String><![CDATA[
attacking character character : pred.
hitting_on character character : pred.
spellcast character character : pred.
joking_with character character : pred.
accusing character character : pred.
pushing_away character character : pred.
acting_affectionate character character : pred.
bickering character character : pred.
]]></Attribute_String></CharacterCharacterStates>
<!-- context init_game = {...}. see ref [2] -->
<Context roleName="init_game"><Attribute_String><![CDATA[
npc buffy, npc willow, npc xander, npc anya, npc tara,
npc giles, npc spike, npc villain, npc dawn,
no_pc
]]></Attribute_String></Context>
<!-- % Once more, with feeling, context init_season = {...}. see ref [2] -->
<Context roleName="init_season"><Attribute_String><![CDATA[
friends buffy willow, friends willow buffy,
friends buffy xander, friends xander buffy,
friends willow xander, friends xander willow,
friends dawn buffy, friends buffy dawn,
friends dawn xander, friends xander dawn,
friends dawn willow, friends willow dawn,
friends dawn tara, friends tara dawn,
dating willow tara, dating tara willow,
dating xander anya, dating anya xander,
friends giles buffy, friends buffy giles,
friends willow giles, friends giles willow,
dislike giles spike, dislike spike giles,
dislike xander spike, dislike spike xander,
evil spike, crush spike buffy, dislike buffy spike,
dislike villain buffy, evil villain,
witch willow, slayer buffy, watcher giles, witch tara,
strong buffy, strong willow, strong villain,
weak xander, weak giles, weak anya, weak tara, weak dawn, weak spike
]]></Attribute_String></Context>
<!-- init_episode = {...}. see ref [2] -->
<Context roleName="init_episode"><Attribute_String><![CDATA[
hunting villain dawn, crush buffy spike,
at dawn high_school,
at buffy graveyard, at willow buffy_house, at tara buffy_house,
at xander magic_box, at anya magic_box, at giles magic_box,
at spike crypt, at villain villain_lair
]]></Attribute_String></Context>
<stage roleName="pc_choices"><Attribute_String><![CDATA[
[
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "at", "value": "L"},
{"fact": "L", "operator": "adjacent", "value": "L'"}
]
}]
},
"event": {
"type": "act/move",
"params": {
"message": "An Avatar can move.",
"rhs": "at C L'"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "pc", "value": true},
{"fact": "C", "operator": "at", "value": "L"},
{"fact": "C'", "operator": "at", "value": "L"},
{"fact": "C", "operator": "crush", "value": "C'"}
]
}]
},
"event": {
"type": "act/hit_on",
"params": {
"message": "An Avatar can hit_on.",
"rhs": "hitting_on C C'"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "pc", "value": true},
{"fact": "C", "operator": "at", "value": "L"},
{"fact": "C'", "operator": "at", "value": "L"}
]
}]
},
"event": {
"type": "act/joke_with",
"params": {
"message": "An Avatar can joke_with.",
"rhs": "joking_with C C'"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "at", "value": "L"},
{"fact": "C'", "operator": "at", "value": "L"},
{"fact": "C", "operator": "dating", "value": "C'"}
]
}]
},
"event": {
"type": "act/bicker",
"params": {
"message": "An Avatar can bicker.",
"rhs": "bickering C C'"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "at", "value": "L"},
{"fact": "C'", "operator": "at", "value": "L"},
{"fact": "C", "operator": "dating", "value": "C'"}
]
}]
},
"event": {
"type": "act/affection",
"params": {
"message": "An Avatar can act affectionate.",
"rhs": "acting_affectionate C C'"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "npc", "value": true},
{"fact": "C'", "operator": "hitting_on", "value": "C"},
{"fact": "C", "operator": "crush", "value": "C'"}
]
}]
},
"event": {
"type": "react/hit_on/date",
"params": {
"message": "An Avatar can hit_on date.",
"rhs": "dating C C' * dating C' C"
}
}
},
{
"conditions": {
"any": [{
"all": [
{"fact": "C", "operator": "npc", "value": true},
{"fact": "C'", "operator": "joking_with", "value": "C"}
]
}]
},
"event": {
"type": "react/joke_with/laugh",
"params": {
"message": "An Avatar can laugh at a joke.",
"rhs": "!joking_with C' C"
}
}
},
{
"conditions": {
"any": [
{
"all": [
{
"fact": "C",
"operator": "$pc",
"value": true
},
{
"fact": "C",
"operator": "$evil",
"value": true
},
{
"fact": "C",
"operator": "at",
"value": "L"
},
{
"fact": "C'",
"operator": "at",
"value": "L"
},
{
"fact": "C'",
"operator": "$weak",
"value": true
},
{
"fact": "L",
"operator": "adjacent",
"value": "L'"
}
]
}
]
},
"event": {
"type": "act/kidnap/evil",
"params": {
"message": "act/kidnap/evil parsed from Ceptre as a test",
"rhs": "at C L' * at C' L' * go"
}
}
}
]
]]></Attribute_String></stage>
<StageRunner roleName="pc_choices" interactive="true" rbname="RecipeService-JsonRulesEngineRecipeBook-pc_choices"/>
<!-- experimental see ref [2] -->
<stageCeptre><Attribute_String><![CDATA[
stage pc_choices = {
act/move
: turn * $pc C
* at C L * adjacent L L'
-o at C L' * go.
act/kidnap/evil
: turn * $pc C
* $evil C
* at C L * at C' L * $weak C'
* adjacent L L'
-o at C L' * at C' L' * go.
act/attack/evil
: turn * $pc C
* $evil C
* $at C L * $at C' L
-o attacking C C' * go.
act/attack/slayer
: turn * $pc C
* $slayer C * $at C L * $at C' L * $evil C'
-o attacking C C' * go.
act/attack/revenge/friend
: turn * $pc C
* $at C L * $at C' L
* $friends C Victim * hurt_by Victim C'
* $evil C'
-o attacking C C' * go.
act/attack/revenge/lover
: turn * $pc C
* $at C L * $at C' L
* $dating C Victim * hurt_by Victim C'
* $evil C'
-o attacking C C' * go.
act/hit_on
: turn * $pc C
* $at C L * $at C' L * $crush C C'
-o hitting_on C C' * go.
act/affection
: turn * $pc C
* $at C L * $at C' L * $dating C C'
-o acting_affectionate C C' * go.
act/bicker
: turn * $pc C
* $at C L * $at C' L * $dating C C'
-o bickering C C' * go.
act/spellcast/weak_to_strong
: turn * $pc C * $witch C
* $at C L * $at C' L
* weak C'
-o strong C' * spellcast C C' * go.
act/spellcast/strong_to_weak
: turn * $pc C * $witch C
* $at C L * $at C' L
* strong C'
-o weak C' * spellcast C C' * go.
act/watcher/push_slayer_away
: turn * $pc C * $watcher C
* $at C L * $at C' L * $slayer C'
* $strong C'
-o pushing_away C C' * go.
act/accuse
: turn * $pc C
* $at C L * $at C' L
* $hurt_by C C'
-o accusing C C' * go.
act/joke_with
: turn * $pc C
* $at C L * $at C' L
-o joking_with C C' * go.
act/none : turn -o go.
end_story : turn -o end.
}
]]></Attribute_String></stageCeptre>
<StageCeptreRunner/>
<Animate selection="#xhanim" xpath="./PhysicalSystem/placez" duration="1" cssStyle=".d3cpnode circle {stroke-width: 0px;}" efParams="{&quot;selection&quot;:&quot;#xhanim&quot;,&quot;sort&quot;:&quot;disable&quot;,&quot;width&quot;:600,&quot;height&quot;:600,&quot;mode&quot;:&quot;tween&quot;,&quot;labelContainers&quot;:false,&quot;includeId&quot;:true,&quot;shape&quot;:&quot;circle&quot;,&quot;useIcons&quot;:false,&quot;maxChars&quot;:1,&quot;togglePortColors&quot;:false}"/>
</PhysicalSystem>
<charactersbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
const TEST_AVA_SYSTEM = false;
var me, nextAva, pc, beh = {
postConfigure: function() {
me = this.cnode.parent();
// buffy : character.
// <character roleName="buffy"></character>
if ($wnd.xh.html["selectTab"]) {
$wnd.xh.html.selectTab(0); // display contents of the "out" tab
}
//$wnd.xh.avatarKeyMap('{"UP":"go port0","DOWN":"go port2","LEFT":"go port3","RIGHT":"go port1","A":"appear","D":"drop","E":"eat","F":"flip","H":"if xpath(Avatar/Lumber) build Hut role Shack;if xpath(Avatar/Lumber) eat lumber;","I":"inventory","L":"look","N":"enter","P":"pause","R":"start","S":"step","T":"take","V":"vanish","W":"who;where;","X":"exit","Z":"param transcript toggle;"}');
$wnd.xh.avatarKeyMap('{"0":"out transcript 0;go link0;step","1":"out transcript 1;go link1;step","2":"out transcript 2;go link2;step","3":"out transcript 3;go link3;step","4":"out transcript 4;go link4;step","5":"out transcript 5;go link5;step","6":"out transcript 6;go link6;step","7":"out transcript 7;go link7;step","8":"out transcript 8;go link8;step","9":"out transcript 9;go link9;step","UP":"exit","DOWN":"first","LEFT":"prev","RIGHT":"next","A":"appear","D":"drop","E":"eat","F":"flip","I":"inventory","L":"look","N":"anim this hop","P":"pause","R":"start","S":"out transcript S;step","T":"take","V":"vanish","W":"who;where"}');
var str = me.first().text();
me.first().remove();
var arr = str.split("\n");
$wnd.console.log(arr);
var xmlStr = "<" + "_-.characters>";
arr.forEach(function(item) {
item = item.trim();
item = item.substring(0, item.length-13); // remove trailing " : character."
if (item == me["chosenOne"]) {
// the chosen one should be the system Avatar
me.println(item + " is the chosen one.");
var ava = $wnd.xh.avatar();
if (ava.parent() == null) {
ava.action("param setCtxtOnselect false;appear;become this role " + item + ";" + "enter;enter;where;pause;step;");
}
else {
// the system Avatar may already be part of another Xholon app, for example "Island"
if (ava.parent().xhc().name().endsWith("Cell")) { // ex: OceanCell LandCell CoastalCell
ava.action("param setCtxtOnselect false;appear;become this role " + item + ";" + "where;");
$wnd.console.log("Buffy 2 has been dragged into a grid app");
var thisRoot = $wnd.xh.root().first().next(); // PhysicalSystem
$wnd.console.log(thisRoot);
ava.parent().append(thisRoot.remove());
//ava.action("enter physicalSystem;enter placez;"); // later I have to manually move ava to "graveyard"
ava.action("enter physicalSystem;enter characters;pause;step;");
}
}
pc = ava; // player character
pc.color("red");
}
else {
xmlStr += '<' + 'character roleName="' + item + '"/>';
}
});
me.parent().parent().append(this.cnode.remove());
xmlStr += "</_-.characters>";
me.append(xmlStr);
nextAva = me.first();
nextAva.action("who;anim this hop;");
// build a characterArr and characterMap that can subsequently be used to supply facts to the rules engine, and for other purposes
var carr = [];
var cmap = {};
var character = me.first();
while (character) {
if (character != pc) { // don't add the player character
carr.push(character);
cmap[character.role()] = character;
}
character = character.next();
}
me["characterArr"] = carr;
me["characterMap"] = cmap;
},
act: function() {
if (!TEST_AVA_SYSTEM) {return;}
if (nextAva) {
nextAva.action("system;who;anim this hop;");
nextAva = nextAva.next();
}
else {
nextAva = me.first();
}
}
}
//# sourceURL=charactersbehavior.js
]]></charactersbehavior>
<characterPredsbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
// npc character : pred.
var str = me.first().text();
me.first().remove();
var arr = str.split("\n");
//$wnd.console.log(arr);
var cpArr = []; // name of each character pred (ex: ["npc","weak"]
arr.forEach(function(item) {
item = item.trim();
var itemArr = item.split(" ");
cpArr.push(itemArr[0]);
});
$wnd.console.log(cpArr);
this.cnode.remove();
var characters = me.xpath("../characters");
var character = characters.first();
while (character) {
cpArr.forEach(function(cpred) {character[cpred] = false;});
character = character.next();
}
}
}
//# sourceURL=characterPredsbehavior.js
]]></characterPredsbehavior>
<CharacterCharacterPredsbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
// friends character character : pred.
var str = me.first().text();
me.first().remove();
var arr = str.split("\n");
//$wnd.console.log(arr);
var cpArr = []; // name of each character character pred (ex: ["friends","crush"]
arr.forEach(function(item) {
item = item.trim();
var itemArr = item.split(" ");
cpArr.push(itemArr[0]);
});
$wnd.console.log(cpArr);
this.cnode.remove();
var characters = me.xpath("../characters");
var character = characters.first();
while (character) {
cpArr.forEach(function(cpred) {
if (!character[cpred]) {
character[cpred] = [];
}
});
character = character.next();
}
}
}
//# sourceURL=CharacterCharacterPredsbehavior.js
]]></CharacterCharacterPredsbehavior>
<CharacterCharacterStatesbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
// attacking character character : pred.
var str = me.first().text();
me.first().remove();
var arr = str.split("\n");
//$wnd.console.log(arr);
var cpArr = []; // name of each character character pred (ex: ["friends","crush"]
arr.forEach(function(item) {
item = item.trim();
var itemArr = item.split(" ");
cpArr.push(itemArr[0]);
});
$wnd.console.log(cpArr);
this.cnode.remove();
var characters = me.xpath("../characters");
var character = characters.first();
while (character) {
cpArr.forEach(function(cpred) {
if (!character[cpred]) {
character[cpred] = [];
}
});
character = character.next();
}
}
}
//# sourceURL=CharacterCharacterStatesbehavior.js
]]></CharacterCharacterStatesbehavior>
<placezbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
// crypt : place.
// <place roleName="crypt"></place>
var str = me.first().text();
me.first().remove();
var arr = str.split("\n");
$wnd.console.log(arr);
var xmlStr = "<" + "_-.placez>";
arr.forEach(function(item) {
item = item.trim();
item = item.substring(0, item.length-9); // remove trailing " : place."
xmlStr += '<' + 'place roleName="' + item + '"/>';
});
this.cnode.remove();
xmlStr += "</_-.placez>";
me.append(xmlStr);
}
}
//# sourceURL=placezbehavior.js
]]></placezbehavior>
<AdjacentPlacesbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
var characters = me.xpath("../characters");
var placez = me.xpath("../placez");
var place = placez.first();
while (place) {
place["adjacent"] = [];
place = place.next();
}
var str = me.first().text();
var adjArr = str.split("\n");
$wnd.console.log(adjArr);
adjArr.forEach(function(adjItem) {
adjItem = adjItem.trim();
adjItem = adjItem.substring(9, adjItem.length-1); // remove "adjacent " and "."
var fromtoArr = adjItem.split(" ");
//$wnd.console.log(fromtoArr);
var fromNode = placez.xpath("place[@roleName='" + fromtoArr[0] + "']");
var toNode = placez.xpath("place[@roleName='" + fromtoArr[1] + "']");
//$wnd.console.log(fromNode);
//$wnd.console.log(toNode);
if ((fromNode != null) && (toNode != null)) {
fromNode["adjacent"].push(toNode);
}
});
me.remove();
}
}
//# sourceURL=AdjacentPlacesbehavior.js
]]></AdjacentPlacesbehavior>
<Contextbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var me, charnodes, pnodes, beh = {
postConfigure: function() {
me = this.cnode.parent();
charnodes = me.xpath("../characters");
pnodes = me.xpath("../placez");
//me.println("CONTEXT " + me.role());
var str = me.first().text();
var arr = str.split(",");
arr.forEach(function(item) {
item = item.trim();
//me.println(item);
beh.processItem(item);
});
this.cnode.remove();
me.first().remove();
//me.remove();
},
processItem: function(item) {
var arr = item.split(" ");
switch(arr[0]) {
case "at":
this.processAt(arr);
break;
case "friends":
case "crush":
case "dating":
case "dislike":
case "hunting":
case "hurt":
//these are all "character character : pred."
this.processPred_cc(arr);
break;
case "npc":
case "evil":
case "witch":
case "slayer":
case "watcher":
case "strong":
case "weak":
//these are all "character : pred."
this.processPred_c(arr);
break;
default:
//me.println("UNHANDLED " + arr[0]); // no_pc
break;
}
},
processPred_c: function(arr) {
// pred, character
var pred = arr[0];
var cstr1 = arr[1];
var charnode1 = charnodes.xpath("*[@roleName='" + cstr1 + "']"); // character or Avatar
if (!charnode1) {
//me.println(" NOpred1c " + cstr1);
}
else {
charnode1[pred] = true;
}
},
processPred_cc: function(arr) {
// pred, character, character
var pred = arr[0];
var cstr1 = arr[1];
var cstr2 = arr[2];
var charnode1 = charnodes.xpath("*[@roleName='" + cstr1 + "']"); // character or Avatar
var charnode2 = charnodes.xpath("*[@roleName='" + cstr2 + "']");
if ((!charnode1) || (!charnode2)) {
//if (!charnode1) {me.println(" NOpred1 " + cstr1);}
//if (!charnode2) {me.println(" NOpred2 " + cstr2);}
}
else {
if (!charnode1[pred]) {
charnode1[pred] = [];
}
charnode1[pred].push(charnode2);
}
},
processAt: function(arr) {
// at dawn high_school
var cstr = arr[1];
var pstr = arr[2];
var charnode = charnodes.xpath("*[@roleName='" + cstr + "']"); // character or Avatar
var placenode = pnodes.xpath("place[@roleName='" + pstr + "']");
if ((!charnode) || (!placenode)) {
//if (!charnode) {me.println(" NO " + cstr);}
//if (!placenode) {me.println(" NO " + pstr);}
}
else {
placenode.append(charnode.remove());
}
}
}
//# sourceURL=Contextbehavior.js
]]></Contextbehavior>
<StageRunnerbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
const AVA_LOCATION = "location";
//const STAGE_STATES = ["select_character","pc_choices","done","npc_reactions","gen_npc_turns","npc_choices","pc_reactions"];
const ST_SELECT_CHARACTER = "select_character";
const ST_PC_CHOICES = "pc_choices";
const ST_DONE = "done";
const ST_NPC_REACTIONS = "npc_reactions";
const ST_GEN_NPC_TURNS = "gen_npc_turns";
const ST_NPC_CHOICES = "npc_choices";
const ST_PC_REACTIONS = "pc_reactions";
var me, engine, ready, pc, npcArr, npcMap, pcLocation, pcNodeAdj, currentNpcIx, facts, stageState, beh = {
// postConfigure
postConfigure: function() {
me = this.cnode.parent();
engine = null;
ready = false;
pc = null;
npcArr = null;
npcMap = null; // this is no longer necessary ?
pcLocation = null; // playing character's location (system
pcNodeAdj = null; // playing character's adjacent node/place
currentNpcIx = 0; // index in npcArr of current default non-playing character
stageState = ST_SELECT_CHARACTER; // initial stage state
if (me.interactive == "true") {me.interactive = true;} else {me.interactive = false;}
me.println("\n" + "S" + ': act/none (Press the "S" key to step one timestep)');
me.print("?- ");
},
// act
act: function() {
if (!ready && $wnd["JsonRulesEngine"]) {
pc = $wnd.xh.avatar(); // playing character
pcLocation = pc.obj(); //.role();
var characters = me.xpath("../characters");
npcArr = characters["characterArr"]; // array of non-playing characters
npcMap = characters["characterMap"]; // map of non-playing characters
ready = true;
var rserv = $wnd.xh.service("RecipeService");
var rbname = me["rbname"]; //"RecipeService-JsonRulesEngineRecipeBook-pc_choices";
var recipebook = null;
if (rserv) {
var rmsg = rserv.call(-3897, rbname, me);
recipebook = rmsg.data;
}
let engOptions = {
allowUndefinedFacts: false // perhaps at least some facts are deduced while running an operator?
};
if (Array.isArray(recipebook)) {
engine = new $wnd.JsonRulesEngine.Engine(recipebook, engOptions);
}
else { // recipebook is just a single Object
engine = new $wnd.JsonRulesEngine.Engine([recipebook], engOptions);
//engine.addRule(recipebook);
}
this.addOperators(pc, npcMap);
engine.on('success', (event, almanac, ruleResult) => {
//$wnd.console.log('success');
this.render(event, almanac, ruleResult);
});
engine.on('failure', (event, almanac, ruleResult) => {
//$wnd.console.log('failure');
//$wnd.console.log(event);
//$wnd.console.log(almanac);
//$wnd.console.log(ruleResult);
});
$wnd.console.log(engine);
}
if (ready) {
// TODO perhaps some/all facts should be dynamic/functions ?
//me.println(stageState);
// do stage state machine
switch (stageState) {
case ST_SELECT_CHARACTER: stageState = ST_PC_CHOICES; break;
case ST_PC_CHOICES: stageState = ST_NPC_REACTIONS; break;
case ST_NPC_REACTIONS: stageState = ST_PC_CHOICES; break;
default: break;
}
pcLocation = pc.obj();
var linksArr = pcLocation.links(false, true);
if (me.interactive) {
pcNodeAdj = pcLocation;
me.print("\n");
for (var i = 0; i < linksArr.length; i++) {
me.println("" + i + ": (act/move " + pc.role() + " " + pcLocation.role() + " " + linksArr[i].reffedNode.role() + ")");
}
me.println("" + "S" + ": act/none"); // + i++
me.print("?- ");
}
else {
var linkIx = $wnd.Math.floor($wnd.Math.random() * linksArr.length);
pcNodeAdj = linksArr[linkIx].reffedNode;
}
var currentNpc = npcArr[currentNpcIx];
if ($wnd.Math.random() > 0.5) {
currentNpcIx++;
if (currentNpcIx >= npcArr.length) {
currentNpcIx = 0;
}
}
switch (stageState) {
case ST_PC_CHOICES:
facts = {"C": pc, "C'": currentNpc, "L": pcLocation, "L'": pcNodeAdj}
break;
case ST_NPC_REACTIONS:
pcLocation = currentNpc.obj();
linksArr = pcLocation.links(false, true);
linkIx = $wnd.Math.floor($wnd.Math.random() * linksArr.length);
pcNodeAdj = linksArr[linkIx].reffedNode;
facts = {"C": currentNpc, "C'": pc, "L": pcLocation, "L'": pcNodeAdj}
break;
default: break;
}
//facts = {"C": pc, "C'": currentNpc, "L": pcLocation, "L'": pcNodeAdj}
/*engine.run(facts)
.then(function(events) {
$wnd.console.log(events);
});*/
engine.run(facts);
}
},
/**
* Add operators
* @param pc the Ceptre character player, the Xholon system avatar
* @param npcMap An array or map of Ceptre non-player characters, the Xholon non-system avatars
*/
addOperators: function(pc, npcMap) {
engine.addOperator("crush", (fact, value) => {
//$wnd.console.log("trying crush operator fact " + fact + ", value " + value);
var node1 = fact;
var node2 = facts[value];
if (node1) {
var arr = node1["crush"];
if (arr && (arr.length > 0) && (arr.indexOf(node2) != -1)) {
return true;
}
}
return false;
})
// react: reverse node1 and node2
engine.addOperator("hitting_on", (fact, value) => {
//$wnd.console.log("trying hitting_on operator fact " + fact + ", value " + value);
var node2 = fact;
var node1 = facts[value];
if (node1) {
var arr = node2["hitting_on"];
if (arr && (arr.length > 0) && (arr.indexOf(node1) != -1)) {
return true;
}
}
return false;
})
// react: reverse node1 and node2
engine.addOperator("joking_with", (fact, value) => {
//$wnd.console.log("trying joking_with operator fact " + fact + ", value " + value);
var node2 = fact;
var node1 = facts[value];
if (node1) {
var arr = node2["joking_with"];
if (arr && (arr.length > 0) && (arr.indexOf(node1) != -1)) {
return true;
}
}
return false;
})
engine.addOperator("at", (fact, value) => {
//$wnd.console.log("trying at operator fact " + fact + ", value " + value);
var node1 = fact;
var node2 = facts[value];
if (node1 && (node1.obj() == node2)) {
return true;
}
return false;
})
engine.addOperator("pc", (fact, value) => {
return value;
})
engine.addOperator("npc", (fact, value) => {
return value;
})
// these operators are not yet implemented
engine.addOperator("adjacent", (fact, value) => {return true;})
engine.addOperator("dating", (fact, value) => {return false;})
// parsed from Ceptre for testing
engine.addOperator("$pc", (fact, value) => {return false;})
engine.addOperator("$evil", (fact, value) => {return false;})
engine.addOperator("$weak", (fact, value) => {return false;})
}, // end addOperators()
/**
* Render
* @param event
* @param almanac
* @param ruleResult
*/
render: function(event, almanac, ruleResult) {
switch (stageState) {
case ST_PC_CHOICES:
switch (event.type) {
case "act/hit_on":
case "act/joke_with":
case "act/move":
case "act/bicker":
this.renderRHS(event, almanac);
break;
default: break;
}
break;
case ST_NPC_REACTIONS:
switch (event.type) {
case "react/hit_on/date":
case "react/joke_with/laugh":
this.renderRHS(event, almanac);
break;
default: break;
}
break;
}
/*switch (event.type) {
case "act/hit_on":
case "act/joke_with":
case "act/move":
case "act/bicker":
this.renderRHS(event, almanac);
break;
case "react/hit_on/date":
case "react/joke_with/laugh":
this.renderRHS(event, almanac);
break;
default: break;
}*/
},
/**
* Render right-hand side of event
* TODO maybe use facts[] array rather than almanac.factValue() Promise ???
* ex: "rhs": "hitting_on C C'"
* ex: "rhs": "weak C' * spellcast C C'"
* ex: "rhs": "dating C C' * dating C' C"
* ex: "rhs": "at C L'"
* ex: "rhs":"attacking C C' * go * !hurt_by Victim C'"
* @param event
* @param almanac
*/
renderRHS: function(event, almanac) {
const NOT = "!"; // new actions start with the NOT symbol
if (!event.params.rhs) {return;}
//$wnd.console.log(event.type);
var rhsArr = event.params.rhs.split("*");
rhsArr.forEach(function(rhs) {
var rhsTermArr = rhs.trim().split(" ");
if (rhsTermArr.length > 1) {
var operator = rhsTermArr[0].trim(); // ex: at hitting_on weak spellcast etc.
var operand1 = rhsTermArr[1].trim(); // ex: C C' are the only 2 possible values
var operand2 = null;
if (rhsTermArr.length > 2) {
operand2 = rhsTermArr[2].trim(); // ex: C' C L L' null are the only possible values
}
var node1 = null;
var node2 = null;
function successCbOperand1(value) {
node1 = value;
if (operand2) {
const promise2 = almanac.factValue(operand2);
promise2.then(successCbOperand2, failureCbOperand2);
}
else {
// this involves a boolean value
if (operator.charAt(0) == NOT) {
operator = operator.substring(1);
node1[operator] = false; // ex: "!weak C"
}
else {
node1[operator] = true; // ex: "weak C'"
}
}
}
function failureCbOperand1(error) {
$wnd.console.log("Error in failureCbOperand1(): " + error);
}
function successCbOperand2(value) {
node2 = value;
switch (operand2) {
case "C":
case "C'":
if (operator.charAt(0) == NOT) {
operator = operator.substring(1);
var index = node1[operator].indexOf(node2);
if (index != -1 ) {
node1[operator].splice(index, 1); // remove node2 from the array
}
}
else if (node1[operator].indexOf(node2) == -1 ) {
node1[operator].push(node2);
var arr = node1[operator].map(node => node.role());
me.println(node1.role() + " is " + operator + " " + arr);
}
break;
case "L":
case "L'":
node2.append(node1.remove());
break;
default:
break;
}
}
function failureCbOperand2(error) {
$wnd.console.log("Error in failureCbOperand2(): " + error);
}
const promise1 = almanac.factValue(operand1);
promise1.then(successCbOperand1, failureCbOperand1);
} // end if
}); // end forEach
} // end renderRHS
}
//# sourceURL=StageRunnerbehavior.js
]]></StageRunnerbehavior>
<StageCeptreRunnerbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
const LOLLI = "-o";
const TENSOR = "*";
const NOT = "!"; // new actions start with the NOT symbol
var me, beh = {
postConfigure: function() {
me = this.cnode.parent();
var str = me.prev().first().text().trim();
me.first().remove();
var openBracketPos = str.indexOf("{");
var closedBracketPos = str.indexOf("}");
var ceptreRules = str.substring(openBracketPos+1, closedBracketPos).trim();
//me.println(str.substring(0, openBracketPos+1));
var arr = ceptreRules.split(".");
var rules = []; // rules-engine rules
arr.forEach(function(ceptreRule) {
// Ceptre syntax NAME ":" CONDITIONS LOLLI ACTIONS "."
if (ceptreRule) {
ceptreRule = ceptreRule.trim().substring(0, ceptreRule.length-1); // remove trailing "."
var nameBodyArr = ceptreRule.split(":");
var rname = nameBodyArr[0].trim();
var rbody = nameBodyArr[1].trim();
var lhsRhsArr = rbody.split(LOLLI);
var lhs = lhsRhsArr[0].trim();
var rhs = lhsRhsArr[1].trim();
//me.println(rname);
var rule = {};
var mcArr = beh.makeConditions(lhs);
rule.conditions = mcArr[0];
rule.event = beh.makeEvent(rhs, mcArr[1], rname);
$wnd.console.log($wnd.JSON.stringify(rule));
rules.push(rule);
}
})
$wnd.console.log(rules);
},
makeConditions: function(ceptreLHS) {
//me.println("CONDITIONS");
const NOT_ExtraRHS = ["at","adjacent","turn"];
var arr = ceptreLHS.split(TENSOR);
var conditions = {};
conditions.any = [];
var anyObj = {};
anyObj.all = [];
var extraRHS = ""; // ex: condition "strong C'" becomes new action "!strong C'"
arr.forEach(function(cond) {
cond = cond.trim();
var tarr = cond.split(" ");
var operator = null;
var operand1 = null;
var operand2 = null;
switch (tarr.length) {
case 0:
case 1:
break;
case 2:
operator = tarr[0];
operand1 = tarr[1];
operand2 = true;
break;
case 3:
operator = tarr[0];
operand1 = tarr[1];
operand2 = tarr[2];
break;
default:
break;
}
if (operator) {
//me.println(" " + operator);
if (operator.charAt(0) == "$") {
operator = operator.substring(1); // remove initial "$"
}
else if (NOT_ExtraRHS.indexOf(operator) == -1) {
if (extraRHS) {
extraRHS += " " + TENSOR + " ";
}
extraRHS += NOT + cond;
}
var obj = {};
obj.fact = operand1;
obj.operator = operator;
obj.value = operand2;
anyObj.all.push(obj);
}
});
conditions.any.push(anyObj);
return [conditions, extraRHS];
},
makeEvent: function(ceptreRHS, extraRHS, rname) {
//me.println("ACTIONS");
var rhs = ceptreRHS;
if (extraRHS) {
if (rhs) {
rhs += " " + TENSOR + " ";
}
rhs += extraRHS;
}
var event = {};
event.type = rname;
event.params = {};
event.params.message = rname;
event.params.rhs = rhs;
return event;
}
}
//# sourceURL=StageCeptreRunnerbehavior.js
]]></StageCeptreRunnerbehavior>
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml,
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg">
<g>
<title>characters</title>
<rect id="PhysicalSystem/characters" fill="#98FB98" height="50" width="50" x="25" y="0"/>
<g>
<title>placez</title>
<rect id="PhysicalSystem/placez" fill="#6AB06A" height="50" width="10" x="80" y="0"/>
</g>
</g>
</svg>
<svg width="1178pt" height="879pt"
viewBox="0.00 0.00 1177.64 878.80" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="placez" class="graph" transform="scale(1 1) rotate(0) translate(4 874.8)">
<title>placez</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-874.8 1173.64,-874.8 1173.64,4 -4,4"/>
<text text-anchor="middle" x="584.82" y="-8.2" font-family="Courier,monospace" font-size="14.00">placez</text>
<!-- spike -->
<g id="placez/place[@roleName=&#39;crypt&#39;]/character" class="node"><title>spike</title>
<polygon fill="green" stroke="black" points="646.495,-870.8 589.505,-870.8 589.505,-834.8 646.495,-834.8 646.495,-870.8"/>
<text text-anchor="middle" x="618" y="-848.6" font-family="Courier,monospace" font-size="14.00">spike</text>
</g>
<!-- crypt -->
<g id="placez_node2" class="node"><title>crypt</title>
<polygon fill="#f0f8ff" stroke="black" points="1059.49,-510.8 1002.51,-510.8 1002.51,-474.8 1059.49,-474.8 1059.49,-510.8"/>
<text text-anchor="middle" x="1031" y="-488.6" font-family="Courier,monospace" font-size="14.00">crypt</text>
</g>
<!-- spike&#45;&gt;crypt -->
<g id="placez_edge3" class="edge"><title>spike&#45;&gt;crypt</title>
<path fill="none" stroke="black" d="M646.713,-851.813C740.373,-851.093 1031,-842.518 1031,-763.8 1031,-763.8 1031,-763.8 1031,-581.8 1031,-561.43 1031,-538.409 1031,-521.022"/>
<polygon fill="black" stroke="black" points="1031,-510.999 1035.5,-520.999 1031,-515.999 1031,-520.999 1031,-520.999 1031,-520.999 1031,-515.999 1026.5,-521 1031,-510.999 1031,-510.999"/>
<text text-anchor="middle" x="1084.27" y="-668.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- buffy -->
<g id="placez/place[@roleName=&#39;graveyard&#39;]/Avatar" class="node"><title>buffy</title>
<polygon fill="green" stroke="black" points="590.495,-780.8 533.505,-780.8 533.505,-744.8 590.495,-744.8 590.495,-780.8"/>
<text text-anchor="middle" x="562" y="-758.6" font-family="Courier,monospace" font-size="14.00">buffy</text>
</g>
<!-- spike&#45;&gt;buffy -->
<g id="placez_edge32" class="edge"><title>spike&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M624.553,-834.464C627.546,-823.536 629.207,-809.517 623,-798.8 617.722,-789.687 609.077,-782.742 599.932,-777.538"/>
<polygon fill="black" stroke="black" points="590.726,-772.899 601.682,-773.381 595.191,-775.149 599.656,-777.399 599.656,-777.399 599.656,-777.399 595.191,-775.149 597.631,-781.418 590.726,-772.899 590.726,-772.899"/>
<text text-anchor="middle" x="643.16" y="-803.6" font-family="Times,serif" font-size="14.00">crush</text>
</g>
<!-- xander -->
<g id="placez/place[@roleName=&#39;magic_box&#39;]/character[@roleName=&#39;xander&#39;]" class="node"><title>xander</title>
<polygon fill="green" stroke="black" points="206.294,-600.8 139.706,-600.8 139.706,-564.8 206.294,-564.8 206.294,-600.8"/>
<text text-anchor="middle" x="173" y="-578.6" font-family="Courier,monospace" font-size="14.00">xander</text>
</g>
<!-- spike&#45;&gt;xander -->
<g id="placez_edge31" class="edge"><title>spike&#45;&gt;xander</title>
<path fill="none" stroke="black" d="M589.312,-851.353C490.152,-849.59 165.828,-841.938 127,-816.8 82.857,-788.22 69.1401,-760.517 78.669,-708.8 86.4265,-666.697 85.3034,-651.445 113,-618.8 118.102,-612.787 124.512,-607.562 131.229,-603.115"/>
<polygon fill="black" stroke="black" points="139.827,-597.898 133.612,-606.933 135.552,-600.492 131.278,-603.086 131.278,-603.086 131.278,-603.086 135.552,-600.492 128.943,-599.239 139.827,-597.898 139.827,-597.898"/>
<text text-anchor="middle" x="97.6655" y="-713.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- giles -->
<g id="placez/place[@roleName=&#39;magic_box&#39;]/character[@roleName=&#39;giles&#39;]" class="node"><title>giles</title>
<polygon fill="green" stroke="black" points="745.495,-420.8 688.505,-420.8 688.505,-384.8 745.495,-384.8 745.495,-420.8"/>
<text text-anchor="middle" x="717" y="-398.6" font-family="Courier,monospace" font-size="14.00">giles</text>
</g>
<!-- spike&#45;&gt;giles -->
<g id="placez_edge30" class="edge"><title>spike&#45;&gt;giles</title>
<path fill="none" stroke="black" d="M642.653,-834.701C649.36,-829.406 656.331,-823.253 662,-816.8 734.91,-733.803 758.672,-708.091 785,-600.8 802.726,-528.563 777.369,-504.764 743,-438.8 741.341,-435.616 739.404,-432.409 737.349,-429.299"/>
<polygon fill="black" stroke="black" points="731.378,-420.884 740.835,-426.436 734.271,-424.962 737.165,-429.04 737.165,-429.04 737.165,-429.04 734.271,-424.962 733.495,-431.644 731.378,-420.884 731.378,-420.884"/>
<text text-anchor="middle" x="799.666" y="-623.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- graveyard -->
<g id="placez_node3" class="node"><title>graveyard</title>
<polygon fill="#f0f8ff" stroke="black" points="915.193,-420.8 824.807,-420.8 824.807,-384.8 915.193,-384.8 915.193,-420.8"/>
<text text-anchor="middle" x="870" y="-398.6" font-family="Courier,monospace" font-size="14.00">graveyard</text>
</g>
<!-- crypt&#45;&gt;graveyard -->
<g id="placez_edge1" class="edge"><title>crypt&#45;&gt;graveyard</title>
<path fill="none" stroke="black" d="M1005.05,-474.658C996.764,-469.069 987.61,-462.766 979.36,-456.8 968.739,-449.12 967.365,-445.33 956,-438.8 946.163,-433.148 935.234,-427.958 924.558,-423.403"/>
<polygon fill="black" stroke="black" points="915.274,-419.569 926.235,-419.227 919.895,-421.478 924.517,-423.387 924.517,-423.387 924.517,-423.387 919.895,-421.478 922.799,-427.546 915.274,-419.569 915.274,-419.569"/>
<text text-anchor="middle" x="1003.32" y="-443.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- magic_box -->
<g id="placez_node4" class="node"><title>magic_box</title>
<polygon fill="#f0f8ff" stroke="black" points="598.193,-150.8 507.807,-150.8 507.807,-114.8 598.193,-114.8 598.193,-150.8"/>
<text text-anchor="middle" x="553" y="-128.6" font-family="Courier,monospace" font-size="14.00">magic_box</text>
</g>
<!-- crypt&#45;&gt;magic_box -->
<g id="placez_edge2" class="edge"><title>crypt&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M1059.61,-479.14C1086.61,-465.017 1123,-439.385 1123,-403.8 1123,-403.8 1123,-403.8 1123,-221.8 1123,-183.131 1090.16,-182.508 1054,-168.8 973.852,-138.415 721.3,-134.058 608.437,-133.671"/>
<polygon fill="black" stroke="black" points="598.285,-133.646 608.296,-129.171 603.285,-133.658 608.285,-133.671 608.285,-133.671 608.285,-133.671 603.285,-133.658 608.273,-138.171 598.285,-133.646 598.285,-133.646"/>
<text text-anchor="middle" x="1146.32" y="-308.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- graveyard&#45;&gt;crypt -->
<g id="placez_edge4" class="edge"><title>graveyard&#45;&gt;crypt</title>
<path fill="none" stroke="black" d="M877.477,-420.987C883.421,-432.714 892.821,-447.713 905.36,-456.8 930.854,-475.274 965.718,-484.005 992.253,-488.127"/>
<polygon fill="black" stroke="black" points="1002.34,-489.537 991.812,-492.609 997.387,-488.844 992.435,-488.152 992.435,-488.152 992.435,-488.152 997.387,-488.844 993.058,-483.695 1002.34,-489.537 1002.34,-489.537"/>
<text text-anchor="middle" x="929.32" y="-443.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- graveyard&#45;&gt;magic_box -->
<g id="placez_edge6" class="edge"><title>graveyard&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M872.105,-384.709C876.472,-340.5 881.099,-222.118 814,-168.8 783.167,-144.299 675.626,-136.924 608.588,-134.72"/>
<polygon fill="black" stroke="black" points="598.194,-134.409 608.324,-130.211 603.192,-134.559 608.19,-134.709 608.19,-134.709 608.19,-134.709 603.192,-134.559 608.055,-139.207 598.194,-134.409 598.194,-134.409"/>
<text text-anchor="middle" x="892.32" y="-263.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- buffy_house -->
<g id="placez_node6" class="node"><title>buffy_house</title>
<polygon fill="#f0f8ff" stroke="black" points="566.289,-330.8 457.711,-330.8 457.711,-294.8 566.289,-294.8 566.289,-330.8"/>
<text text-anchor="middle" x="512" y="-308.6" font-family="Courier,monospace" font-size="14.00">buffy_house</text>
</g>
<!-- graveyard&#45;&gt;buffy_house -->
<g id="placez_edge5" class="edge"><title>graveyard&#45;&gt;buffy_house</title>
<path fill="none" stroke="black" d="M824.659,-390.655C761.765,-375.195 647.722,-347.162 576.128,-329.563"/>
<polygon fill="black" stroke="black" points="566.318,-327.152 577.103,-325.169 571.173,-328.345 576.029,-329.539 576.029,-329.539 576.029,-329.539 571.173,-328.345 574.954,-333.909 566.318,-327.152 566.318,-327.152"/>
<text text-anchor="middle" x="747.32" y="-353.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- magic_box&#45;&gt;crypt -->
<g id="placez_edge18" class="edge"><title>magic_box&#45;&gt;crypt</title>
<path fill="none" stroke="black" d="M598.378,-137.244C719.276,-147.025 1040,-177.176 1040,-221.8 1040,-403.8 1040,-403.8 1040,-403.8 1040,-424.276 1037.56,-447.293 1035.22,-464.651"/>
<polygon fill="black" stroke="black" points="1033.8,-474.654 1030.75,-464.12 1034.5,-469.703 1035.2,-464.753 1035.2,-464.753 1035.2,-464.753 1034.5,-469.703 1039.66,-465.386 1033.8,-474.654 1033.8,-474.654"/>
<text text-anchor="middle" x="1063.32" y="-308.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- magic_box&#45;&gt;graveyard -->
<g id="placez_edge20" class="edge"><title>magic_box&#45;&gt;graveyard</title>
<path fill="none" stroke="black" d="M593.313,-150.946C638.886,-171.715 713.547,-210.058 766,-258.8 804.109,-294.213 837.338,-345.407 855.448,-375.969"/>
<polygon fill="black" stroke="black" points="860.572,-384.751 851.646,-378.381 858.052,-380.432 855.532,-376.113 855.532,-376.113 855.532,-376.113 858.052,-380.432 859.419,-373.846 860.572,-384.751 860.572,-384.751"/>
<text text-anchor="middle" x="806.32" y="-263.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- magic_box&#45;&gt;buffy_house -->
<g id="placez_edge19" class="edge"><title>magic_box&#45;&gt;buffy_house</title>
<path fill="none" stroke="black" d="M561.695,-150.956C571.384,-172.497 584.295,-210.321 573,-240.8 566.344,-258.761 552.886,-275.234 540.3,-287.781"/>
<polygon fill="black" stroke="black" points="533.049,-294.697 537.18,-284.539 536.667,-291.246 540.286,-287.795 540.286,-287.795 540.286,-287.795 536.667,-291.246 543.391,-291.052 533.049,-294.697 533.049,-294.697"/>
<text text-anchor="middle" x="601.32" y="-218.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- villain_lair -->
<g id="placez_node9" class="node"><title>villain_lair</title>
<polygon fill="#f0f8ff" stroke="black" points="398.088,-60.8 281.912,-60.8 281.912,-24.8 398.088,-24.8 398.088,-60.8"/>
<text text-anchor="middle" x="340" y="-38.6" font-family="Courier,monospace" font-size="14.00">villain_lair</text>
</g>
<!-- magic_box&#45;&gt;villain_lair -->
<g id="placez_edge21" class="edge"><title>magic_box&#45;&gt;villain_lair</title>
<path fill="none" stroke="black" d="M527.3,-114.745C509.314,-103.379 484.409,-88.7553 461,-78.8 444.19,-71.6511 425.468,-65.4411 407.87,-60.3185"/>
<polygon fill="black" stroke="black" points="398.229,-57.5853 409.077,-55.9834 403.04,-58.9491 407.85,-60.3128 407.85,-60.3128 407.85,-60.3128 403.04,-58.9491 406.623,-64.6422 398.229,-57.5853 398.229,-57.5853"/>
<text text-anchor="middle" x="518.32" y="-83.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- buffy&#45;&gt;spike -->
<g id="placez_edge37" class="edge"><title>buffy&#45;&gt;spike</title>
<path fill="none" stroke="black" d="M542.579,-780.944C532.977,-791.54 524.937,-805.271 532.669,-816.8 543.181,-832.474 562.103,-841.135 579.461,-845.917"/>
<polygon fill="black" stroke="black" points="589.425,-848.308 578.651,-850.35 584.563,-847.141 579.701,-845.975 579.701,-845.975 579.701,-845.975 584.563,-847.141 580.751,-841.599 589.425,-848.308 589.425,-848.308"/>
<text text-anchor="middle" x="551.665" y="-803.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- buffy&#45;&gt;spike -->
<g id="placez_edge38" class="edge"><title>buffy&#45;&gt;spike</title>
<path fill="none" stroke="black" d="M569.455,-781.062C574.347,-791.703 581.207,-805.44 588.68,-816.8 590.872,-820.132 593.335,-823.506 595.877,-826.777"/>
<polygon fill="black" stroke="black" points="602.253,-834.613 592.451,-829.696 599.097,-830.735 595.942,-826.856 595.942,-826.856 595.942,-826.856 599.097,-830.735 599.432,-824.016 602.253,-834.613 602.253,-834.613"/>
<text text-anchor="middle" x="604.16" y="-803.6" font-family="Times,serif" font-size="14.00">crush</text>
</g>
<!-- buffy&#45;&gt;graveyard -->
<g id="placez_edge7" class="edge"><title>buffy&#45;&gt;graveyard</title>
<path fill="none" stroke="black" d="M590.883,-761.413C658.119,-758.722 824.221,-741.32 888,-636.8 908.704,-602.87 887.171,-484.386 875.927,-430.656"/>
<polygon fill="black" stroke="black" points="873.831,-420.817 880.316,-429.66 874.872,-425.708 875.914,-430.598 875.914,-430.598 875.914,-430.598 874.872,-425.708 871.513,-431.536 873.831,-420.817 873.831,-420.817"/>
<text text-anchor="middle" x="950.266" y="-578.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- willow -->
<g id="placez/place[@roleName=&#39;buffy_house&#39;]/character[@roleName=&#39;willow&#39;]" class="node"><title>willow</title>
<polygon fill="green" stroke="black" points="552.294,-510.8 485.706,-510.8 485.706,-474.8 552.294,-474.8 552.294,-510.8"/>
<text text-anchor="middle" x="519" y="-488.6" font-family="Courier,monospace" font-size="14.00">willow</text>
</g>
<!-- buffy&#45;&gt;willow -->
<g id="placez_edge33" class="edge"><title>buffy&#45;&gt;willow</title>
<path fill="none" stroke="black" d="M572.359,-744.545C595.597,-703.365 646.353,-597.646 600,-528.8 591.241,-515.791 576.534,-507.589 562.037,-502.43"/>
<polygon fill="black" stroke="black" points="552.109,-499.324 562.997,-498.016 556.881,-500.817 561.653,-502.31 561.653,-502.31 561.653,-502.31 556.881,-500.817 560.309,-506.605 552.109,-499.324 552.109,-499.324"/>
<text text-anchor="middle" x="637.436" y="-623.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- buffy&#45;&gt;xander -->
<g id="placez_edge34" class="edge"><title>buffy&#45;&gt;xander</title>
<path fill="none" stroke="black" d="M533.356,-760.73C463.884,-757.818 288.166,-748.474 234,-726.8 209.613,-717.042 200.262,-713.548 187.129,-690.8 173.057,-666.424 170.634,-633.815 171.035,-611.027"/>
<polygon fill="black" stroke="black" points="171.403,-601.011 175.533,-611.169 171.219,-606.007 171.036,-611.004 171.036,-611.004 171.036,-611.004 171.219,-606.007 166.539,-610.839 171.403,-601.011 171.403,-601.011"/>
<text text-anchor="middle" x="207.436" y="-668.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- buffy&#45;&gt;giles -->
<g id="placez_edge36" class="edge"><title>buffy&#45;&gt;giles</title>
<path fill="none" stroke="black" d="M590.642,-762.521C620.503,-761.607 666.441,-755.21 692,-726.8 767.564,-642.805 739.934,-491.749 724.532,-430.593"/>
<polygon fill="black" stroke="black" points="722.004,-420.912 728.884,-429.451 723.267,-425.75 724.53,-430.588 724.53,-430.588 724.53,-430.588 723.267,-425.75 720.176,-431.725 722.004,-420.912 722.004,-420.912"/>
<text text-anchor="middle" x="762.436" y="-578.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- dawn -->
<g id="placez/place[@roleName=&#39;high_school&#39;]/character" class="node"><title>dawn</title>
<polygon fill="green" stroke="black" points="412,-690.8 358,-690.8 358,-654.8 412,-654.8 412,-690.8"/>
<text text-anchor="middle" x="385" y="-668.6" font-family="Courier,monospace" font-size="14.00">dawn</text>
</g>
<!-- buffy&#45;&gt;dawn -->
<g id="placez_edge35" class="edge"><title>buffy&#45;&gt;dawn</title>
<path fill="none" stroke="black" d="M533.273,-758.868C505.628,-754.984 463.513,-746.198 432.129,-726.8 420.673,-719.719 410.403,-709.015 402.397,-699.075"/>
<polygon fill="black" stroke="black" points="396.228,-691.002 405.876,-696.215 399.264,-694.975 402.3,-698.947 402.3,-698.947 402.3,-698.947 399.264,-694.975 398.724,-701.68 396.228,-691.002 396.228,-691.002"/>
<text text-anchor="middle" x="452.436" y="-713.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- buffy_house&#45;&gt;graveyard -->
<g id="placez_edge10" class="edge"><title>buffy_house&#45;&gt;graveyard</title>
<path fill="none" stroke="black" d="M544.163,-330.896C554.664,-336.537 566.359,-342.883 577,-348.8 591.045,-356.61 593.116,-361.714 608.36,-366.8 670.229,-387.441 689.366,-376.071 754,-384.8 773.748,-387.467 795.357,-390.581 814.516,-393.409"/>
<polygon fill="black" stroke="black" points="824.583,-394.902 814.031,-397.886 819.637,-394.168 814.691,-393.435 814.691,-393.435 814.691,-393.435 819.637,-394.168 815.352,-388.984 824.583,-394.902 824.583,-394.902"/>
<text text-anchor="middle" x="632.32" y="-353.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- buffy_house&#45;&gt;magic_box -->
<g id="placez_edge11" class="edge"><title>buffy_house&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M513.115,-294.525C514.766,-273.183 518.55,-235.884 526.36,-204.8 530.144,-189.741 536.096,-173.488 541.414,-160.338"/>
<polygon fill="black" stroke="black" points="545.312,-150.957 545.631,-161.919 543.394,-155.575 541.475,-160.192 541.475,-160.192 541.475,-160.192 543.394,-155.575 537.319,-158.465 545.312,-150.957 545.312,-150.957"/>
<text text-anchor="middle" x="550.32" y="-218.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- buffy_house&#45;&gt;villain_lair -->
<g id="placez_edge12" class="edge"><title>buffy_house&#45;&gt;villain_lair</title>
<path fill="none" stroke="black" d="M457.751,-301.107C423.639,-291.392 381.889,-273.39 359,-240.8 323.106,-189.693 328.603,-111.852 334.811,-71.0009"/>
<polygon fill="black" stroke="black" points="336.463,-60.981 339.276,-71.5799 335.649,-65.9144 334.836,-70.8478 334.836,-70.8478 334.836,-70.8478 335.649,-65.9144 330.396,-70.1157 336.463,-60.981 336.463,-60.981"/>
<text text-anchor="middle" x="360.32" y="-173.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- high_school -->
<g id="placez_node10" class="node"><title>high_school</title>
<polygon fill="#f0f8ff" stroke="black" points="476.289,-240.8 367.711,-240.8 367.711,-204.8 476.289,-204.8 476.289,-240.8"/>
<text text-anchor="middle" x="422" y="-218.6" font-family="Courier,monospace" font-size="14.00">high_school</text>
</g>
<!-- buffy_house&#45;&gt;high_school -->
<g id="placez_edge13" class="edge"><title>buffy_house&#45;&gt;high_school</title>
<path fill="none" stroke="black" d="M475.089,-294.753C466.653,-289.755 458.176,-283.736 451.36,-276.8 443.919,-269.227 437.781,-259.386 433.076,-250.243"/>
<polygon fill="black" stroke="black" points="428.697,-241.092 437.073,-248.17 430.855,-245.603 433.014,-250.113 433.014,-250.113 433.014,-250.113 430.855,-245.603 428.954,-252.055 428.697,-241.092 428.697,-241.092"/>
<text text-anchor="middle" x="475.32" y="-263.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- willow&#45;&gt;buffy -->
<g id="placez_edge39" class="edge"><title>willow&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M527.065,-510.882C533.346,-525.007 541.698,-545.762 546,-564.8 559.422,-624.203 561.924,-695.926 562.196,-734.335"/>
<polygon fill="black" stroke="black" points="562.219,-744.692 557.697,-734.702 562.208,-739.692 562.196,-734.692 562.196,-734.692 562.196,-734.692 562.208,-739.692 566.696,-734.682 562.219,-744.692 562.219,-744.692"/>
<text text-anchor="middle" x="576.436" y="-623.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- willow&#45;&gt;buffy_house -->
<g id="placez_edge14" class="edge"><title>willow&#45;&gt;buffy_house</title>
<path fill="none" stroke="black" d="M532.8,-474.546C536.411,-469.156 539.883,-462.992 542,-456.8 557.564,-411.287 568.023,-392.979 549,-348.8 547.432,-345.158 545.278,-341.718 542.791,-338.521"/>
<polygon fill="black" stroke="black" points="536.069,-331.098 546.117,-335.49 539.425,-334.804 542.782,-338.51 542.782,-338.51 542.782,-338.51 539.425,-334.804 539.446,-341.531 536.069,-331.098 536.069,-331.098"/>
<text text-anchor="middle" x="613.266" y="-398.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- tara -->
<g id="placez/place[@roleName=&#39;buffy_house&#39;]/character[@roleName=&#39;tara&#39;]" class="node"><title>tara</title>
<polygon fill="green" stroke="black" points="468,-420.8 414,-420.8 414,-384.8 468,-384.8 468,-420.8"/>
<text text-anchor="middle" x="441" y="-398.6" font-family="Courier,monospace" font-size="14.00">tara</text>
</g>
<!-- willow&#45;&gt;tara -->
<g id="placez_edge8" class="edge"><title>willow&#45;&gt;tara</title>
<path fill="none" stroke="black" d="M512.484,-474.776C507.682,-463.706 500.365,-449.412 491,-438.8 486.721,-433.951 481.641,-429.425 476.384,-425.343"/>
<polygon fill="black" stroke="black" points="468.068,-419.313 478.805,-421.541 472.116,-422.248 476.163,-425.184 476.163,-425.184 476.163,-425.184 472.116,-422.248 473.521,-428.826 468.068,-419.313 468.068,-419.313"/>
<text text-anchor="middle" x="521.498" y="-443.6" font-family="Times,serif" font-size="14.00">dating</text>
</g>
<!-- willow&#45;&gt;xander -->
<g id="placez_edge40" class="edge"><title>willow&#45;&gt;xander</title>
<path fill="none" stroke="black" d="M485.683,-496.595C442.137,-500.814 363.806,-510.354 299.129,-528.8 270.395,-536.995 239.443,-549.935 215.392,-560.977"/>
<polygon fill="black" stroke="black" points="206.2,-565.258 213.365,-556.956 210.733,-563.147 215.265,-561.036 215.265,-561.036 215.265,-561.036 210.733,-563.147 217.165,-565.115 206.2,-565.258 206.2,-565.258"/>
<text text-anchor="middle" x="319.436" y="-533.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- willow&#45;&gt;giles -->
<g id="placez_edge42" class="edge"><title>willow&#45;&gt;giles</title>
<path fill="none" stroke="black" d="M547.035,-474.677C555.786,-469.142 565.397,-462.865 574,-456.8 584.646,-449.295 585.384,-444.432 597.129,-438.8 628.378,-423.815 639.9,-431.069 673,-420.8 674.877,-420.218 676.789,-419.595 678.713,-418.945"/>
<polygon fill="black" stroke="black" points="688.322,-415.523 680.411,-423.117 683.612,-417.2 678.902,-418.878 678.902,-418.878 678.902,-418.878 683.612,-417.2 677.392,-414.638 688.322,-415.523 688.322,-415.523"/>
<text text-anchor="middle" x="617.436" y="-443.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- willow&#45;&gt;dawn -->
<g id="placez_edge41" class="edge"><title>willow&#45;&gt;dawn</title>
<path fill="none" stroke="black" d="M516.889,-510.996C512.189,-541.435 497.927,-604.617 458,-636.8 447.1,-645.586 433.63,-652.834 421.241,-658.41"/>
<polygon fill="black" stroke="black" points="412.038,-662.346 419.462,-654.276 416.635,-660.38 421.232,-658.414 421.232,-658.414 421.232,-658.414 416.635,-660.38 423.002,-662.551 412.038,-662.346 412.038,-662.346"/>
<text text-anchor="middle" x="523.436" y="-578.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- tara&#45;&gt;buffy_house -->
<g id="placez_edge15" class="edge"><title>tara&#45;&gt;buffy_house</title>
<path fill="none" stroke="black" d="M437.24,-384.746C435.76,-373.664 435.754,-359.366 442.468,-348.8 445.295,-344.351 448.874,-340.446 452.911,-337.022"/>
<polygon fill="black" stroke="black" points="461.161,-331.012 455.727,-340.538 457.119,-333.956 453.078,-336.9 453.078,-336.9 453.078,-336.9 457.119,-333.956 450.428,-333.263 461.161,-331.012 461.161,-331.012"/>
<text text-anchor="middle" x="496.266" y="-353.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- tara&#45;&gt;willow -->
<g id="placez_edge9" class="edge"><title>tara&#45;&gt;willow</title>
<path fill="none" stroke="black" d="M440.908,-421.097C441.675,-432.282 444.3,-446.603 452.004,-456.8 458.293,-465.124 467.137,-471.653 476.343,-476.7"/>
<polygon fill="black" stroke="black" points="485.588,-481.264 474.629,-480.872 481.104,-479.05 476.621,-476.837 476.621,-476.837 476.621,-476.837 481.104,-479.05 478.613,-472.802 485.588,-481.264 485.588,-481.264"/>
<text text-anchor="middle" x="470.498" y="-443.6" font-family="Times,serif" font-size="14.00">dating</text>
</g>
<!-- tara&#45;&gt;dawn -->
<g id="placez_edge43" class="edge"><title>tara&#45;&gt;dawn</title>
<path fill="none" stroke="black" d="M437.442,-420.829C427.993,-466.046 402.213,-589.424 390.693,-644.555"/>
<polygon fill="black" stroke="black" points="388.588,-654.628 386.229,-643.919 389.611,-649.733 390.634,-644.839 390.634,-644.839 390.634,-644.839 389.611,-649.733 395.039,-645.76 388.588,-654.628 388.588,-654.628"/>
<text text-anchor="middle" x="434.436" y="-533.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- villain_lair&#45;&gt;magic_box -->
<g id="placez_edge25" class="edge"><title>villain_lair&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M358.333,-60.93C371.788,-72.6301 391.018,-87.6204 410.36,-96.8 437.732,-109.79 470.423,-118.261 497.6,-123.611"/>
<polygon fill="black" stroke="black" points="507.723,-125.511 497.064,-128.089 502.809,-124.588 497.894,-123.666 497.894,-123.666 497.894,-123.666 502.809,-124.588 498.725,-119.243 507.723,-125.511 507.723,-125.511"/>
<text text-anchor="middle" x="434.32" y="-83.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- villain_lair&#45;&gt;buffy_house -->
<g id="placez_edge26" class="edge"><title>villain_lair&#45;&gt;buffy_house</title>
<path fill="none" stroke="black" d="M298.576,-60.8589C245.438,-85.3697 163.786,-133.507 196.36,-186.8 248.763,-272.534 371.351,-299.515 447.406,-307.974"/>
<polygon fill="black" stroke="black" points="457.817,-309.049 447.408,-312.498 452.843,-308.535 447.87,-308.022 447.87,-308.022 447.87,-308.022 452.843,-308.535 448.332,-303.546 457.817,-309.049 457.817,-309.049"/>
<text text-anchor="middle" x="220.32" y="-173.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- high_school&#45;&gt;magic_box -->
<g id="placez_edge28" class="edge"><title>high_school&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M427.876,-204.348C432.579,-192.804 440.242,-178.132 451.36,-168.8 464.56,-157.721 481.46,-150.081 497.675,-144.84"/>
<polygon fill="black" stroke="black" points="507.643,-141.878 499.339,-149.04 502.85,-143.303 498.057,-144.727 498.057,-144.727 498.057,-144.727 502.85,-143.303 496.775,-140.413 507.643,-141.878 507.643,-141.878"/>
<text text-anchor="middle" x="475.32" y="-173.6" font-family="Times,serif" font-size="14.00">adjacent</text>
</g>
<!-- xander&#45;&gt;spike -->
<g id="placez_edge47" class="edge"><title>xander&#45;&gt;spike</title>
<path fill="none" stroke="black" d="M166.818,-601.101C157.996,-628.58 144.451,-683.519 159.669,-726.8 169.876,-755.829 178.852,-761.728 203,-780.8 232.331,-803.965 243.005,-806.736 279,-816.8 384.795,-846.379 515.444,-851.463 579.25,-852.024"/>
<polygon fill="black" stroke="black" points="589.269,-852.079 579.244,-856.524 584.269,-852.052 579.269,-852.024 579.269,-852.024 579.269,-852.024 584.269,-852.052 579.293,-847.524 589.269,-852.079 589.269,-852.079"/>
<text text-anchor="middle" x="178.665" y="-713.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- xander&#45;&gt;magic_box -->
<g id="placez_edge22" class="edge"><title>xander&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M172.253,-564.796C171.225,-524.604 172.955,-421.65 212.468,-348.8 218.097,-338.423 224.53,-339.941 232,-330.8 285.246,-265.639 260.134,-215.702 330,-168.8 356.649,-150.91 440.496,-141.585 497.433,-137.188"/>
<polygon fill="black" stroke="black" points="507.731,-136.423 498.092,-141.651 502.745,-136.794 497.758,-137.164 497.758,-137.164 497.758,-137.164 502.745,-136.794 497.425,-132.676 507.731,-136.423 507.731,-136.423"/>
<text text-anchor="middle" x="266.266" y="-353.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- xander&#45;&gt;buffy -->
<g id="placez_edge44" class="edge"><title>xander&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M182.973,-601.068C190.04,-612.24 200.317,-626.558 212,-636.8 304.532,-717.914 453.437,-747.546 523.371,-757.384"/>
<polygon fill="black" stroke="black" points="533.499,-758.747 522.988,-761.873 528.543,-758.08 523.588,-757.413 523.588,-757.413 523.588,-757.413 528.543,-758.08 524.188,-752.953 533.499,-758.747 533.499,-758.747"/>
<text text-anchor="middle" x="311.436" y="-668.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- xander&#45;&gt;willow -->
<g id="placez_edge45" class="edge"><title>xander&#45;&gt;willow</title>
<path fill="none" stroke="black" d="M179.305,-564.759C184.739,-552.62 193.83,-537.05 207.129,-528.8 251.017,-501.575 400.94,-495.479 475.779,-494.148"/>
<polygon fill="black" stroke="black" points="485.822,-493.99 475.894,-498.647 480.822,-494.068 475.823,-494.147 475.823,-494.147 475.823,-494.147 480.822,-494.068 475.752,-489.648 485.822,-493.99 485.822,-493.99"/>
<text text-anchor="middle" x="227.436" y="-533.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- anya -->
<g id="placez/place[@roleName=&#39;magic_box&#39;]/character[@roleName=&#39;anya&#39;]" class="node"><title>anya</title>
<polygon fill="green" stroke="black" points="145,-510.8 91,-510.8 91,-474.8 145,-474.8 145,-510.8"/>
<text text-anchor="middle" x="118" y="-488.6" font-family="Courier,monospace" font-size="14.00">anya</text>
</g>
<!-- xander&#45;&gt;anya -->
<g id="placez_edge16" class="edge"><title>xander&#45;&gt;anya</title>
<path fill="none" stroke="black" d="M139.735,-580.735C114.977,-577.981 82.6961,-569.822 66.0042,-546.8 56.8331,-534.151 68.0033,-521.598 82.3084,-511.886"/>
<polygon fill="black" stroke="black" points="90.9631,-506.517 84.8377,-515.613 86.7143,-509.153 82.4655,-511.789 82.4655,-511.789 82.4655,-511.789 86.7143,-509.153 80.0932,-507.965 90.9631,-506.517 90.9631,-506.517"/>
<text text-anchor="middle" x="84.4979" y="-533.6" font-family="Times,serif" font-size="14.00">dating</text>
</g>
<!-- xander&#45;&gt;dawn -->
<g id="placez_edge46" class="edge"><title>xander&#45;&gt;dawn</title>
<path fill="none" stroke="black" d="M206.343,-592.812C225.847,-598.783 250.572,-607.582 271,-618.8 282.418,-625.07 282.79,-630.39 294.129,-636.8 311.107,-646.397 331.236,-654.452 348.228,-660.406"/>
<polygon fill="black" stroke="black" points="357.824,-663.664 346.908,-664.71 353.089,-662.056 348.355,-660.449 348.355,-660.449 348.355,-660.449 353.089,-662.056 349.802,-656.188 357.824,-663.664 357.824,-663.664"/>
<text text-anchor="middle" x="314.436" y="-623.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- anya&#45;&gt;magic_box -->
<g id="placez_edge23" class="edge"><title>anya&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M119.244,-474.611C120.418,-456.881 122,-428.423 122,-403.8 122,-403.8 122,-403.8 122,-221.8 122,-145.999 381.153,-134.841 497.552,-133.652"/>
<polygon fill="black" stroke="black" points="507.69,-133.57 497.727,-138.151 502.69,-133.611 497.69,-133.651 497.69,-133.651 497.69,-133.651 502.69,-133.611 497.654,-129.151 507.69,-133.57 507.69,-133.57"/>
<text text-anchor="middle" x="175.266" y="-308.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- anya&#45;&gt;xander -->
<g id="placez_edge17" class="edge"><title>anya&#45;&gt;xander</title>
<path fill="none" stroke="black" d="M116.505,-511.151C116.363,-522.084 117.713,-536.104 124.004,-546.8 126.459,-550.973 129.628,-554.782 133.175,-558.221"/>
<polygon fill="black" stroke="black" points="140.873,-564.761 130.339,-561.717 137.063,-561.524 133.252,-558.287 133.252,-558.287 133.252,-558.287 137.063,-561.524 136.166,-554.857 140.873,-564.761 140.873,-564.761"/>
<text text-anchor="middle" x="142.498" y="-533.6" font-family="Times,serif" font-size="14.00">dating</text>
</g>
<!-- giles&#45;&gt;spike -->
<g id="placez_edge50" class="edge"><title>giles&#45;&gt;spike</title>
<path fill="none" stroke="black" d="M745.532,-409.364C784.612,-418.833 850,-442.102 850,-491.8 850,-763.8 850,-763.8 850,-763.8 850,-804.588 723.052,-833.185 656.968,-845.308"/>
<polygon fill="black" stroke="black" points="646.914,-847.112 655.962,-840.917 651.835,-846.229 656.757,-845.346 656.757,-845.346 656.757,-845.346 651.835,-846.229 657.551,-849.776 646.914,-847.112 646.914,-847.112"/>
<text text-anchor="middle" x="868.666" y="-623.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- giles&#45;&gt;magic_box -->
<g id="placez_edge24" class="edge"><title>giles&#45;&gt;magic_box</title>
<path fill="none" stroke="black" d="M697.935,-384.486C692.895,-379.187 687.806,-373.087 684,-366.8 644.545,-301.633 669.289,-268.821 628,-204.8 616.439,-186.874 599.426,-170.275 584.525,-157.642"/>
<polygon fill="black" stroke="black" points="576.512,-151.048 587.093,-153.928 580.372,-154.225 584.233,-157.402 584.233,-157.402 584.233,-157.402 580.372,-154.225 581.374,-160.877 576.512,-151.048 576.512,-151.048"/>
<text text-anchor="middle" x="709.266" y="-263.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- giles&#45;&gt;buffy -->
<g id="placez_edge48" class="edge"><title>giles&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M714.9,-420.831C709.606,-460.233 693.67,-560.165 660,-636.8 640.663,-680.813 631.235,-690.256 600,-726.8 596.886,-730.443 593.416,-734.091 589.875,-737.582"/>
<polygon fill="black" stroke="black" points="582.596,-744.476 586.762,-734.332 586.226,-741.038 589.856,-737.599 589.856,-737.599 589.856,-737.599 586.226,-741.038 592.951,-740.866 582.596,-744.476 582.596,-744.476"/>
<text text-anchor="middle" x="705.436" y="-578.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- giles&#45;&gt;willow -->
<g id="placez_edge49" class="edge"><title>giles&#45;&gt;willow</title>
<path fill="none" stroke="black" d="M688.322,-420.239C678.875,-425.892 668.415,-432.411 659.129,-438.8 648.398,-446.183 647.578,-450.831 636,-456.8 612.772,-468.775 584.788,-477.333 562.013,-482.987"/>
<polygon fill="black" stroke="black" points="552.276,-485.309 560.96,-478.612 557.14,-484.149 562.004,-482.989 562.004,-482.989 562.004,-482.989 557.14,-484.149 563.047,-487.367 552.276,-485.309 552.276,-485.309"/>
<text text-anchor="middle" x="679.436" y="-443.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- villain -->
<g id="placez/place[@roleName=&#39;villain_lair&#39;]/character" class="node"><title>villain</title>
<polygon fill="green" stroke="black" points="125.093,-870.8 50.9065,-870.8 50.9065,-834.8 125.093,-834.8 125.093,-870.8"/>
<text text-anchor="middle" x="88" y="-848.6" font-family="Courier,monospace" font-size="14.00">villain</text>
</g>
<!-- villain&#45;&gt;buffy -->
<g id="placez_edge51" class="edge"><title>villain&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M125.194,-844.895C213.261,-828.545 433.833,-787.595 523.345,-770.976"/>
<polygon fill="black" stroke="black" points="533.345,-769.12 524.334,-775.37 528.429,-770.033 523.513,-770.945 523.513,-770.945 523.513,-770.945 528.429,-770.033 522.691,-766.521 533.345,-769.12 533.345,-769.12"/>
<text text-anchor="middle" x="386.665" y="-803.6" font-family="Times,serif" font-size="14.00">dislike</text>
</g>
<!-- villain&#45;&gt;villain_lair -->
<g id="placez_edge27" class="edge"><title>villain&#45;&gt;villain_lair</title>
<path fill="none" stroke="black" d="M53.7249,-834.799C29.016,-819.862 0,-795.561 0,-763.8 0,-763.8 0,-763.8 0,-131.8 0,-76.2973 171.955,-55.2313 271.289,-47.6924"/>
<polygon fill="black" stroke="black" points="281.552,-46.9419 271.907,-52.1594 276.565,-47.3067 271.579,-47.6714 271.579,-47.6714 271.579,-47.6714 276.565,-47.3067 271.25,-43.1834 281.552,-46.9419 281.552,-46.9419"/>
<text text-anchor="middle" x="53.2658" y="-443.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- villain&#45;&gt;dawn -->
<g id="placez_edge52" class="edge"><title>villain&#45;&gt;dawn</title>
<path fill="none" stroke="black" d="M116.478,-834.733C170.889,-802.123 289.51,-731.029 349.193,-695.26"/>
<polygon fill="black" stroke="black" points="357.901,-690.041 351.637,-699.042 353.613,-692.611 349.324,-695.182 349.324,-695.182 349.324,-695.182 353.613,-692.611 347.01,-691.322 357.901,-690.041 357.901,-690.041"/>
<text text-anchor="middle" x="288.391" y="-758.6" font-family="Times,serif" font-size="14.00">hunting</text>
</g>
<!-- dawn&#45;&gt;buffy -->
<g id="placez_edge53" class="edge"><title>dawn&#45;&gt;buffy</title>
<path fill="none" stroke="black" d="M412.157,-683.724C429.299,-690.263 451.76,-699.341 471,-708.8 489.689,-717.988 509.762,-729.493 526.289,-739.433"/>
<polygon fill="black" stroke="black" points="535.074,-744.77 524.191,-743.424 530.8,-742.174 526.527,-739.578 526.527,-739.578 526.527,-739.578 530.8,-742.174 528.864,-735.732 535.074,-744.77 535.074,-744.77"/>
<text text-anchor="middle" x="524.436" y="-713.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- dawn&#45;&gt;willow -->
<g id="placez_edge55" class="edge"><title>dawn&#45;&gt;willow</title>
<path fill="none" stroke="black" d="M399.503,-654.523C403.786,-649.033 408.31,-642.82 412,-636.8 430.506,-606.607 425.538,-593.611 446.129,-564.8 453.299,-554.768 474.323,-534.561 491.957,-518.26"/>
<polygon fill="black" stroke="black" points="499.758,-511.096 495.436,-521.175 496.075,-514.478 492.393,-517.86 492.393,-517.86 492.393,-517.86 496.075,-514.478 489.349,-514.545 499.758,-511.096 499.758,-511.096"/>
<text text-anchor="middle" x="466.436" y="-578.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- dawn&#45;&gt;tara -->
<g id="placez_edge56" class="edge"><title>dawn&#45;&gt;tara</title>
<path fill="none" stroke="black" d="M379.126,-654.766C370.659,-627.652 357.273,-573.206 369.129,-528.8 379.136,-491.32 403.364,-453.411 420.929,-429.327"/>
<polygon fill="black" stroke="black" points="427.06,-421.106 424.689,-431.812 424.071,-425.114 421.082,-429.122 421.082,-429.122 421.082,-429.122 424.071,-425.114 417.475,-426.432 427.06,-421.106 427.06,-421.106"/>
<text text-anchor="middle" x="389.436" y="-533.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
<!-- dawn&#45;&gt;high_school -->
<g id="placez_edge29" class="edge"><title>dawn&#45;&gt;high_school</title>
<path fill="none" stroke="black" d="M375.097,-654.56C349.056,-608.347 281.467,-482.264 293.468,-438.8 314.398,-363 369.888,-287.013 400.673,-248.922"/>
<polygon fill="black" stroke="black" points="407.208,-240.946 404.351,-251.534 404.039,-244.814 400.87,-248.681 400.87,-248.681 400.87,-248.681 404.039,-244.814 397.389,-245.829 407.208,-240.946 407.208,-240.946"/>
<text text-anchor="middle" x="347.266" y="-443.6" font-family="Times,serif" font-size="14.00">contextNode_1_g$</text>
</g>
<!-- dawn&#45;&gt;xander -->
<g id="placez_edge54" class="edge"><title>dawn&#45;&gt;xander</title>
<path fill="none" stroke="black" d="M357.778,-666.559C315.945,-658.38 239.469,-642.887 228.129,-636.8 227.145,-636.272 211.967,-621.659 197.787,-607.912"/>
<polygon fill="black" stroke="black" points="190.543,-600.882 200.854,-604.617 194.131,-604.364 197.719,-607.846 197.719,-607.846 197.719,-607.846 194.131,-604.364 194.585,-611.075 190.543,-600.882 190.543,-600.882"/>
<text text-anchor="middle" x="248.436" y="-623.6" font-family="Times,serif" font-size="14.00">friends</text>
</g>
</g>
</svg>
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient>
</XholonWorkbook>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment