diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..496ee2c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
\ No newline at end of file
diff --git a/Drivetrain.ink b/Drivetrain.ink
new file mode 100644
index 0000000..fa6d6b7
--- /dev/null
+++ b/Drivetrain.ink
@@ -0,0 +1,11 @@
+== drivetrain
+
+Ok, great. So to start, let's talk about the kit of parts drivetrain. Are you planning on using that?
++ Yes, it's already built but I'm having problems
+-> not_implemented
++ We want to but we're not sure how to start...
+-> not_implemented
++ We're not sure why we should
+-> not_implemented
++ No, we're definitetly building something custom...
+-> not_implemented
\ No newline at end of file
diff --git a/FRC Assistant.ink b/FRC Assistant.ink
new file mode 100644
index 0000000..bbbcdea
--- /dev/null
+++ b/FRC Assistant.ink
@@ -0,0 +1,21 @@
+INCLUDE Drivetrain.ink
+
+Hey, I'm here to help give you some advice on how to build your robot this year. I'm just a compendium of best practices and resources, at the end of the day it is your robot, you should build something that meets your team's goals, whatever they may be.
+
+So let's get started...
+-> main_start
+== main_start
+What {~what can I help you with?| are you struggling with?}
++ I need to figure out my drivetrain
+ -> drivetrain
++ How do I grab the game piece?
+ -> not_implemented
++ I have the game piece but I don't know what to do next...
+ -> not_implemented
+
+
+== not_implemented
+Hey, sorry, I don't know how to help you with this yet. If you want to help build this check out my source on github<\/a>.
+-> main_start
+
+-> END
\ No newline at end of file
diff --git a/public/FRC Assistant.js b/public/FRC Assistant.js
new file mode 100644
index 0000000..b296656
--- /dev/null
+++ b/public/FRC Assistant.js
@@ -0,0 +1 @@
+var storyContent = {"inkVersion":17,"root":["\n","^Hey, I'm here to help give you some advice on how to build your robot this year. I'm just a compendium of best practices and resources, at the end of the day it is your robot, you should build something that meets your team's goals, whatever they may be.","\n","^So let's get started...","\n",{"->":"main_start"},"done",{"main_start":["^What ",["G>",["ev","visit",2,"seq","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"nop",{"s0":["pop","^what can I help you with?",{"->":".^.^.17"},null],"s1":["pop","^ are you struggling with?",{"->":".^.^.17"},null],"#f":5}],"G<",null],"\n",["ev",{"^->":"main_start.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^I need to figure out my drivetrain",{"->":"$r","var":true},null],"c":["ev",{"^->":"main_start.3.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"drivetrain"},{"#f":7}]}],["ev",{"^->":"main_start.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^How do I grab the game piece?",{"->":"$r","var":true},null],"c":["ev",{"^->":"main_start.4.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],["ev",{"^->":"main_start.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^I have the game piece but I don't know what to do next...",{"->":"$r","var":true},null],"c":["ev",{"^->":"main_start.5.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],{"#f":3}],"not_implemented":["^Hey, sorry, I don't know how to help you with this yet. If you want to help build this check out my source on github.","\n",{"->":"main_start"},"end",{"#f":3}],"drivetrain":["^Ok, great. So to start, let's talk about the kit of parts drivetrain. Are you planning on using that?","\n",["ev",{"^->":"drivetrain.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^Yes, it's already built but I'm having problems",{"->":"$r","var":true},null],"c":["ev",{"^->":"drivetrain.2.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],["ev",{"^->":"drivetrain.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^We want to but we're not sure how to start...",{"->":"$r","var":true},null],"c":["ev",{"^->":"drivetrain.3.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],["ev",{"^->":"drivetrain.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^We're not sure why we should",{"->":"$r","var":true},null],"c":["ev",{"^->":"drivetrain.4.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],["ev",{"^->":"drivetrain.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.c","flg":2},{"s":["^No, we're definitetly building something custom...",{"->":"$r","var":true},null],"c":["ev",{"^->":"drivetrain.5.c.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.s"},[{"#n":"$r2"}],"\n","\n",{"->":"not_implemented"},{"#f":7}]}],{"#f":3}],"#f":3}],"listDefs":{}};
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..168332f
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ FRC Assistant
+
+
+
+
+
+
+
+
+
+
+
FRC Assistant
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/ink.js b/public/ink.js
new file mode 100644
index 0000000..2c81141
--- /dev/null
+++ b/public/ink.js
@@ -0,0 +1,6697 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+ typeof define === 'function' && define.amd ? define('inkjs', ['exports'], factory) :
+ (factory((global.inkjs = global.inkjs || {})));
+}(this, (function (exports) { 'use strict';
+
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+ return typeof obj;
+ } : function (obj) {
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+ };
+
+
+
+
+
+
+
+
+
+
+
+ var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ };
+
+ var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+
+
+
+
+
+
+ var _extends = Object.assign || function (target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+
+ for (var key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+
+ return target;
+ };
+
+
+
+ var inherits = function (subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ };
+
+
+
+
+
+
+
+
+
+
+
+ var possibleConstructorReturn = function (self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ };
+
+ var Path$1 = function () {
+ function Path() /*polymorphic constructor*/{
+ classCallCheck(this, Path);
+
+ this._isRelative;
+ this._components = [];
+
+ if (typeof arguments[0] == 'string') {
+ this.componentsString = arguments[0];
+ } else if (arguments[0] instanceof Component && arguments[1] instanceof Path) {
+ this._components.push(arguments[0]);
+ this._components = this._components.concat(arguments[1]);
+ } else if (arguments[0] instanceof Array) {
+ this._components = this._components.concat(arguments[0]);
+ this._isRelative = !!arguments[1];
+ }
+ }
+
+ createClass(Path, [{
+ key: "PathByAppendingPath",
+ value: function PathByAppendingPath(pathToAppend) {
+ var p = new Path();
+
+ var upwardMoves = 0;
+ for (var i = 0; i < pathToAppend.components.length; ++i) {
+ if (pathToAppend.components[i].isParent) {
+ upwardMoves++;
+ } else {
+ break;
+ }
+ }
+
+ for (var i = 0; i < this.components.length - upwardMoves; ++i) {
+ p.components.push(this.components[i]);
+ }
+
+ for (var i = upwardMoves; i < pathToAppend.components.length; ++i) {
+ p.components.push(pathToAppend.components[i]);
+ }
+
+ return p;
+ }
+ }, {
+ key: "toString",
+ value: function toString() {
+ return this.componentsString;
+ }
+ }, {
+ key: "Equals",
+ value: function Equals(otherPath) {
+ if (otherPath == null) return false;
+
+ if (otherPath.components.length != this.components.length) return false;
+
+ if (otherPath.isRelative != this.isRelative) return false;
+
+ //the original code uses SequenceEqual here, so we need to iterate over the components manually.
+ for (var i = 0, l = otherPath.components.length; i < l; i++) {
+ //it's not quite clear whether this test should use Equals or a simple == operator, see https://github.com/y-lohse/inkjs/issues/22
+ if (!otherPath.components[i].Equals(this.components[i])) return false;
+ }
+
+ return true;
+ }
+ }, {
+ key: "isRelative",
+ get: function get$$1() {
+ return this._isRelative;
+ }
+ }, {
+ key: "components",
+ get: function get$$1() {
+ return this._components;
+ }
+ }, {
+ key: "head",
+ get: function get$$1() {
+ if (this.components.length > 0) {
+ return this.components[0];
+ } else {
+ return null;
+ }
+ }
+ }, {
+ key: "tail",
+ get: function get$$1() {
+ if (this.components.length >= 2) {
+ var tailComps = this.components.slice(1, this.components.length); //careful, the original code uses length-1 here. This is because the second argument of List.GetRange is a number of elements to extract, wherease Array.slice uses an index
+ return new Path(tailComps);
+ } else {
+ return Path.self;
+ }
+ }
+ }, {
+ key: "length",
+ get: function get$$1() {
+ return this.components.length;
+ }
+ }, {
+ key: "lastComponent",
+ get: function get$$1() {
+ if (this.components.length > 0) {
+ return this.components[this.components.length - 1];
+ } else {
+ return null;
+ }
+ }
+ }, {
+ key: "containsNamedComponent",
+ get: function get$$1() {
+ for (var i = 0, l = this.components.length; i < l; i++) {
+ if (!this.components[i].isIndex) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }, {
+ key: "componentsString",
+ get: function get$$1() {
+ var compsStr = this.components.join(".");
+ if (this.isRelative) return "." + compsStr;else return compsStr;
+ },
+ set: function set$$1(value) {
+ var _this = this;
+
+ this.components.length = 0;
+
+ var componentsStr = value;
+
+ if (componentsStr == null || componentsStr == '') return;
+
+ // When components start with ".", it indicates a relative path, e.g.
+ // .^.^.hello.5
+ // is equivalent to file system style path:
+ // ../../hello/5
+ if (componentsStr[0] == '.') {
+ this._isRelative = true;
+ componentsStr = componentsStr.substring(1);
+ }
+
+ var componentStrings = componentsStr.split('.');
+ componentStrings.forEach(function (str) {
+ //we need to distinguish between named components that start with a number, eg "42somewhere", and indexed components
+ //the normal parseInt won't do for the detection because it's too relaxed.
+ //see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
+ if (/^(\-|\+)?([0-9]+|Infinity)$/.test(str)) {
+ _this.components.push(new Component(parseInt(str)));
+ } else {
+ _this.components.push(new Component(str));
+ }
+ });
+ }
+ }], [{
+ key: "self",
+ get: function get$$1() {
+ var path = new Path();
+ path._isRelative = true;
+ return path;
+ }
+ }]);
+ return Path;
+ }();
+
+ var Component = function () {
+ function Component(indexOrName) {
+ classCallCheck(this, Component);
+
+ if (typeof indexOrName == 'string') {
+ this._index = -1;
+ this._name = indexOrName;
+ } else {
+ this._index = parseInt(indexOrName);
+ this._name = null;
+ }
+ }
+
+ createClass(Component, [{
+ key: "toString",
+ value: function toString() {
+ if (this.isIndex) {
+ return this.index.toString();
+ } else {
+ return this.name;
+ }
+ }
+ }, {
+ key: "Equals",
+ value: function Equals(otherComp) {
+ if (otherComp != null && otherComp.isIndex == this.isIndex) {
+ if (this.isIndex) {
+ return this.index == otherComp.index;
+ } else {
+ return this.name == otherComp.name;
+ }
+ }
+
+ return false;
+ }
+ }, {
+ key: "index",
+ get: function get$$1() {
+ return this._index;
+ }
+ }, {
+ key: "name",
+ get: function get$$1() {
+ return this._name;
+ }
+ }, {
+ key: "isIndex",
+ get: function get$$1() {
+ return this.index >= 0;
+ }
+ }, {
+ key: "isParent",
+ get: function get$$1() {
+ return this.name == Path$1.parentId;
+ }
+ }], [{
+ key: "ToParent",
+ value: function ToParent() {
+ return new Component(Path$1.parentId);
+ }
+ }]);
+ return Component;
+ }();
+
+ Path$1.parentId = "^";
+ Path$1.Component = Component;
+
+ var Object$1 = function () {
+ function Object() {
+ classCallCheck(this, Object);
+
+ this.parent = null;
+ this._path = null;
+ }
+
+ createClass(Object, [{
+ key: 'ResolvePath',
+ value: function ResolvePath(path) {
+ if (path.isRelative) {
+ var nearestContainer = this;
+
+ if (nearestContainer instanceof Container === false) {
+ if (this.parent == null) console.warn("Can't resolve relative path because we don't have a parent");
+
+ nearestContainer = this.parent;
+ if (nearestContainer.constructor.name !== 'Container') console.warn("Expected parent to be a container");
+
+ //Debug.Assert (path.components [0].isParent);
+ path = path.tail;
+ }
+
+ return nearestContainer.ContentAtPath(path);
+ } else {
+ return this.rootContentContainer.ContentAtPath(path);
+ }
+ }
+ }, {
+ key: 'ConvertPathToRelative',
+ value: function ConvertPathToRelative(globalPath) {
+ var ownPath = this.path;
+
+ var minPathLength = Math.min(globalPath.components.length, ownPath.components.length);
+ var lastSharedPathCompIndex = -1;
+
+ for (var i = 0; i < minPathLength; ++i) {
+ var ownComp = ownPath.components[i];
+ var otherComp = globalPath.components[i];
+
+ if (ownComp.Equals(otherComp)) {
+ lastSharedPathCompIndex = i;
+ } else {
+ break;
+ }
+ }
+
+ // No shared path components, so just use global path
+ if (lastSharedPathCompIndex == -1) return globalPath;
+
+ var numUpwardsMoves = ownPath.components.length - 1 - lastSharedPathCompIndex;
+
+ var newPathComps = [];
+
+ for (var up = 0; up < numUpwardsMoves; ++up) {
+ newPathComps.push(Path$1.Component.ToParent());
+ }for (var down = lastSharedPathCompIndex + 1; down < globalPath.components.length; ++down) {
+ newPathComps.push(globalPath.components[down]);
+ }var relativePath = new Path$1(newPathComps, true);
+ return relativePath;
+ }
+ }, {
+ key: 'CompactPathString',
+ value: function CompactPathString(otherPath) {
+ var globalPathStr = null;
+ var relativePathStr = null;
+
+ if (otherPath.isRelative) {
+ relativePathStr = otherPath.componentsString;
+ globalPathStr = this.path.PathByAppendingPath(otherPath).componentsString;
+ } else {
+ var relativePath = this.ConvertPathToRelative(otherPath);
+ relativePathStr = relativePath.componentsString;
+ globalPathStr = otherPath.componentsString;
+ }
+
+ if (relativePathStr.Length < globalPathStr.Length) return relativePathStr;else return globalPathStr;
+ }
+ }, {
+ key: 'Copy',
+ value: function Copy() {
+ throw "Not Implemented";
+ }
+ //SetCHild works slightly diferently in the js implementation. SInce we can't pass an objets property by reference, we instead pass the object and the property string.
+
+ }, {
+ key: 'SetChild',
+ value: function SetChild(obj, prop, value) {
+ if (obj[prop]) obj[prop] = null;
+
+ obj[prop] = value;
+
+ if (obj[prop]) obj[prop].parent = this;
+ }
+ }, {
+ key: 'path',
+ get: function get$$1() {
+ if (this._path == null) {
+
+ if (this.parent == null) {
+ this._path = new Path$1();
+ } else {
+ // Maintain a Stack so that the order of the components
+ // is reversed when they're added to the Path.
+ // We're iterating up the hierarchy from the leaves/children to the root.
+ var comps = [];
+
+ var child = this;
+ // Container container = child.parent as Container;
+ var container = child.parent;
+
+ while (container instanceof Container) {
+
+ var namedChild = child;
+ if (namedChild.name && namedChild.hasValidName) {
+ comps.unshift(new Path$1.Component(namedChild.name));
+ } else {
+ comps.unshift(new Path$1.Component(container.content.indexOf(child)));
+ }
+
+ child = container;
+ // container = container.parent as Container;
+ container = container.parent;
+ }
+
+ this._path = new Path$1(comps);
+ }
+ }
+
+ return this._path;
+ }
+ }, {
+ key: 'rootContentContainer',
+ get: function get$$1() {
+ var ancestor = this;
+ while (ancestor.parent) {
+ ancestor = ancestor.parent;
+ }
+ return ancestor;
+ }
+ }]);
+ return Object;
+ }();
+
+ var StringBuilder = function () {
+ function StringBuilder(str) {
+ classCallCheck(this, StringBuilder);
+
+ str = typeof str !== 'undefined' ? str.toString() : '';
+ this._string = str;
+ }
+
+ createClass(StringBuilder, [{
+ key: 'Append',
+ value: function Append(str) {
+ this._string += str;
+ }
+ }, {
+ key: 'AppendLine',
+ value: function AppendLine(str) {
+ if (typeof str !== 'undefined') this.Append(str);
+ this._string += "\n";
+ }
+ }, {
+ key: 'AppendFormat',
+ value: function AppendFormat(format) {
+ //taken from http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
+ var args = Array.prototype.slice.call(arguments, 1);
+ return format.replace(/{(\d+)}/g, function (match, number) {
+ return typeof args[number] != 'undefined' ? args[number] : match;
+ });
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return this._string;
+ }
+ }, {
+ key: 'Length',
+ get: function get$$1() {
+ return this._string.length;
+ }
+ }]);
+ return StringBuilder;
+ }();
+
+ var InkListItem = function () {
+ function InkListItem(fullNameOrOriginName, itemName) {
+ classCallCheck(this, InkListItem);
+
+ if (itemName !== undefined) {
+ this.originName = fullNameOrOriginName;
+ this.itemName = itemName;
+ } else {
+ var nameParts = fullNameOrOriginName.toString().split('.');
+ this.originName = nameParts[0];
+ this.itemName = nameParts[1];
+ }
+ }
+
+ createClass(InkListItem, [{
+ key: 'isNull',
+ value: function isNull() {
+ return this.originName == null && this.itemName == null;
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return this.fullname;
+ }
+ }, {
+ key: 'Equals',
+ value: function Equals(obj) {
+ if (obj instanceof InkListItem) {
+ // var otherItem = (InkListItem)obj;
+ var otherItem = obj;
+ return otherItem.itemName == this.itemName && otherItem.originName == this.originName;
+ }
+
+ return false;
+ }
+ //GetHashCode not implemented
+
+ }, {
+ key: 'toString',
+ value: function toString() {
+ //WARNING: experimental. InkListItem are structs and are used as keys inside hashes. In js, we can't use an object as a key, as the key needs to be a string. C# gets around that with the internal GetHashCode, and the js equivalent to that is toString. So here, toString acts as C#'s GetHashCode
+ var originCode = '0';
+ var itemCode = this.itemName ? this.itemName.toString() : 'null';
+ if (this.originName != null) originCode = this.originName.toString();
+
+ return originCode + itemCode;
+ }
+ }, {
+ key: 'fullName',
+ get: function get$$1() {
+ return (this.originName !== null ? this.originName : "?") + "." + this.itemName;
+ }
+ }], [{
+ key: 'Null',
+ value: function Null() {
+ return new InkListItem(null, null);
+ }
+ }]);
+ return InkListItem;
+ }();
+
+ //in C#, rawlists are based on dictionnary; the equivalent of a dictionnary in js is Object, but we can't use that or it will conflate dictionnary items and InkList class properties.
+ //instead InkList-js has a special _values property wich contains the actual "Dictionnary", and a few Dictionnary methods are re-implemented on InkList. This also means directly iterating over the InkList won't work as expected. Maybe we can return a proxy if that's required.
+ //@TODO: actually we could use a Map for this.
+ var InkList = function () {
+ function InkList(polymorphicArgument, originStory) {
+ var _this = this;
+
+ classCallCheck(this, InkList);
+
+ this._keys = {};
+ this._values = {};
+ this.origins = null;
+ this._originNames = null;
+
+ //polymorphioc constructor
+ if (polymorphicArgument) {
+ if (polymorphicArgument instanceof InkList) {
+ var otherList = polymorphicArgument;
+ otherList.forEach(function (kv) {
+ _this.Add(kv.Key, kv.Value);
+ });
+
+ this._originNames = otherList._originNames;
+ } else if (typeof polymorphicArgument === 'string') {
+ this.SetInitialOriginName(polymorphicArgument);
+
+ var def = null;
+ if (def = originStory.listDefinitions.TryGetDefinition(polymorphicArgument, def)) {
+ this.origins = [def];
+ } else {
+ throw new Error("InkList origin could not be found in story when constructing new list: " + singleOriginListName);
+ }
+ } else if (polymorphicArgument.hasOwnProperty('Key') && polymorphicArgument.hasOwnProperty('Value')) {
+ var singleElement = polymorphicArgument;
+ this.Add(singleElement.Key, singleElement.Value);
+ }
+ }
+ }
+
+ createClass(InkList, [{
+ key: 'forEach',
+ value: function forEach(fn) {
+ for (var key in this._values) {
+ fn({
+ Key: this._keys[key],
+ Value: this._values[key]
+ });
+ }
+ }
+ }, {
+ key: 'AddItem',
+ value: function AddItem(itemOrItemName) {
+ var _this2 = this;
+
+ if (itemOrItemName instanceof InkListItem) {
+ var item = itemOrItemName;
+
+ if (item.originName == null) {
+ this.AddItem(item.itemName);
+ return;
+ }
+
+ this.origins.forEach(function (origin) {
+ if (origin.name == item.originName) {
+ var intVal;
+ intVal = origin.TryGetValueForItem(item, intVal);
+ if (intVal !== undefined) {
+ _this2.Add(item, intVal);
+ return;
+ } else {
+ throw "Could not add the item " + item + " to this list because it doesn't exist in the original list definition in ink.";
+ }
+ }
+ });
+
+ throw "Failed to add item to list because the item was from a new list definition that wasn't previously known to this list. Only items from previously known lists can be used, so that the int value can be found.";
+ } else {
+ var itemName = itemOrItemName;
+
+ var foundListDef = null;
+
+ this.origins.forEach(function (origin) {
+ if (origin.ContainsItemWithName(itemName)) {
+ if (foundListDef != null) {
+ throw "Could not add the item " + itemName + " to this list because it could come from either " + origin.name + " or " + foundListDef.name;
+ } else {
+ foundListDef = origin;
+ }
+ }
+ });
+
+ if (foundListDef == null) throw "Could not add the item " + itemName + " to this list because it isn't known to any list definitions previously associated with this list.";
+
+ var item = new InkListItem(foundListDef.name, itemName);
+ var itemVal = foundListDef.ValueForItem(item);
+ this.Add(item, itemVal);
+ }
+ }
+ }, {
+ key: 'ContainsItemNamed',
+ value: function ContainsItemNamed(itemName) {
+ var contains = false;
+ this.forEach(function (itemWithValue) {
+ if (itemWithValue.Key.itemName == itemName) contains = true;
+ });
+ return contains;
+ }
+ }, {
+ key: 'ContainsKey',
+ value: function ContainsKey(key) {
+ return key in this._values;
+ }
+ }, {
+ key: 'Add',
+ value: function Add(key, value) {
+ this._keys[key] = key;
+ this._values[key] = value;
+ }
+ }, {
+ key: 'Remove',
+ value: function Remove(key) {
+ delete this._values[key];
+ delete this._keys[key];
+ }
+ }, {
+ key: 'SetInitialOriginName',
+ value: function SetInitialOriginName(initialOriginName) {
+ this._originNames = [initialOriginName];
+ }
+ }, {
+ key: 'SetInitialOriginNames',
+ value: function SetInitialOriginNames(initialOriginNames) {
+ if (initialOriginNames == null) this._originNames = null;else this._originNames = initialOriginNames.slice(); //store a copy
+ }
+ }, {
+ key: 'Union',
+ value: function Union(otherList) {
+ var union = new InkList(this);
+ otherList.forEach(function (kv) {
+ union.Add(kv.Key, kv.Value);
+ });
+ return union;
+ }
+ }, {
+ key: 'Intersect',
+ value: function Intersect(otherList) {
+ var intersection = new InkList();
+ this.forEach(function (kv) {
+ if (otherList.ContainsKey(kv.Key)) intersection.Add(kv.Key, kv.Value);
+ });
+ return intersection;
+ }
+ }, {
+ key: 'Without',
+ value: function Without(listToRemove) {
+ var result = new InkList(this);
+ listToRemove.forEach(function (kv) {
+ result.Remove(kv.Key);
+ });
+ return result;
+ }
+ }, {
+ key: 'Contains',
+ value: function Contains(otherList) {
+ var _this3 = this;
+
+ var contains = true;
+ otherList.forEach(function (kv) {
+ if (!_this3.ContainsKey(kv.Key)) contains = false;
+ });
+ return contains;
+ }
+ }, {
+ key: 'GreaterThan',
+ value: function GreaterThan(otherList) {
+ if (this.Count == 0) return false;
+ if (otherList.Count == 0) return true;
+
+ // All greater
+ return this.minItem.Value > otherList.maxItem.Value;
+ }
+ }, {
+ key: 'GreaterThanOrEquals',
+ value: function GreaterThanOrEquals(otherList) {
+ if (this.Count == 0) return false;
+ if (otherList.Count == 0) return true;
+
+ return this.minItem.Value >= otherList.minItem.Value && this.maxItem.Value >= otherList.maxItem.Value;
+ }
+ }, {
+ key: 'LessThan',
+ value: function LessThan(otherList) {
+ if (otherList.Count == 0) return false;
+ if (this.Count == 0) return true;
+
+ return this.maxItem.Value < otherList.minItem.Value;
+ }
+ }, {
+ key: 'LessThanOrEquals',
+ value: function LessThanOrEquals(otherList) {
+ if (otherList.Count == 0) return false;
+ if (this.Count == 0) return true;
+
+ return this.maxItem.Value <= otherList.maxItem.Value && this.minItem.Value <= otherList.minItem.Value;
+ }
+ }, {
+ key: 'MaxAsList',
+ value: function MaxAsList() {
+ if (this.Count > 0) return new InkList(this.maxItem);else return new InkList();
+ }
+ }, {
+ key: 'MinAsList',
+ value: function MinAsList() {
+ if (this.Count > 0) return new InkList(this.minItem);else return new InkList();
+ }
+ }, {
+ key: 'Equals',
+ value: function Equals(other) {
+ // var otherInkList = other as InkList;
+ var otherInkList = other;
+ if (otherInkList instanceof InkList === false) return false;
+ if (otherInkList.Count != this.Count) return false;
+
+ var equals = true;
+ this.forEach(function (kv) {
+ if (!otherInkList.ContainsKey(kv.Key)) equals = false;
+ });
+
+ return equals;
+ }
+ //GetHashCode not implemented
+
+ }, {
+ key: 'toString',
+ value: function toString() {
+ var ordered = [];
+ this.forEach(function (kv) {
+ ordered.push(kv);
+ });
+ ordered = ordered.sort(function (a, b) {
+ return a.Value === b.Value ? 0 : a.Value > b.Value ? 1 : -1;
+ });
+
+ var sb = new StringBuilder();
+ for (var i = 0; i < ordered.length; i++) {
+ if (i > 0) sb.Append(", ");
+
+ var item = ordered[i].Key;
+ sb.Append(item.itemName);
+ }
+
+ return sb.toString();
+ }
+ //casting a InkList to a Number, for somereason, actually gives a number. This messes up the type detection when creating a Value from a InkList. Returning NaN here prevents that.
+
+ }, {
+ key: 'valueOf',
+ value: function valueOf() {
+ return NaN;
+ }
+ }, {
+ key: 'Count',
+ get: function get$$1() {
+ return Object.keys(this._values).length;
+ }
+ }, {
+ key: 'originOfMaxItem',
+ get: function get$$1() {
+ if (this.origins == null) return null;
+
+ var maxOriginName = this.maxItem.Key.originName;
+ var result = null;
+ this.origins.every(function (origin) {
+ if (origin.name == maxOriginName) {
+ result = origin;
+ return false;
+ } else return true;
+ });
+
+ return result;
+ }
+ }, {
+ key: 'originNames',
+ get: function get$$1() {
+ var _this4 = this;
+
+ if (this.Count > 0) {
+ if (this._originNames == null && this.Count > 0) this._originNames = [];else this._originNames.length = 0;
+
+ this.forEach(function (itemAndValue) {
+ _this4._originNames.push(itemAndValue.Key.originName);
+ });
+ }
+
+ return this._originNames;
+ }
+ }, {
+ key: 'maxItem',
+ get: function get$$1() {
+ var max = {
+ Key: null,
+ Value: null
+ };
+ this.forEach(function (kv) {
+ if (max.Key === null || kv.Value > max.Value) max = kv;
+ });
+
+ return max;
+ }
+ }, {
+ key: 'minItem',
+ get: function get$$1() {
+ var min = {
+ Key: null,
+ Value: null
+ };
+ this.forEach(function (kv) {
+ if (min.Key === null || kv.Value < min.Value) min = kv;
+ });
+
+ return min;
+ }
+ }, {
+ key: 'inverse',
+ get: function get$$1() {
+ var _this5 = this;
+
+ var list = new InkList();
+ if (this.origins != null) {
+ this.origins.forEach(function (origin) {
+ origin.items.forEach(function (itemAndValue) {
+ if (!_this5.ContainsKey(itemAndValue.Key)) list.Add(itemAndValue.Key, itemAndValue.Value);
+ });
+ });
+ }
+ return list;
+ }
+ }, {
+ key: 'all',
+ get: function get$$1() {
+ var list = new InkList();
+ if (this.origins != null) {
+ this.origins.forEach(function (origin) {
+ origin.items.forEach(function (itemAndValue) {
+ list.Add(itemAndValue.Key, itemAndValue.Value);
+ });
+ });
+ }
+ return list;
+ }
+ }]);
+ return InkList;
+ }();
+
+ var ValueType = {
+ // Used in coersion
+ Int: 0,
+ Float: 1,
+ List: 2,
+ String: 3,
+
+ // Not used for coersion described above
+ DivertTarget: 4,
+ VariablePointer: 5
+ };
+
+ var AbstractValue = function (_InkObject) {
+ inherits(AbstractValue, _InkObject);
+
+ function AbstractValue(val) {
+ classCallCheck(this, AbstractValue);
+
+ var _this = possibleConstructorReturn(this, (AbstractValue.__proto__ || Object.getPrototypeOf(AbstractValue)).call(this));
+
+ _this._valueType;
+ _this._isTruthy;
+ _this._valueObject;
+ return _this;
+ }
+
+ createClass(AbstractValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ throw "Trying to casting an AbstractValue";
+ }
+ }, {
+ key: 'Copy',
+ value: function Copy(val) {
+ return AbstractValue.Create(val);
+ }
+ }, {
+ key: 'valueType',
+ get: function get$$1() {
+ return this._valueType;
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ return this._isTruthy;
+ }
+ }, {
+ key: 'valueObject',
+ get: function get$$1() {
+ return this._valueObject;
+ }
+ }], [{
+ key: 'Create',
+ value: function Create(val) {
+ // Implicitly convert bools into ints
+ if (typeof val === 'boolean') {
+ var b = !!val;
+ val = b ? 1 : 0;
+ }
+
+ if (Number.isInteger(Number(val))) {
+ return new IntValue(val);
+ } else if (!isNaN(val)) {
+ return new FloatValue(val);
+ } else if (typeof val === 'string') {
+ return new StringValue(val);
+ } else if (val instanceof Path$1) {
+ return new DivertTargetValue(val);
+ } else if (val instanceof InkList) {
+ return new ListValue(val);
+ }
+
+ return null;
+ }
+ }]);
+ return AbstractValue;
+ }(Object$1);
+
+ var Value = function (_AbstractValue) {
+ inherits(Value, _AbstractValue);
+
+ function Value(val) {
+ classCallCheck(this, Value);
+
+ var _this2 = possibleConstructorReturn(this, (Value.__proto__ || Object.getPrototypeOf(Value)).call(this));
+
+ _this2.value = val;
+ return _this2;
+ }
+
+ createClass(Value, [{
+ key: 'toString',
+ value: function toString() {
+ return this.value.toString();
+ }
+ }, {
+ key: 'value',
+ get: function get$$1() {
+ return this._value;
+ },
+ set: function set$$1(value) {
+ this._value = value;
+ }
+ }, {
+ key: 'valueObject',
+ get: function get$$1() {
+ return this.value;
+ }
+ }]);
+ return Value;
+ }(AbstractValue);
+
+ var IntValue = function (_Value) {
+ inherits(IntValue, _Value);
+
+ function IntValue(val) {
+ classCallCheck(this, IntValue);
+
+ var _this3 = possibleConstructorReturn(this, (IntValue.__proto__ || Object.getPrototypeOf(IntValue)).call(this, val || 0));
+
+ _this3._valueType = ValueType.Int;
+ return _this3;
+ }
+
+ createClass(IntValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == this.valueType) {
+ return this;
+ }
+
+ if (newType == ValueType.Float) {
+ return new FloatValue(parseFloat(this.value));
+ }
+
+ if (newType == ValueType.String) {
+ return new StringValue("" + this.value);
+ }
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ return this.value != 0;
+ }
+ }, {
+ key: 'valueType',
+ get: function get$$1() {
+ return ValueType.Int;
+ }
+ }]);
+ return IntValue;
+ }(Value);
+
+ var FloatValue = function (_Value2) {
+ inherits(FloatValue, _Value2);
+
+ function FloatValue(val) {
+ classCallCheck(this, FloatValue);
+
+ var _this4 = possibleConstructorReturn(this, (FloatValue.__proto__ || Object.getPrototypeOf(FloatValue)).call(this, val || 0.0));
+
+ _this4._valueType = ValueType.Float;
+ return _this4;
+ }
+
+ createClass(FloatValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == this.valueType) {
+ return this;
+ }
+
+ if (newType == ValueType.Int) {
+ return new IntValue(parseInt(this.value));
+ }
+
+ if (newType == ValueType.String) {
+ return new StringValue("" + this.value);
+ }
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ return this._value != 0.0;
+ }
+ }, {
+ key: 'valueType',
+ get: function get$$1() {
+ return ValueType.Float;
+ }
+ }]);
+ return FloatValue;
+ }(Value);
+
+ var StringValue = function (_Value3) {
+ inherits(StringValue, _Value3);
+
+ function StringValue(val) {
+ classCallCheck(this, StringValue);
+
+ var _this5 = possibleConstructorReturn(this, (StringValue.__proto__ || Object.getPrototypeOf(StringValue)).call(this, val || ''));
+
+ _this5._valueType = ValueType.String;
+
+ _this5._isNewline = _this5.value == "\n";
+ _this5._isInlineWhitespace = true;
+
+ _this5.value.split().every(function (c) {
+ if (c != ' ' && c != '\t') {
+ _this5._isInlineWhitespace = false;
+ return false;
+ }
+
+ return true;
+ });
+ return _this5;
+ }
+
+ createClass(StringValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == this.valueType) {
+ return this;
+ }
+
+ if (newType == ValueType.Int) {
+
+ var parsedInt;
+ if (parsedInt = parseInt(value)) {
+ return new IntValue(parsedInt);
+ } else {
+ return null;
+ }
+ }
+
+ if (newType == ValueType.Float) {
+ var parsedFloat;
+ if (parsedFloat = parsedFloat(value)) {
+ return new FloatValue(parsedFloat);
+ } else {
+ return null;
+ }
+ }
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'valueType',
+ get: function get$$1() {
+ return ValueType.String;
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ return this.value.length > 0;
+ }
+ }, {
+ key: 'isNewline',
+ get: function get$$1() {
+ return this._isNewline;
+ }
+ }, {
+ key: 'isInlineWhitespace',
+ get: function get$$1() {
+ return this._isInlineWhitespace;
+ }
+ }, {
+ key: 'isNonWhitespace',
+ get: function get$$1() {
+ return !this.isNewline && !this.isInlineWhitespace;
+ }
+ }]);
+ return StringValue;
+ }(Value);
+
+ var DivertTargetValue = function (_Value4) {
+ inherits(DivertTargetValue, _Value4);
+
+ function DivertTargetValue(targetPath) {
+ classCallCheck(this, DivertTargetValue);
+
+ var _this6 = possibleConstructorReturn(this, (DivertTargetValue.__proto__ || Object.getPrototypeOf(DivertTargetValue)).call(this, targetPath));
+
+ _this6._valueType = ValueType.DivertTarget;
+ return _this6;
+ }
+
+ createClass(DivertTargetValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == this.valueType) return this;
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return "DivertTargetValue(" + this.targetPath + ")";
+ }
+ }, {
+ key: 'targetPath',
+ get: function get$$1() {
+ return this.value;
+ },
+ set: function set$$1(value) {
+ this.value = value;
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ throw "Shouldn't be checking the truthiness of a divert target";
+ }
+ }]);
+ return DivertTargetValue;
+ }(Value);
+
+ var VariablePointerValue = function (_Value5) {
+ inherits(VariablePointerValue, _Value5);
+
+ function VariablePointerValue(variableName, contextIndex) {
+ classCallCheck(this, VariablePointerValue);
+
+ var _this7 = possibleConstructorReturn(this, (VariablePointerValue.__proto__ || Object.getPrototypeOf(VariablePointerValue)).call(this, variableName));
+
+ _this7._valueType = ValueType.VariablePointer;
+ _this7.contextIndex = typeof contextIndex !== 'undefined' ? contextIndex : -1;
+ return _this7;
+ }
+
+ createClass(VariablePointerValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == this.valueType) return this;
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return "VariablePointerValue(" + this.variableName + ")";
+ }
+ }, {
+ key: 'Copy',
+ value: function Copy() {
+ return new VariablePointerValue(this.variableName, this.contextIndex);
+ }
+ }, {
+ key: 'variableName',
+ get: function get$$1() {
+ return this.value;
+ },
+ set: function set$$1(value) {
+ this.value = value;
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ throw "Shouldn't be checking the truthiness of a variable pointer";
+ }
+ }]);
+ return VariablePointerValue;
+ }(Value);
+
+ var ListValue = function (_Value6) {
+ inherits(ListValue, _Value6);
+ createClass(ListValue, [{
+ key: 'Cast',
+ value: function Cast(newType) {
+ if (newType == ValueType.Int) {
+ var max = this.value.maxItem;
+ if (max.Key.isNull) return new IntValue(0);else return new IntValue(max.Value);
+ } else if (newType == ValueType.Float) {
+ var max = this.value.maxItem;
+ if (max.Key.isNull) return new FloatValue(0.0);else return new FloatValue(parseFloat(max.Value));
+ } else if (newType == ValueType.String) {
+ var max = value.maxItem;
+ if (max.Key.isNull) return new StringValue("");else {
+ return new StringValue(max.Key.toString());
+ }
+ }
+
+ if (newType == this.valueType) return this;
+
+ throw "Unexpected type cast of Value to new ValueType";
+ }
+ }, {
+ key: 'valueType',
+ get: function get$$1() {
+ return ValueType.List;
+ }
+ }, {
+ key: 'isTruthy',
+ get: function get$$1() {
+ var isTruthy = false;
+ this.value.forEach(function (kv) {
+ var listItemIntValue = kv.Value;
+ if (listItemIntValue != 0) isTruthy = true;
+ });
+ return isTruthy;
+ }
+ }]);
+
+ function ListValue(listOrSingleItem, singleValue) {
+ classCallCheck(this, ListValue);
+
+ var _this8 = possibleConstructorReturn(this, (ListValue.__proto__ || Object.getPrototypeOf(ListValue)).call(this, null));
+
+ _this8._valueType = ValueType.List;
+
+ if (listOrSingleItem instanceof InkList) {
+ _this8.value = new InkList(listOrSingleItem);
+ } else if (listOrSingleItem !== undefined && singleValue !== undefined) {
+ _this8.value = new InkList({
+ Key: listOrSingleItem,
+ Value: singleValue
+ });
+ } else {
+ _this8.value = new InkList();
+ }
+ return _this8;
+ }
+
+ createClass(ListValue, null, [{
+ key: 'RetainListOriginsForAssignment',
+ value: function RetainListOriginsForAssignment(oldValue, newValue) {
+ // var oldList = oldValue as ListValue;
+ var oldList = oldValue;
+ // var newList = newValue as ListValue;
+ var newList = newValue;
+
+ // When assigning the emtpy list, try to retain any initial origin names
+ if (oldList instanceof ListValue && newList instanceof ListValue && newList.value.Count == 0) newList.value.SetInitialOriginNames(oldList.value.originNames);
+ }
+ }]);
+ return ListValue;
+ }(Value);
+
+ var StoryException = function (_Error) {
+ inherits(StoryException, _Error);
+
+ function StoryException(message) {
+ classCallCheck(this, StoryException);
+
+ var _this = possibleConstructorReturn(this, (StoryException.__proto__ || Object.getPrototypeOf(StoryException)).call(this, message));
+
+ _this.message = message;
+ _this.name = 'StoryException';
+ return _this;
+ }
+
+ return StoryException;
+ }(Error);
+
+ var Container = function (_InkObject) {
+ inherits(Container, _InkObject);
+
+ //also implements INamedContent. Not sure how to do it cleanly in JS.
+ function Container() {
+ classCallCheck(this, Container);
+
+ var _this = possibleConstructorReturn(this, (Container.__proto__ || Object.getPrototypeOf(Container)).call(this));
+
+ _this.name = '';
+
+ _this._content = [];
+ _this.namedContent = {};
+
+ _this.visitsShouldBeCounted = false;
+ _this.turnIndexShouldBeCounted = false;
+ _this.countingAtStartOnly = false;
+
+ _this.CountFlags = {
+ Visits: 1,
+ Turns: 2,
+ CountStartOnly: 4
+ };
+
+ _this._pathToFirstLeafContent = null;
+ return _this;
+ }
+
+ createClass(Container, [{
+ key: 'AddContent',
+ value: function AddContent(contentObj) {
+ var _this2 = this;
+
+ if (contentObj instanceof Array) {
+ contentObj.forEach(function (c) {
+ _this2.AddContent(c);
+ });
+ } else {
+ this._content.push(contentObj);
+
+ if (contentObj.parent) {
+ throw "content is already in " + contentObj.parent;
+ }
+
+ contentObj.parent = this;
+
+ this.TryAddNamedContent(contentObj);
+ }
+ }
+ }, {
+ key: 'TryAddNamedContent',
+ value: function TryAddNamedContent(contentObj) {
+ //so here, in the reference implementation, contentObj is casted to an INamedContent
+ //but here we use js-style duck typing: if it implements the same props as the interface, we treat it as valid
+ if (contentObj.hasValidName && contentObj.name) {
+ this.AddToNamedContentOnly(contentObj);
+ }
+ }
+ }, {
+ key: 'AddToNamedContentOnly',
+ value: function AddToNamedContentOnly(namedContentObj) {
+ if (namedContentObj instanceof Object$1 === false) console.warn("Can only add Runtime.Objects to a Runtime.Container");
+ namedContentObj.parent = this;
+
+ this.namedContent[namedContentObj.name] = namedContentObj;
+ }
+ }, {
+ key: 'ContentAtPath',
+ value: function ContentAtPath(path, partialPathLength) {
+ partialPathLength = typeof partialPathLength !== 'undefined' ? partialPathLength : path.components.length;
+
+ var currentContainer = this;
+ var currentObj = this;
+
+ for (var i = 0; i < partialPathLength; ++i) {
+ var comp = path.components[i];
+ if (!(currentContainer instanceof Container)) throw "Path continued, but previous object wasn't a container: " + currentObj;
+
+ currentObj = currentContainer.ContentWithPathComponent(comp);
+ // currentContainer = currentObj as Container;
+ currentContainer = currentObj;
+ }
+
+ return currentObj;
+ }
+ }, {
+ key: 'InsertContent',
+ value: function InsertContent(contentObj, index) {
+ this.content[i] = contentObj;
+
+ if (contentObj.parent) {
+ throw "content is already in " + contentObj.parent;
+ }
+
+ contentObj.parent = this;
+
+ this.TryAddNamedContent(contentObj);
+ }
+ }, {
+ key: 'AddContentsOfContainer',
+ value: function AddContentsOfContainer(otherContainer) {
+ var _this3 = this;
+
+ this.content = this.content.concat(otherContainer.content);
+
+ otherContainer.content.forEach(function (obj) {
+ obj.parent = _this3;
+ _this3.TryAddNamedContent(obj);
+ });
+ }
+ }, {
+ key: 'ContentWithPathComponent',
+ value: function ContentWithPathComponent(component) {
+ if (component.isIndex) {
+
+ if (component.index >= 0 && component.index < this.content.length) {
+ return this.content[component.index];
+ }
+
+ // When path is out of range, quietly return nil
+ // (useful as we step/increment forwards through content)
+ else {
+ return null;
+ }
+ } else if (component.isParent) {
+ return this.parent;
+ } else {
+ var foundContent = null;
+ if (foundContent = this.namedContent[component.name]) {
+ return foundContent;
+ } else {
+ throw new StoryException("Content '" + component.name + "' not found at path: '" + this.path + "'");
+ }
+ }
+ }
+ }, {
+ key: 'BuildStringOfHierarchy',
+ value: function BuildStringOfHierarchy(sb, indentation, pointedObj) {
+ if (arguments.length == 0) {
+ var sb = new StringBuilder();
+ this.BuildStringOfHierarchy(sb, 0, null);
+ return sb.toString();
+ }
+
+ function appendIndentation() {
+ var spacesPerIndent = 4;
+ for (var i = 0; i < spacesPerIndent * indentation; ++i) {
+ sb.Append(" ");
+ }
+ }
+
+ appendIndentation();
+ sb.Append("[");
+
+ if (this.hasValidName) {
+ sb.AppendFormat(" ({0})", this.name);
+ }
+
+ if (this == pointedObj) {
+ sb.Append(" <---");
+ }
+
+ sb.AppendLine();
+
+ indentation++;
+
+ for (var i = 0; i < this.content.length; ++i) {
+
+ var obj = this.content[i];
+
+ if (obj instanceof Container) {
+
+ var container = obj;
+
+ container.BuildStringOfHierarchy(sb, indentation, pointedObj);
+ } else {
+ appendIndentation();
+ if (obj instanceof StringValue) {
+ sb.Append("\"");
+ sb.Append(obj.toString().replace("\n", "\\n"));
+ sb.Append("\"");
+ } else {
+ sb.Append(obj.toString());
+ }
+ }
+
+ if (i != this.content.length - 1) {
+ sb.Append(",");
+ }
+
+ if (!(obj instanceof Container) && obj == pointedObj) {
+ sb.Append(" <---");
+ }
+
+ sb.AppendLine();
+ }
+
+ var onlyNamed = {};
+
+ for (var key in this.namedContent) {
+ if (this.content.indexOf(this.namedContent[key]) >= 0) {
+ continue;
+ } else {
+ onlyNamed[key] = this.namedContent[key];
+ }
+ }
+
+ if (Object.keys(onlyNamed).length > 0) {
+ appendIndentation();
+ sb.AppendLine("-- named: --");
+
+ for (var key in onlyNamed) {
+ if (!(onlyNamed[key] instanceof Container)) console.warn("Can only print out named Containers");
+
+ var container = onlyNamed[key];
+ container.BuildStringOfHierarchy(sb, indentation, pointedObj);
+ sb.Append("\n");
+ }
+ }
+
+ indentation--;
+
+ appendIndentation();
+ sb.Append("]");
+ }
+ }, {
+ key: 'hasValidName',
+ get: function get$$1() {
+ return this.name != null && this.name.length > 0;
+ }
+ }, {
+ key: 'content',
+ get: function get$$1() {
+ return this._content;
+ },
+ set: function set$$1(value) {
+ this.AddContent(value);
+ }
+ }, {
+ key: 'namedOnlyContent',
+ get: function get$$1() {
+ var namedOnlyContentDict = {};
+
+ for (var key in this.namedContent) {
+ namedOnlyContentDict[key] = this.namedContent[key];
+ }
+
+ this.content.forEach(function (c) {
+ // var named = c as INamedContent;
+ var named = c;
+ if (named.name && named.hasValidName) {
+ delete namedOnlyContentDict[named.name];
+ }
+ });
+
+ if (Object.keys(namedOnlyContentDict).length == 0) namedOnlyContentDict = null;
+
+ return namedOnlyContentDict;
+ },
+ set: function set$$1(value) {
+ var existingNamedOnly = this.namedOnlyContent;
+ if (existingNamedOnly != null) {
+ for (var key in existingNamedOnly) {
+ delete this.namedContent[key];
+ }
+ }
+
+ if (value == null) return;
+
+ for (var key in value) {
+ // var named = kvPair.Value as INamedContent;
+ var named = value[key];
+ if (named.name && typeof named.hasValidName !== 'undefined') this.AddToNamedContentOnly(named);
+ }
+ }
+ }, {
+ key: 'countFlags',
+ get: function get$$1() {
+ var flags = 0;
+ if (this.visitsShouldBeCounted) flags |= this.CountFlags.Visits;
+ if (this.turnIndexShouldBeCounted) flags |= this.CountFlags.Turns;
+ if (this.countingAtStartOnly) flags |= this.CountFlags.CountStartOnly;
+
+ // If we're only storing CountStartOnly, it serves no purpose,
+ // since it's dependent on the other two to be used at all.
+ // (e.g. for setting the fact that *if* a gather or choice's
+ // content is counted, then is should only be counter at the start)
+ // So this is just an optimisation for storage.
+ if (flags == this.CountFlags.CountStartOnly) {
+ flags = 0;
+ }
+
+ return flags;
+ },
+ set: function set$$1(value) {
+ var flag = value;
+ if ((flag & this.CountFlags.Visits) > 0) this.visitsShouldBeCounted = true;
+ if ((flag & this.CountFlags.Turns) > 0) this.turnIndexShouldBeCounted = true;
+ if ((flag & this.CountFlags.CountStartOnly) > 0) this.countingAtStartOnly = true;
+ }
+ }, {
+ key: 'pathToFirstLeafContent',
+ get: function get$$1() {
+ if (this._pathToFirstLeafContent == null) this._pathToFirstLeafContent = this.path.PathByAppendingPath(this.internalPathToFirstLeafContent);
+
+ return this._pathToFirstLeafContent;
+ }
+ }, {
+ key: 'internalPathToFirstLeafContent',
+ get: function get$$1() {
+ var path = new Path();
+ var container = this;
+ while (container instanceof Container) {
+ if (container.content.length > 0) {
+ path.components.push(new Path.Component(0));
+ // container = container.content [0] as Container;
+ container = container.content[0];
+ }
+ }
+ return path;
+ }
+ }]);
+ return Container;
+ }(Object$1);
+
+ var Glue = function (_InkObject) {
+ inherits(Glue, _InkObject);
+
+ function Glue(type) {
+ classCallCheck(this, Glue);
+
+ var _this = possibleConstructorReturn(this, (Glue.__proto__ || Object.getPrototypeOf(Glue)).call(this));
+
+ _this.glueType = type;
+ return _this;
+ }
+
+ createClass(Glue, [{
+ key: "toString",
+ value: function toString() {
+ switch (this.glueType) {
+ case GlueType.Bidirectional:
+ return "BidirGlue";
+ case GlueType.Left:
+ return "LeftGlue";
+ case GlueType.Right:
+ return "RightGlue";
+ }
+
+ return "UnexpectedGlueType";
+ }
+ }, {
+ key: "isLeft",
+ get: function get$$1() {
+ return this.glueType == GlueType.Left;
+ }
+ }, {
+ key: "isBi",
+ get: function get$$1() {
+ return this.glueType == GlueType.Bidirectional;
+ }
+ }, {
+ key: "isRight",
+ get: function get$$1() {
+ return this.glueType == GlueType.Right;
+ }
+ }]);
+ return Glue;
+ }(Object$1);
+
+ var GlueType = {
+ Bidirectional: 0,
+ Left: 1,
+ Right: 2
+ };
+
+ var ControlCommand = function (_InkObject) {
+ inherits(ControlCommand, _InkObject);
+
+ function ControlCommand(commandType) {
+ classCallCheck(this, ControlCommand);
+
+ var _this = possibleConstructorReturn(this, (ControlCommand.__proto__ || Object.getPrototypeOf(ControlCommand)).call(this));
+
+ _this._commandType = typeof commandType != 'undefined' ? commandType : CommandType.NotSet;
+ return _this;
+ }
+
+ createClass(ControlCommand, [{
+ key: 'copy',
+ value: function copy() {
+ return new ControlCommand(this.commandType);
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return this.commandType.toString();
+ }
+ }, {
+ key: 'commandType',
+ get: function get$$1() {
+ return this._commandType;
+ }
+ }], [{
+ key: 'EvalStart',
+ value: function EvalStart() {
+ return new ControlCommand(CommandType.EvalStart);
+ }
+ }, {
+ key: 'EvalOutput',
+ value: function EvalOutput() {
+ return new ControlCommand(CommandType.EvalOutput);
+ }
+ }, {
+ key: 'EvalEnd',
+ value: function EvalEnd() {
+ return new ControlCommand(CommandType.EvalEnd);
+ }
+ }, {
+ key: 'Duplicate',
+ value: function Duplicate() {
+ return new ControlCommand(CommandType.Duplicate);
+ }
+ }, {
+ key: 'PopEvaluatedValue',
+ value: function PopEvaluatedValue() {
+ return new ControlCommand(CommandType.PopEvaluatedValue);
+ }
+ }, {
+ key: 'PopFunction',
+ value: function PopFunction() {
+ return new ControlCommand(CommandType.PopFunction);
+ }
+ }, {
+ key: 'PopTunnel',
+ value: function PopTunnel() {
+ return new ControlCommand(CommandType.PopTunnel);
+ }
+ }, {
+ key: 'BeginString',
+ value: function BeginString() {
+ return new ControlCommand(CommandType.BeginString);
+ }
+ }, {
+ key: 'EndString',
+ value: function EndString() {
+ return new ControlCommand(CommandType.EndString);
+ }
+ }, {
+ key: 'NoOp',
+ value: function NoOp() {
+ return new ControlCommand(CommandType.NoOp);
+ }
+ }, {
+ key: 'ChoiceCount',
+ value: function ChoiceCount() {
+ return new ControlCommand(CommandType.ChoiceCount);
+ }
+ }, {
+ key: 'TurnsSince',
+ value: function TurnsSince() {
+ return new ControlCommand(CommandType.TurnsSince);
+ }
+ }, {
+ key: 'ReadCount',
+ value: function ReadCount() {
+ return new ControlCommand(CommandType.ReadCount);
+ }
+ }, {
+ key: 'Random',
+ value: function Random() {
+ return new ControlCommand(CommandType.Random);
+ }
+ }, {
+ key: 'SeedRandom',
+ value: function SeedRandom() {
+ return new ControlCommand(CommandType.SeedRandom);
+ }
+ }, {
+ key: 'VisitIndex',
+ value: function VisitIndex() {
+ return new ControlCommand(CommandType.VisitIndex);
+ }
+ }, {
+ key: 'SequenceShuffleIndex',
+ value: function SequenceShuffleIndex() {
+ return new ControlCommand(CommandType.SequenceShuffleIndex);
+ }
+ }, {
+ key: 'StartThread',
+ value: function StartThread() {
+ return new ControlCommand(CommandType.StartThread);
+ }
+ }, {
+ key: 'Done',
+ value: function Done() {
+ return new ControlCommand(CommandType.Done);
+ }
+ }, {
+ key: 'End',
+ value: function End() {
+ return new ControlCommand(CommandType.End);
+ }
+ }, {
+ key: 'ListFromInt',
+ value: function ListFromInt() {
+ return new ControlCommand(CommandType.ListFromInt);
+ }
+ }, {
+ key: 'ListRange',
+ value: function ListRange() {
+ return new ControlCommand(CommandType.ListRange);
+ }
+ }]);
+ return ControlCommand;
+ }(Object$1);
+
+ var CommandType = {
+ NotSet: -1,
+ EvalStart: 0,
+ EvalOutput: 1,
+ EvalEnd: 2,
+ Duplicate: 3,
+ PopEvaluatedValue: 4,
+ PopFunction: 5,
+ PopTunnel: 6,
+ BeginString: 7,
+ EndString: 8,
+ NoOp: 9,
+ ChoiceCount: 10,
+ TurnsSince: 11,
+ Random: 12,
+ SeedRandom: 13,
+ VisitIndex: 14,
+ SequenceShuffleIndex: 15,
+ StartThread: 16,
+ Done: 17,
+ End: 18,
+ ListFromInt: 19,
+ ListRange: 20,
+ ReadCount: 21
+ };
+ CommandType.TOTAL_VALUES = Object.keys(CommandType).length - 1; //-1 because NotSet shoudn't count
+ ControlCommand.CommandType = CommandType;
+
+ var PushPopType = {
+ Tunnel: 0,
+ Function: 1
+ };
+
+ var Divert = function (_InkObject) {
+ inherits(Divert, _InkObject);
+
+ function Divert(stackPushType) {
+ classCallCheck(this, Divert);
+
+ var _this = possibleConstructorReturn(this, (Divert.__proto__ || Object.getPrototypeOf(Divert)).call(this));
+
+ _this._targetPath;
+ _this._targetContent;
+
+ _this.variableDivertName;
+ _this.pushesToStack;
+ _this.stackPushType;
+
+ _this.isExternal;
+ _this.isConditional;
+ _this.externalArgs;
+
+ //actual constructor
+ _this.pushesToStack = false;
+ if (stackPushType) {
+ _this.pushesToStack = true;
+ _this.stackPushType = stackPushType;
+ }
+ return _this;
+ }
+
+ createClass(Divert, [{
+ key: 'Equals',
+ value: function Equals(obj) {
+ // var otherDivert = obj as Divert;
+ var otherDivert = obj;
+ if (otherDivert instanceof Divert) {
+ if (this.hasVariableTarget == otherDivert.hasVariableTarget) {
+ if (this.hasVariableTarget) {
+ return this.variableDivertName == otherDivert.variableDivertName;
+ } else {
+ return this.targetPath.Equals(otherDivert.targetPath);
+ }
+ }
+ }
+ return false;
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ if (this.hasVariableTarget) {
+ return "Divert(variable: " + this.variableDivertName + ")";
+ } else if (this.targetPath == null) {
+ return "Divert(null)";
+ } else {
+
+ var sb = new StringBuilder();
+
+ var targetStr = this.targetPath.toString();
+ // int? targetLineNum = DebugLineNumberOfPath (targetPath);
+ var targetLineNum = null;
+ if (targetLineNum != null) {
+ targetStr = "line " + targetLineNum;
+ }
+
+ sb.Append("Divert");
+ if (this.pushesToStack) {
+ if (this.stackPushType == PushPopType.Function) {
+ sb.Append(" function");
+ } else {
+ sb.Append(" tunnel");
+ }
+ }
+
+ sb.Append(" (");
+ sb.Append(targetStr);
+ sb.Append(")");
+
+ return sb.toString();
+ }
+ }
+ }, {
+ key: 'targetPath',
+ get: function get$$1() {
+ // Resolve any relative paths to global ones as we come across them
+ if (this._targetPath != null && this._targetPath.isRelative) {
+ var targetObj = this.targetContent;
+ if (targetObj) {
+ this._targetPath = targetObj.path;
+ }
+ }
+
+ return this._targetPath;
+ },
+ set: function set$$1(value) {
+ this._targetPath = value;
+ this._targetContent = null;
+ }
+ }, {
+ key: 'targetContent',
+ get: function get$$1() {
+ if (this._targetContent == null) {
+ this._targetContent = this.ResolvePath(this._targetPath);
+ }
+
+ return this._targetContent;
+ }
+ }, {
+ key: 'targetPathString',
+ get: function get$$1() {
+ if (this.targetPath == null) return null;
+
+ return this.CompactPathString(this.targetPath);
+ },
+ set: function set$$1(value) {
+ if (value == null) {
+ this.targetPath = null;
+ } else {
+ this.targetPath = new Path$1(value);
+ }
+ }
+ }, {
+ key: 'hasVariableTarget',
+ get: function get$$1() {
+ return this.variableDivertName != null;
+ }
+ }]);
+ return Divert;
+ }(Object$1);
+
+ var ChoicePoint = function (_InkObject) {
+ inherits(ChoicePoint, _InkObject);
+
+ function ChoicePoint(onceOnly) {
+ classCallCheck(this, ChoicePoint);
+
+ var _this = possibleConstructorReturn(this, (ChoicePoint.__proto__ || Object.getPrototypeOf(ChoicePoint)).call(this));
+
+ _this._pathOnChoice;
+ _this.hasCondition;
+ _this.hasStartContent;
+ _this.hasChoiceOnlyContent;
+ _this.onceOnly;
+ _this.isInvisibleDefault;
+
+ _this.onceOnly = !!onceOnly;
+ return _this;
+ }
+
+ createClass(ChoicePoint, [{
+ key: 'toString',
+ value: function toString() {
+ // int? targetLineNum = DebugLineNumberOfPath (pathOnChoice);
+ var targetLineNum = null;
+ var targetString = this.pathOnChoice.toString();
+
+ if (targetLineNum != null) {
+ targetString = " line " + targetLineNum;
+ }
+
+ return "Choice: -> " + targetString;
+ }
+ }, {
+ key: 'pathOnChoice',
+ get: function get$$1() {
+ if (this._pathOnChoice != null && this._pathOnChoice.isRelative) {
+ var choiceTargetObj = this.choiceTarget;
+ if (choiceTargetObj) {
+ this._pathOnChoice = choiceTargetObj.path;
+ }
+ }
+ return this._pathOnChoice;
+ },
+ set: function set$$1(value) {
+ this._pathOnChoice = value;
+ }
+ }, {
+ key: 'choiceTarget',
+ get: function get$$1() {
+ //return this.ResolvePath (_pathOnChoice) as Container;
+ return this.ResolvePath(this._pathOnChoice);
+ }
+ }, {
+ key: 'pathStringOnChoice',
+ get: function get$$1() {
+ return this.CompactPathString(this.pathOnChoice);
+ },
+ set: function set$$1(value) {
+ this.pathOnChoice = new Path$1(value);
+ }
+ }, {
+ key: 'flags',
+ get: function get$$1() {
+ var flags = 0;
+ if (this.hasCondition) flags |= 1;
+ if (this.hasStartContent) flags |= 2;
+ if (this.hasChoiceOnlyContent) flags |= 4;
+ if (this.isInvisibleDefault) flags |= 8;
+ if (this.onceOnly) flags |= 16;
+ return flags;
+ },
+ set: function set$$1(value) {
+ this.hasCondition = (value & 1) > 0;
+ this.hasStartContent = (value & 2) > 0;
+ this.hasChoiceOnlyContent = (value & 4) > 0;
+ this.isInvisibleDefault = (value & 8) > 0;
+ this.onceOnly = (value & 16) > 0;
+ }
+ }]);
+ return ChoicePoint;
+ }(Object$1);
+
+ var VariableReference = function (_InkObject) {
+ inherits(VariableReference, _InkObject);
+
+ function VariableReference(name) {
+ classCallCheck(this, VariableReference);
+
+ var _this = possibleConstructorReturn(this, (VariableReference.__proto__ || Object.getPrototypeOf(VariableReference)).call(this));
+
+ _this.name = name;
+ _this.pathForCount;
+ return _this;
+ }
+
+ createClass(VariableReference, [{
+ key: 'toString',
+ value: function toString() {
+ if (this.name != null) {
+ return "var(" + this.name + ")";
+ } else {
+ var pathStr = this.pathStringForCount;
+ return "read_count(" + pathStr + ")";
+ }
+ }
+ }, {
+ key: 'containerForCount',
+ get: function get$$1() {
+ return this.ResolvePath(this.pathForCount);
+ }
+ }, {
+ key: 'pathStringForCount',
+ get: function get$$1() {
+ if (this.pathForCount == null) return null;
+
+ return this.CompactPathString(this.pathForCount);
+ },
+ set: function set$$1(value) {
+ if (value == null) this.pathForCount = null;else this.pathForCount = new Path$1(value);
+ }
+ }]);
+ return VariableReference;
+ }(Object$1);
+
+ var VariableAssignment = function (_InkObject) {
+ inherits(VariableAssignment, _InkObject);
+
+ function VariableAssignment(variableName, isNewDeclaration) {
+ classCallCheck(this, VariableAssignment);
+
+ var _this = possibleConstructorReturn(this, (VariableAssignment.__proto__ || Object.getPrototypeOf(VariableAssignment)).call(this));
+
+ _this._variableName = variableName || null;
+ _this._isNewDeclaration = !!isNewDeclaration;
+ _this.isGlobal;
+ return _this;
+ }
+
+ createClass(VariableAssignment, [{
+ key: "toString",
+ value: function toString() {
+ return "VarAssign to " + this.variableName;
+ }
+ }, {
+ key: "variableName",
+ get: function get$$1() {
+ return this._variableName;
+ }
+ }, {
+ key: "isNewDeclaration",
+ get: function get$$1() {
+ return this._isNewDeclaration;
+ }
+ }]);
+ return VariableAssignment;
+ }(Object$1);
+
+ var Void = function (_InkObject) {
+ inherits(Void, _InkObject);
+
+ function Void() {
+ classCallCheck(this, Void);
+ return possibleConstructorReturn(this, (Void.__proto__ || Object.getPrototypeOf(Void)).apply(this, arguments));
+ }
+
+ return Void;
+ }(Object$1);
+
+ //misses delegates, probably the returns from function calls
+ var NativeFunctionCall = function (_InkObject) {
+ inherits(NativeFunctionCall, _InkObject);
+
+ function NativeFunctionCall(name) {
+ classCallCheck(this, NativeFunctionCall);
+
+ var _this = possibleConstructorReturn(this, (NativeFunctionCall.__proto__ || Object.getPrototypeOf(NativeFunctionCall)).call(this));
+
+ _this.name = name;
+ _this._numberOfParameters;
+
+ _this._prototype;
+ _this._isPrototype;
+ _this._operationFuncs = null;
+
+ NativeFunctionCall.GenerateNativeFunctionsIfNecessary();
+ return _this;
+ }
+
+ createClass(NativeFunctionCall, [{
+ key: 'Call',
+ value: function Call(parameters) {
+ if (this._prototype) {
+ return this._prototype.Call(parameters);
+ }
+
+ if (this.numberOfParameters != parameters.length) {
+ throw "Unexpected number of parameters";
+ }
+
+ var hasList = false;
+ parameters.forEach(function (p) {
+ if (p instanceof Void) throw new StoryException("Attempting to perform operation on a void value. Did you forget to 'return' a value from a function you called here?");
+ if (p instanceof ListValue) hasList = true;
+ });
+
+ if (parameters.length == 2 && hasList) {
+ return this.CallBinaryListOperation(parameters);
+ }
+
+ var coercedParams = this.CoerceValuesToSingleType(parameters);
+ var coercedType = coercedParams[0].valueType;
+
+ //Originally CallType gets a type parameter that is used to do some casting, but we can do without.
+ if (coercedType == ValueType.Int) {
+ return this.CallType(coercedParams);
+ } else if (coercedType == ValueType.Float) {
+ return this.CallType(coercedParams);
+ } else if (coercedType == ValueType.String) {
+ return this.CallType(coercedParams);
+ } else if (coercedType == ValueType.DivertTarget) {
+ return this.CallType(coercedParams);
+ } else if (coercedType == ValueType.List) {
+ return this.CallType(coercedParams);
+ }
+
+ return null;
+ }
+ }, {
+ key: 'CallType',
+ value: function CallType(parametersOfSingleType) {
+ var param1 = parametersOfSingleType[0];
+ var valType = param1.valueType;
+
+ var val1 = param1;
+
+ var paramCount = parametersOfSingleType.length;
+
+ if (paramCount == 2 || paramCount == 1) {
+
+ var opForTypeObj = this._operationFuncs[valType];
+ if (!opForTypeObj) {
+ throw new StoryException("Cannot perform operation '" + this.name + "' on " + valType);
+ }
+
+ // Binary
+ if (paramCount == 2) {
+ var param2 = parametersOfSingleType[1];
+
+ var val2 = param2;
+
+ var opForType = opForTypeObj;
+
+ // Return value unknown until it's evaluated
+ var resultVal = opForType(val1.value, val2.value);
+
+ return Value.Create(resultVal);
+ }
+
+ // Unary
+ else {
+
+ var opForType = opForTypeObj;
+
+ var resultVal = opForType(val1.value);
+
+ return Value.Create(resultVal);
+ }
+ } else {
+ throw "Unexpected number of parameters to NativeFunctionCall: " + parametersOfSingleType.length;
+ }
+ }
+ }, {
+ key: 'CallBinaryListOperation',
+ value: function CallBinaryListOperation(parameters) {
+ // List-Int addition/subtraction returns a List (e.g. "alpha" + 1 = "beta")
+ if ((this.name == "+" || this.name == "-") && parameters[0] instanceof ListValue && parameters[1] instanceof IntValue) return this.CallListIncrementOperation(parameters);
+
+ // var v1 = parameters [0] as Value;
+ var v1 = parameters[0];
+ // var v2 = parameters [1] as Value;
+ var v2 = parameters[1];
+
+ // And/or with any other type requires coerscion to bool (int)
+ if ((this.name == "&&" || this.name == "||") && (v1.valueType != ValueType.List || v2.valueType != ValueType.List)) {
+ // var op = _operationFuncs [ValueType.Int] as BinaryOp;
+ var op = this._operationFuncs[ValueType.Int];
+ var result = op(v1.isTruthy ? 1 : 0, v2.isTruthy ? 1 : 0);
+ return new IntValue(result);
+ }
+
+ // Normal (list • list) operation
+ if (v1.valueType == ValueType.List && v2.valueType == ValueType.List) return this.CallType([v1, v2]);
+
+ throw new StoryException("Can not call use '" + this.name + "' operation on " + v1.valueType + " and " + v2.valueType);
+ }
+ }, {
+ key: 'CallListIncrementOperation',
+ value: function CallListIncrementOperation(listIntParams) {
+ var _this2 = this;
+
+ var listVal = listIntParams[0];
+ var intVal = listIntParams[1];
+
+ var resultInkList = new InkList();
+
+ listVal.value.forEach(function (listItemWithValue) {
+ var listItem = listItemWithValue.Key;
+ var listItemValue = listItemWithValue.Value;
+
+ // Find + or - operation
+ var intOp = _this2._operationFuncs[ValueType.Int];
+
+ // Return value unknown until it's evaluated
+ var targetInt = intOp(listItemValue, intVal.value);
+
+ // Find this item's origin (linear search should be ok, should be short haha)
+ var itemOrigin = null;
+ listVal.value.origins.forEach(function (origin) {
+ if (origin.name == listItem.originName) {
+ itemOrigin = origin;
+ return false;
+ }
+ });
+ if (itemOrigin != null) {
+ var incrementedItem = itemOrigin.TryGetItemWithValue(targetInt);
+ if (incrementedItem.exists) resultInkList.Add(incrementedItem.item, targetInt);
+ }
+ });
+
+ return new ListValue(resultInkList);
+ }
+ }, {
+ key: 'CoerceValuesToSingleType',
+ value: function CoerceValuesToSingleType(parametersIn) {
+ var valType = ValueType.Int;
+
+ var specialCaseList = null;
+
+ // Find out what the output type is
+ // "higher level" types infect both so that binary operations
+ // use the same type on both sides. e.g. binary operation of
+ // int and float causes the int to be casted to a float.
+ parametersIn.forEach(function (obj) {
+ var val = obj;
+ if (val.valueType > valType) {
+ valType = val.valueType;
+ }
+
+ if (val.valueType == ValueType.List) {
+ // specialCaseList = val as ListValue;
+ specialCaseList = val;
+ }
+ });
+
+ // Coerce to this chosen type
+ var parametersOut = [];
+
+ if (valType == ValueType.List) {
+ parametersIn.forEach(function (val) {
+ if (val.valueType == ValueType.List) {
+ parametersOut.push(val);
+ } else if (val.valueType == ValueType.Int) {
+ var intVal = parseInt(val.valueObject);
+ var list = specialCaseList.value.originOfMaxItem;
+
+ var item = list.TryGetItemWithValue(intVal);
+ if (item.exists) {
+ var castedValue = new ListValue(item.item, intVal);
+ parametersOut.push(castedValue);
+ } else throw new StoryException("Could not find List item with the value " + intVal + " in " + list.name);
+ } else throw new StoryException("Cannot mix Lists and " + val.valueType + " values in this operation");
+ });
+ }
+
+ // Normal Coercing (with standard casting)
+ else {
+ parametersIn.forEach(function (val) {
+ var castedValue = val.Cast(valType);
+ parametersOut.push(castedValue);
+ });
+ }
+
+ return parametersOut;
+ }
+ }, {
+ key: 'AddOpFuncForType',
+ value: function AddOpFuncForType(valType, op) {
+ if (this._operationFuncs == null) {
+ this._operationFuncs = {};
+ }
+
+ this._operationFuncs[valType] = op;
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return "Native '" + this.name + "'";
+ }
+ }, {
+ key: 'name',
+ get: function get$$1() {
+ return this._name;
+ },
+ set: function set$$1(value) {
+ this._name = value;
+ if (!this._isPrototype) this._prototype = NativeFunctionCall._nativeFunctions[this._name];
+ }
+ }, {
+ key: 'numberOfParameters',
+ get: function get$$1() {
+ if (this._prototype) {
+ return this._prototype.numberOfParameters;
+ } else {
+ return this._numberOfParameters;
+ }
+ },
+ set: function set$$1(value) {
+ this._numberOfParameters = value;
+ }
+ }], [{
+ key: 'internalConstructor',
+ value: function internalConstructor(name, numberOfParamters) {
+ var nativeFunc = new NativeFunctionCall(name);
+ nativeFunc._isPrototype = true;
+ nativeFunc.numberOfParameters = numberOfParamters;
+ return nativeFunc;
+ }
+ }, {
+ key: 'CallWithName',
+ value: function CallWithName(functionName) {
+ return new NativeFunctionCall(functionName);
+ }
+ }, {
+ key: 'CallExistsWithName',
+ value: function CallExistsWithName(functionName) {
+ this.GenerateNativeFunctionsIfNecessary();
+ return this._nativeFunctions[functionName];
+ }
+ }, {
+ key: 'GenerateNativeFunctionsIfNecessary',
+ value: function GenerateNativeFunctionsIfNecessary() {
+ if (this._nativeFunctions == null) {
+ this._nativeFunctions = {};
+
+ // Int operations
+ this.AddIntBinaryOp(this.Add, function (x, y) {
+ return x + y;
+ });
+ this.AddIntBinaryOp(this.Subtract, function (x, y) {
+ return x - y;
+ });
+ this.AddIntBinaryOp(this.Multiply, function (x, y) {
+ return x * y;
+ });
+ this.AddIntBinaryOp(this.Divide, function (x, y) {
+ return parseInt(x / y);
+ });
+ this.AddIntBinaryOp(this.Mod, function (x, y) {
+ return x % y;
+ });
+ this.AddIntUnaryOp(this.Negate, function (x) {
+ return -x;
+ });
+
+ this.AddIntBinaryOp(this.Equal, function (x, y) {
+ return x == y ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.Greater, function (x, y) {
+ return x > y ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.Less, function (x, y) {
+ return x < y ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.GreaterThanOrEquals, function (x, y) {
+ return x >= y ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.LessThanOrEquals, function (x, y) {
+ return x <= y ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.NotEquals, function (x, y) {
+ return x != y ? 1 : 0;
+ });
+ this.AddIntUnaryOp(this.Not, function (x) {
+ return x == 0 ? 1 : 0;
+ });
+
+ this.AddIntBinaryOp(this.And, function (x, y) {
+ return x != 0 && y != 0 ? 1 : 0;
+ });
+ this.AddIntBinaryOp(this.Or, function (x, y) {
+ return x != 0 || y != 0 ? 1 : 0;
+ });
+
+ this.AddIntBinaryOp(this.Max, function (x, y) {
+ return Math.max(x, y);
+ });
+ this.AddIntBinaryOp(this.Min, function (x, y) {
+ return Math.min(x, y);
+ });
+
+ // Float operations
+ this.AddFloatBinaryOp(this.Add, function (x, y) {
+ return x + y;
+ });
+ this.AddFloatBinaryOp(this.Subtract, function (x, y) {
+ return x - y;
+ });
+ this.AddFloatBinaryOp(this.Multiply, function (x, y) {
+ return x * y;
+ });
+ this.AddFloatBinaryOp(this.Divide, function (x, y) {
+ return x / y;
+ });
+ this.AddFloatBinaryOp(this.Mod, function (x, y) {
+ return x % y;
+ }); // TODO: Is this the operation we want for floats?
+ this.AddFloatUnaryOp(this.Negate, function (x) {
+ return -x;
+ });
+
+ this.AddFloatBinaryOp(this.Equal, function (x, y) {
+ return x == y ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.Greater, function (x, y) {
+ return x > y ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.Less, function (x, y) {
+ return x < y ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.GreaterThanOrEquals, function (x, y) {
+ return x >= y ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.LessThanOrEquals, function (x, y) {
+ return x <= y ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.NotEquals, function (x, y) {
+ return x != y ? 1 : 0;
+ });
+ this.AddFloatUnaryOp(this.Not, function (x) {
+ return x == 0.0 ? 1 : 0;
+ });
+
+ this.AddFloatBinaryOp(this.And, function (x, y) {
+ return x != 0.0 && y != 0.0 ? 1 : 0;
+ });
+ this.AddFloatBinaryOp(this.Or, function (x, y) {
+ return x != 0.0 || y != 0.0 ? 1 : 0;
+ });
+
+ this.AddFloatBinaryOp(this.Max, function (x, y) {
+ return Math.max(x, y);
+ });
+ this.AddFloatBinaryOp(this.Min, function (x, y) {
+ return Math.min(x, y);
+ });
+
+ // String operations
+ this.AddStringBinaryOp(this.Add, function (x, y) {
+ return x + y;
+ }); // concat
+ this.AddStringBinaryOp(this.Equal, function (x, y) {
+ return x === y ? 1 : 0;
+ });
+ this.AddStringBinaryOp(this.NotEquals, function (x, y) {
+ return !(x === y) ? 1 : 0;
+ });
+
+ this.AddListBinaryOp(this.Add, function (x, y) {
+ return x.Union(y);
+ });
+ this.AddListBinaryOp(this.Subtract, function (x, y) {
+ return x.Without(y);
+ });
+ this.AddListBinaryOp(this.Has, function (x, y) {
+ return x.Contains(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.Hasnt, function (x, y) {
+ return x.Contains(y) ? 0 : 1;
+ });
+ this.AddListBinaryOp(this.Intersect, function (x, y) {
+ return x.Intersect(y);
+ });
+
+ this.AddListBinaryOp(this.Equal, function (x, y) {
+ return x.Equals(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.Greater, function (x, y) {
+ return x.GreaterThan(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.Less, function (x, y) {
+ return x.LessThan(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.GreaterThanOrEquals, function (x, y) {
+ return x.GreaterThanOrEquals(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.LessThanOrEquals, function (x, y) {
+ return x.LessThanOrEquals(y) ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.NotEquals, function (x, y) {
+ return !x.Equals(y) ? 1 : 0;
+ });
+
+ this.AddListBinaryOp(this.And, function (x, y) {
+ return x.Count > 0 && y.Count > 0 ? 1 : 0;
+ });
+ this.AddListBinaryOp(this.Or, function (x, y) {
+ return x.Count > 0 || y.Count > 0 ? 1 : 0;
+ });
+
+ this.AddListUnaryOp(this.Not, function (x) {
+ return x.Count == 0 ? 1 : 0;
+ });
+
+ this.AddListUnaryOp(this.Invert, function (x) {
+ return x.inverse;
+ });
+ this.AddListUnaryOp(this.All, function (x) {
+ return x.all;
+ });
+ this.AddListUnaryOp(this.ListMin, function (x) {
+ return x.MinAsList();
+ });
+ this.AddListUnaryOp(this.ListMax, function (x) {
+ return x.MaxAsList();
+ });
+ this.AddListUnaryOp(this.Count, function (x) {
+ return x.Count;
+ });
+ this.AddListUnaryOp(this.ValueOfList, function (x) {
+ return x.maxItem.Value;
+ });
+
+ // Special case: The only operation you can do on divert target values
+ var divertTargetsEqual = function divertTargetsEqual(d1, d2) {
+ return d1.Equals(d2) ? 1 : 0;
+ };
+ this.AddOpToNativeFunc(this.Equal, 2, ValueType.DivertTarget, divertTargetsEqual);
+ }
+ }
+ }, {
+ key: 'AddOpToNativeFunc',
+ value: function AddOpToNativeFunc(name, args, valType, op) {
+ var nativeFunc = this._nativeFunctions[name];
+ if (!nativeFunc) {
+ nativeFunc = NativeFunctionCall.internalConstructor(name, args);
+ this._nativeFunctions[name] = nativeFunc;
+ }
+
+ nativeFunc.AddOpFuncForType(valType, op);
+ }
+ }, {
+ key: 'AddIntBinaryOp',
+ value: function AddIntBinaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 2, ValueType.Int, op);
+ }
+ }, {
+ key: 'AddIntUnaryOp',
+ value: function AddIntUnaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 1, ValueType.Int, op);
+ }
+ }, {
+ key: 'AddFloatBinaryOp',
+ value: function AddFloatBinaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 2, ValueType.Float, op);
+ }
+ }, {
+ key: 'AddFloatUnaryOp',
+ value: function AddFloatUnaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 1, ValueType.Float, op);
+ }
+ }, {
+ key: 'AddStringBinaryOp',
+ value: function AddStringBinaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 2, ValueType.String, op);
+ }
+ }, {
+ key: 'AddListBinaryOp',
+ value: function AddListBinaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 2, ValueType.List, op);
+ }
+ }, {
+ key: 'AddListUnaryOp',
+ value: function AddListUnaryOp(name, op) {
+ this.AddOpToNativeFunc(name, 1, ValueType.List, op);
+ }
+ }]);
+ return NativeFunctionCall;
+ }(Object$1);
+
+ NativeFunctionCall.Add = "+";
+ NativeFunctionCall.Subtract = "-";
+ NativeFunctionCall.Divide = "/";
+ NativeFunctionCall.Multiply = "*";
+ NativeFunctionCall.Mod = "%";
+ NativeFunctionCall.Negate = "_";
+
+ NativeFunctionCall.Equal = "==";
+ NativeFunctionCall.Greater = ">";
+ NativeFunctionCall.Less = "<";
+ NativeFunctionCall.GreaterThanOrEquals = ">=";
+ NativeFunctionCall.LessThanOrEquals = "<=";
+ NativeFunctionCall.NotEquals = "!=";
+ NativeFunctionCall.Not = "!";
+
+ NativeFunctionCall.And = "&&";
+ NativeFunctionCall.Or = "||";
+
+ NativeFunctionCall.Min = "MIN";
+ NativeFunctionCall.Max = "MAX";
+
+ NativeFunctionCall.Has = "?";
+ NativeFunctionCall.Hasnt = "!?";
+ NativeFunctionCall.Intersect = "^";
+
+ NativeFunctionCall.ListMin = "LIST_MIN";
+ NativeFunctionCall.ListMax = "LIST_MAX";
+ NativeFunctionCall.All = "LIST_ALL";
+ NativeFunctionCall.Count = "LIST_COUNT";
+ NativeFunctionCall.ValueOfList = "LIST_VALUE";
+ NativeFunctionCall.Invert = "LIST_INVERT";
+
+ NativeFunctionCall._nativeFunctions = null;
+
+ var Tag = function (_InkObject) {
+ inherits(Tag, _InkObject);
+
+ function Tag(tagText) {
+ classCallCheck(this, Tag);
+
+ var _this = possibleConstructorReturn(this, (Tag.__proto__ || Object.getPrototypeOf(Tag)).call(this));
+
+ _this._text = tagText.toString() || '';
+ return _this;
+ }
+
+ createClass(Tag, [{
+ key: 'toString',
+ value: function toString() {
+ return "# " + this._text;
+ }
+ }, {
+ key: 'text',
+ get: function get$$1() {
+ return this._text;
+ }
+ }]);
+ return Tag;
+ }(Object$1);
+
+ var Choice = function () {
+ function Choice(choice) {
+ classCallCheck(this, Choice);
+
+ this.text;
+ this.index;
+ this.choicePoint;
+ this.threadAtGeneration;
+
+ this._originalThreadIndex;
+ this._originalChoicePath;
+
+ if (choice) this.choicePoint = choice;
+ }
+
+ createClass(Choice, [{
+ key: "pathStringOnChoice",
+ get: function get$$1() {
+ return this.choicePoint.pathStringOnChoice;
+ }
+ }, {
+ key: "sourcePath",
+ get: function get$$1() {
+ return this.choicePoint.path.componentsString;
+ }
+ }]);
+ return Choice;
+ }();
+
+ var ListDefinition = function () {
+ function ListDefinition(name, items) {
+ classCallCheck(this, ListDefinition);
+
+ this._name = name || '';
+ this._items = null;
+ this._rawListItemsKeys = null;
+ this._itemNameToValues = items || {};
+ }
+
+ createClass(ListDefinition, [{
+ key: 'forEachItems',
+ value: function forEachItems(fn) {
+ for (var key in this._rawListItemsKeys) {
+ fn({
+ Key: this._rawListItemsKeys[key],
+ Value: this._items[key]
+ });
+ }
+ }
+ }, {
+ key: 'ValueForItem',
+ value: function ValueForItem(item) {
+ var intVal = this._itemNameToValues[item.itemName];
+ if (intVal !== undefined) return intVal;else return 0;
+ }
+ }, {
+ key: 'ContainsItem',
+ value: function ContainsItem(item) {
+ if (item.originName != this.name) return false;
+
+ return item.itemName in this._itemNameToValues;
+ }
+ }, {
+ key: 'ContainsItemWithName',
+ value: function ContainsItemWithName(itemName) {
+ return this._itemNameToValues[itemName] !== undefined;
+ }
+ }, {
+ key: 'TryGetItemWithValue',
+ value: function TryGetItemWithValue(val, item) {
+ //item was an out
+ //the original function returns a boolean and has a second parameter called item that is an `out`. Both are needed and we can't just return the item because it'll always be truthy. Instead, we return an object containing the bool and the item
+ for (var key in this._itemNameToValues) {
+ if (this._itemNameToValues[key] == val) {
+ item = new InkListItem(this.name, key);
+ return {
+ item: item,
+ exists: true
+ };
+ }
+ }
+
+ item = InkListItem.Null;
+ return {
+ item: item,
+ exists: false
+ };
+ }
+ }, {
+ key: 'TryGetValueForItem',
+ value: function TryGetValueForItem(item, intval) {
+ //intval is an out
+ intVal = this._itemNameToValues[item.itemName];
+ return intVal;
+ }
+ }, {
+ key: 'ListRange',
+ value: function ListRange(min, max) {
+ var rawList = new InkList();
+ for (var key in this._itemNameToValues) {
+ if (this._itemNameToValues[key] >= min && this._itemNameToValues[key] <= max) {
+ var item = new InkListItem(this.name, key);
+ rawList.Add(item, this._itemNameToValues[key]);
+ }
+ }
+ return new ListValue(rawList);
+ }
+ }, {
+ key: 'name',
+ get: function get$$1() {
+ return this._name;
+ }
+ }, {
+ key: 'items',
+ get: function get$$1() {
+ if (this._items == null) {
+ this._items = {};
+ this._rawListItemsKeys = {};
+ for (var key in this._itemNameToValues) {
+ var item = new InkListItem(this.name, key);
+ this._rawListItemsKeys[item] = item;
+ this._items[item] = this._itemNameToValues[key];
+ }
+ }
+ this._items.forEach = this.forEachItems.bind(this);
+
+ return this._items;
+ }
+ }]);
+ return ListDefinition;
+ }();
+
+ var ListDefinitionsOrigin = function () {
+ function ListDefinitionsOrigin(lists) {
+ var _this = this;
+
+ classCallCheck(this, ListDefinitionsOrigin);
+
+ this._lists = {};
+
+ lists.forEach(function (list) {
+ _this._lists[list.name] = list;
+ });
+ }
+
+ createClass(ListDefinitionsOrigin, [{
+ key: 'TryGetDefinition',
+ value: function TryGetDefinition(name, def) {
+ //initially, this function returns a boolean and the second parameter is an out.
+ return name in this._lists ? this._lists[name] : def;
+ }
+ }, {
+ key: 'FindSingleItemListWithName',
+ value: function FindSingleItemListWithName(name) {
+ var item = InkListItem.Null;
+ var list = null;
+
+ var nameParts = name.split('.');
+ if (nameParts.length == 2) {
+ item = new InkListItem(nameParts[0], nameParts[1]);
+ list = this.TryGetDefinition(item.originName, list);
+ } else {
+ for (var key in this._lists) {
+ var listWithItem = this._lists[key];
+ item = new InkListItem(key, name);
+ if (listWithItem.ContainsItem(item)) {
+ list = listWithItem;
+ break;
+ }
+ }
+ }
+
+ if (list != null) {
+ var itemValue = list.ValueForItem(item);
+ return new ListValue(item, itemValue);
+ }
+
+ return null;
+ }
+ }, {
+ key: 'lists',
+ get: function get$$1() {
+ var listOfLists = [];
+
+ for (var key in this._lists) {
+ listOfLists.push(this._lists[key]);
+ }
+ return listOfLists;
+ }
+ }]);
+ return ListDefinitionsOrigin;
+ }();
+
+ var JsonSerialisation = function () {
+ function JsonSerialisation() {
+ classCallCheck(this, JsonSerialisation);
+ }
+
+ createClass(JsonSerialisation, null, [{
+ key: 'ListToJArray',
+ value: function ListToJArray(serialisables) {
+ var _this = this;
+
+ var jArray = [];
+ serialisables.forEach(function (s) {
+ jArray.push(_this.RuntimeObjectToJToken(s));
+ });
+ return jArray;
+ }
+ }, {
+ key: 'JArrayToRuntimeObjList',
+ value: function JArrayToRuntimeObjList(jArray, skipLast) {
+ var count = jArray.length;
+ if (skipLast) count--;
+
+ var list = [];
+
+ for (var i = 0; i < count; i++) {
+ var jTok = jArray[i];
+ var runtimeObj = this.JTokenToRuntimeObject(jTok);
+ list.push(runtimeObj);
+ }
+
+ return list;
+ }
+ }, {
+ key: 'JObjectToDictionaryRuntimeObjs',
+ value: function JObjectToDictionaryRuntimeObjs(jObject) {
+ var dict = {};
+
+ for (var key in jObject) {
+ dict[key] = this.JTokenToRuntimeObject(jObject[key]);
+ }
+
+ return dict;
+ }
+ }, {
+ key: 'DictionaryRuntimeObjsToJObject',
+ value: function DictionaryRuntimeObjsToJObject(dictionary) {
+ var jsonObj = {};
+
+ for (var key in dictionary) {
+ // var runtimeObj = keyVal.Value as Runtime.Object;
+ var runtimeObj = dictionary[key];
+ if (runtimeObj instanceof Object$1) jsonObj[key] = this.RuntimeObjectToJToken(runtimeObj);
+ }
+
+ return jsonObj;
+ }
+ }, {
+ key: 'JObjectToIntDictionary',
+ value: function JObjectToIntDictionary(jObject) {
+ var dict = {};
+ for (var key in jObject) {
+ dict[key] = parseInt(jObject[key]);
+ }
+ return dict;
+ }
+ }, {
+ key: 'IntDictionaryToJObject',
+ value: function IntDictionaryToJObject(dict) {
+ var jObj = {};
+ for (var key in dict) {
+ jObj[key] = dict[key];
+ }
+ return jObj;
+ }
+ }, {
+ key: 'JTokenToRuntimeObject',
+ value: function JTokenToRuntimeObject(token) {
+ //@TODO probably find a more robust way to detect numbers, isNaN seems happy to accept things that really aren't numberish.
+ if (!isNaN(token) && token !== "\n") {
+ //JS thinks "\n" is a number
+ return Value.Create(token);
+ }
+
+ if (typeof token === 'string') {
+ var str = token.toString();
+
+ // String value
+ var firstChar = str[0];
+ if (firstChar == '^') return new StringValue(str.substring(1));else if (firstChar == "\n" && str.length == 1) return new StringValue("\n");
+
+ // Glue
+ if (str == "<>") return new Glue(GlueType.Bidirectional);else if (str == "G<") return new Glue(GlueType.Left);else if (str == "G>") return new Glue(GlueType.Right);
+
+ // Control commands (would looking up in a hash set be faster?)
+ for (var i = 0; i < _controlCommandNames.length; ++i) {
+ var cmdName = _controlCommandNames[i];
+ if (str == cmdName) {
+ return new ControlCommand(i);
+ }
+ }
+
+ // Native functions
+ if (str == "L^") str = "^";
+ if (NativeFunctionCall.CallExistsWithName(str)) return NativeFunctionCall.CallWithName(str);
+
+ // Pop
+ if (str == "->->") return ControlCommand.PopTunnel();else if (str == "~ret") return ControlCommand.PopFunction();
+
+ // Void
+ if (str == "void") return new Void();
+ }
+
+ if ((typeof token === 'undefined' ? 'undefined' : _typeof(token)) === 'object' && token instanceof Array === false) {
+ var obj = token;
+ var propValue;
+
+ // Divert target value to path
+ if (obj["^->"]) {
+ propValue = obj["^->"];
+ return new DivertTargetValue(new Path$1(propValue.toString()));
+ }
+
+ // VariablePointerValue
+ if (obj["^var"]) {
+ propValue = obj["^var"];
+ var varPtr = new VariablePointerValue(propValue.toString());
+ if (obj["ci"]) {
+ propValue = obj["ci"];
+ varPtr.contextIndex = parseInt(propValue);
+ }
+ return varPtr;
+ }
+
+ // Divert
+ var isDivert = false;
+ var pushesToStack = false;
+ var divPushType = PushPopType.Function;
+ var external = false;
+ if (propValue = obj["->"]) {
+ isDivert = true;
+ } else if (propValue = obj["f()"]) {
+ isDivert = true;
+ pushesToStack = true;
+ divPushType = PushPopType.Function;
+ } else if (propValue = obj["->t->"]) {
+ isDivert = true;
+ pushesToStack = true;
+ divPushType = PushPopType.Tunnel;
+ } else if (propValue = obj["x()"]) {
+ isDivert = true;
+ external = true;
+ pushesToStack = false;
+ divPushType = PushPopType.Function;
+ }
+
+ if (isDivert) {
+ var divert = new Divert();
+ divert.pushesToStack = pushesToStack;
+ divert.stackPushType = divPushType;
+ divert.isExternal = external;
+
+ var target = propValue.toString();
+
+ if (propValue = obj["var"]) divert.variableDivertName = target;else divert.targetPathString = target;
+
+ divert.isConditional = !!obj["c"];
+
+ if (external) {
+ if (propValue = obj["exArgs"]) divert.externalArgs = parseInt(propValue);
+ }
+
+ return divert;
+ }
+
+ // Choice
+ if (propValue = obj["*"]) {
+ var choice = new ChoicePoint();
+ choice.pathStringOnChoice = propValue.toString();
+
+ if (propValue = obj["flg"]) choice.flags = parseInt(propValue);
+
+ return choice;
+ }
+
+ // Variable reference
+ if (propValue = obj["VAR?"]) {
+ return new VariableReference(propValue.toString());
+ } else if (propValue = obj["CNT?"]) {
+ var readCountVarRef = new VariableReference();
+ readCountVarRef.pathStringForCount = propValue.toString();
+ return readCountVarRef;
+ }
+
+ // Variable assignment
+ var isVarAss = false;
+ var isGlobalVar = false;
+ if (propValue = obj["VAR="]) {
+ isVarAss = true;
+ isGlobalVar = true;
+ } else if (propValue = obj["temp="]) {
+ isVarAss = true;
+ isGlobalVar = false;
+ }
+ if (isVarAss) {
+ var varName = propValue.toString();
+ var isNewDecl = !obj["re"];
+ var varAss = new VariableAssignment(varName, isNewDecl);
+ varAss.isGlobal = isGlobalVar;
+ return varAss;
+ }
+ if (obj["#"] !== undefined) {
+ propValue = obj["#"];
+ return new Tag(propValue.toString());
+ }
+ //list value
+ if (propValue = obj["list"]) {
+ // var listContent = (Dictionary)propValue;
+ var listContent = propValue;
+ var rawList = new InkList();
+ if (propValue = obj["origins"]) {
+ // var namesAsObjs = (List