Browse Source

MPIDE-29: import MP IDE site as basis for new model-lang site

Kyle P Davis 10 years ago
parent
commit
bedf40225b

+ 3 - 0
.bowerrc

@@ -0,0 +1,3 @@
+{
+  "directory": "src/web/bower_components"
+}

+ 9 - 24
.gitignore

@@ -1,27 +1,12 @@
-# Logs
-logs
-*.log
+# misc files
+*.swp
+.DS_Store
 
-# Runtime data
-pids
-*.pid
-*.seed
+# outputs
+build/
+src/web/bower_components/
 
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
+# node
+node_modules/
+npm-debug.log
 
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directory
-# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
-node_modules

+ 27 - 0
.tern-project

@@ -0,0 +1,27 @@
+{
+  "libs": [
+	"ecma5",
+	"ecma6",
+    "browser",
+    "jquery"
+  ],
+  "loadEagerly": [
+    "src/**/*.js",
+    "src/**/*.es6"
+  ],
+  "dontLoad": [
+    "src/**/*.min.js",
+    "src/web/bower_components/**/*.js"
+  ],
+  "plugins": {
+    "complete_strings": {
+      "maxLength": 15
+    },
+    "node": {},
+    "lint": {},
+    "angular": true,
+    "doc_comment": {
+      "fullDocs": true
+    }
+  }
+}

+ 20 - 0
bower.json

@@ -0,0 +1,20 @@
+{
+  "name": "model-lang",
+  "description": "TODO: NAME ME: A new modeling language somewhat inspired by Monterey Phoenix",
+  "version": "0.0.0",
+  "homepage": "",
+  "license": "MIT",
+  "dependencies": {
+    "ace-builds": "~1.1.8",
+    "angular": "~1.4.0",
+    "angular-loader": "~1.4.0",
+    "angular-mocks": "~1.4.0",
+    "angular-route": "~1.4.0",
+    "angular-ui-ace": "~0.2.3",
+    "golden-layout": "~1.0.7",
+    "html5-boilerplate": "~4.3.0",
+    "jquery": "~2.1.3",
+    "bootstrap": "~3.3.4"
+  },
+  "private": true
+}

+ 44 - 0
gulpfile.js

@@ -0,0 +1,44 @@
+"use strict";
+
+var gulp = require("gulp"),
+	gutil = require("gulp-util"),
+	plumber = require("gulp-plumber"),
+	bower = require("gulp-bower"),
+	peg = require("gulp-peg"),
+/*
+	concat = require("gulp-concat"),
+	babel = require("gulp-babel"),
+	cssmin = require("gulp-cssmin"),
+*/
+	errLogger = gutil.log.bind(gutil, gutil.colors.red("Error: ")),
+	opts = {
+		buildDir: "build",
+	};
+
+
+gulp
+
+.task("bower", function() {
+	return bower();
+	//.pipe(gulp.dest("bowered"));
+})
+
+
+.task("parser", function() {
+	return gulp.src("src/lib/parser/modellang.pegjs")
+		.pipe(plumber(errLogger))
+		.pipe(peg({
+			exportVar: "modellangParser",
+		}))
+		.pipe(gulp.dest(opts.buildDir + "/lib/parser"));
+})
+
+
+.task("default", ["bower", "parser"], function() {
+	return gulp.src([
+		"src/web/assets/*.js",
+	])
+	.pipe(plumber(errLogger))
+	.pipe(gulp.dest(opts.buildDir + "/web/assets"));
+
+});

+ 23 - 0
package.json

@@ -0,0 +1,23 @@
+{
+  "name": "model-lang",
+  "version": "0.0.0",
+  "description": "TODO: NAME ME: A new modeling language somewhat inspired by Monterey Phoenix",
+  "repository": "https://github.com/RiveraGroup/model-lang.git",
+  "license": "MIT",
+  "devDependencies": {
+    "bower": "^1.4.1",
+    "babel": "^5.4.3",
+    "pegjs": "0.8.0"
+  },
+  "scripts": {
+    "postinstall": "./postinstall.sh",
+    "start": "http-server build/web/ -p 8000 -c-1",
+    "test": "karma start karma.conf.js",
+    "test-single-run": "karma start karma.conf.js --single-run",
+    "preupdate-webdriver": "npm install",
+    "update-webdriver": "webdriver-manager update",
+    "preprotractor": "npm run update-webdriver",
+    "protractor": "protractor tests-e2e/protractor.conf.js"
+  },
+  "private": true
+}

+ 20 - 0
postinstall.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+# A postinstall script for npm to trigger additional build steps
+###############################################################################
+set -o errexit -o pipefail
+
+CMD_DIR="$(cd "$(dirname "$0")"; pwd -P)"
+cd "$CMD_DIR"
+
+PATH="$PATH:$(npm bin)"
+
+echo "Build: bower ..."
+bower install
+
+echo "Build: parser ..."
+mkdir -p "build/lib/parser/"
+pegjs -e "modellangParser" "src/lib/parser/modellang.pegjs" "build/lib/parser/modellang.js"
+
+echo "Build: generator ..."
+mkdir -p "build/lib/generator/"
+babel -m umd --module-id "modellangGenerator" -s -L --stage 0 "src/lib/generator/modellang.es6" > "build/lib/generator/modellang.js"

+ 0 - 0
src/www/.jshintrc → src/web/.jshintrc


+ 157 - 0
src/web/assets/scripts/debug_ace_token_tooltip.js

@@ -0,0 +1,157 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Ajax.org B.V. nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*global ace*/
+ace.define("ace/token_tooltip",
+["require", "exports", "module", "ace/lib/oop", "ace/range", "ace/tooltip"],
+function(require, exports, module) {
+"use strict";
+
+// var dom = require("ace/lib/dom");
+var oop = require("ace/lib/oop");
+var event = require("ace/lib/event");
+var Range = require("ace/range").Range;
+var Tooltip = require("ace/tooltip").Tooltip;
+
+function TokenTooltip(editor) {
+    if (editor.tokenTooltip)
+        return;
+    Tooltip.call(this, editor.container);
+    editor.tokenTooltip = this;
+    this.editor = editor;
+
+    this.update = this.update.bind(this);
+    this.onMouseMove = this.onMouseMove.bind(this);
+    this.onMouseOut = this.onMouseOut.bind(this);
+    event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove);
+    event.addListener(editor.renderer.content, "mouseout", this.onMouseOut);
+}
+
+oop.inherits(TokenTooltip, Tooltip);
+
+(function() {
+    this.token = {};
+    this.range = new Range();
+
+    this.update = function() {
+        this.$timer = null;
+
+        var r = this.editor.renderer;
+        if (this.lastT - (r.timeStamp || 0) > 1000) {
+            r.rect = null;
+            r.timeStamp = this.lastT;
+            this.maxHeight = window.innerHeight;
+            this.maxWidth = window.innerWidth;
+        }
+
+        var canvasPos = r.rect || (r.rect = r.scroller.getBoundingClientRect());
+        var offset = (this.x + r.scrollLeft - canvasPos.left - r.$padding) / r.characterWidth;
+        var row = Math.floor((this.y + r.scrollTop - canvasPos.top) / r.lineHeight);
+        var col = Math.round(offset);
+
+        var screenPos = {row: row, column: col, side: offset - col > 0 ? 1 : -1};
+        var session = this.editor.session;
+        var docPos = session.screenToDocumentPosition(screenPos.row, screenPos.column);
+        var token = session.getTokenAt(docPos.row, docPos.column);
+
+        if (!token && !session.getLine(docPos.row)) {
+            token = {
+                type: "",
+                value: "",
+                state: session.bgTokenizer.getState(0),
+            };
+        }
+        if (!token) {
+            session.removeMarker(this.marker);
+            this.hide();
+            return;
+        }
+
+        var tokenText = token.type;
+        if (token.state)
+            tokenText += "|" + token.state;
+        if (token.merge)
+            tokenText += "\n  merge";
+        if (token.stateTransitions)
+            tokenText += "\n  " + token.stateTransitions.join("\n  ");
+
+        if (this.tokenText !== tokenText) {
+            this.setText(tokenText);
+            this.width = this.getWidth();
+            this.height = this.getHeight();
+            this.tokenText = tokenText;
+        }
+
+        this.show(null, this.x, this.y);
+
+        this.token = token;
+        session.removeMarker(this.marker);
+        this.range = new Range(docPos.row, token.start, docPos.row, token.start + token.value.length);
+        this.marker = session.addMarker(this.range, "ace_bracket", "text");
+    };
+
+    this.onMouseMove = function(e) {
+        this.x = e.clientX;
+        this.y = e.clientY;
+        if (this.isOpen) {
+            this.lastT = e.timeStamp;
+            this.setPosition(this.x, this.y);
+        }
+        if (!this.$timer)
+            this.$timer = setTimeout(this.update, 100);
+    };
+
+    this.onMouseOut = function(e) {
+        if (e && e.currentTarget.contains(e.relatedTarget))
+            return;
+        this.hide();
+        this.editor.session.removeMarker(this.marker);
+        this.$timer = clearTimeout(this.$timer);
+    };
+
+    this.setPosition = function(x, y) {
+        if (x + 10 + this.width > this.maxWidth)
+            x = window.innerWidth - this.width - 10;
+        if (y > window.innerHeight * 0.75 || y + 20 + this.height > this.maxHeight)
+            y = y - this.height - 30;
+
+        Tooltip.prototype.setPosition.call(this, x + 10, y + 20);
+    };
+
+    this.destroy = function() {
+        this.onMouseOut();
+        event.removeListener(this.editor.renderer.scroller, "mousemove", this.onMouseMove);
+        event.removeListener(this.editor.renderer.content, "mouseout", this.onMouseOut);
+        delete this.editor.tokenTooltip;
+    };
+
+}).call(TokenTooltip.prototype);
+
+exports.TokenTooltip = TokenTooltip;
+});

+ 850 - 0
src/web/assets/scripts/mp.js

@@ -0,0 +1,850 @@
+/*global ace*/
+
+ace.define("ace/mode/mp_highlight_rules",
+["require", "exports", "module", "ace/lib/oop"],
+function(require, exports, module) {
+	"use strict";
+
+	var oop = require("../lib/oop");
+	var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
+
+	var MpHighlightRules = function() {
+
+		this.$rules = {
+
+			// identifier: [a-zA-Z0-9]\w*
+			// variable:   \$\w+
+			start: [
+				// line comment
+				{
+					token: "comment.line.double-slash",
+					regex: /\/\/.*/,
+				},
+				// multi-line comment
+				{
+					token: "comment.block",
+					regex: /\/\*/,
+					next: "comment",
+				},
+				// schema
+				{
+					token: [
+						"keyword.operator",
+						"text",
+						"entity.name.section",
+						"text",
+						"punctuation.operator",
+						],
+					regex: /(\bSCHEMA\b)(\s+)([a-zA-Z0-9]\w*)(\s*)(;?)/,
+				},
+				// includes
+				{
+					token: [
+						"keyword.operator",
+						"text",
+						"entity.name.section",
+						"text",
+						"punctuation.operator",
+						],
+					regex: /(\bINCLUDE\b)(\s+)([a-zA-Z0-9]\w*)(\s*)(;)/,
+				},
+				// roots
+				{
+					token: [
+						"keyword",
+						"text",
+						"variable.other",
+						"text",
+						"punctuation.operator",
+						],
+					regex: /(\bROOT\b)(\s+)([a-zA-Z0-9]\w*)(\s*)(:)/,
+					push: "eventPatternList",
+				},
+				// events
+				{
+					token: [
+						"variable.other",
+						"text",
+						"punctuation.operator",
+						],
+					regex: /([a-zA-Z0-9]\w*)(\s*)(:)/,
+					push: "eventPatternList",
+				},
+				// push: shareAll
+				{
+					token: "entity.name.tag",
+					regex: /([a-zA-Z0-9$]\w*)(?=[$\w\s,]+\bSHARE\s+ALL\b)/,
+					push: "shareAll",
+				},
+				// push: coordinate
+				{
+					token: "keyword.control",
+					regex: /(\bCOORDINATE\b)/,
+					push: "coordinate",
+				},
+				// whitespace
+				{
+					token: "text",
+					regex: /\s+/,
+				},
+				// default: invalid
+				{
+					defaultToken: "invalid"
+				},
+			],
+
+			eventPatternList: [
+				// opening bracket
+				{
+					token: [
+						"paren.lparen.type",
+						"paren.lparen.quantifier",
+						],
+					regex: /([\[({])([*+]?)/,
+				},
+				// closing bracket
+				{
+					token: [
+						"paren.rparen.quantifier",
+						"paren.rparen.type",
+						],
+					regex: /([*+]?)([\])}])/,
+				},
+				// scope
+				{
+					token: [
+						"comment",
+						"comment",
+						"comment",
+						"comment",
+					],
+					regex: /(<)(\d)(\.\.\d)?(>)/,
+				},
+				// seperators
+				{
+					token: "keyword.operator",
+					regex: /[,|]/,
+				},
+				// identifiers
+				{
+					token: "text",
+					regex: /\$\w[\w\d_]*/,
+				},
+				{
+					token: "punctuation.operator",
+					regex: /;/,
+					next: "pop",
+				},
+			],
+
+			shareAll: [
+				// share all
+				{
+					token: "support.function",
+					regex: /(\bSHARE\s+ALL\b)/,
+				},
+				// id list
+				{
+					token: "entity.name.tag",
+					regex: /([a-zA-Z0-9]\w*)/,
+				},
+				// list seperator
+				{
+					token: "text",
+					regex: /[, ]/,
+				},
+				// pop: semicolon
+				{
+					token: "punctuation.operator",
+					regex: /(;)/,
+					next: "pop",
+				},
+			],
+
+			coordinate: [
+				// async flag
+				{
+					token: "support.function",
+					regex: /(<!>)/,
+				},
+				// coordination source list
+				{
+					token: [
+						"variable",
+						"punctuation.operator",
+						"text",
+						"text",
+						"text",
+						],
+					regex: /(\$\w+)(\s*:\s*)([a-zA-Z0-9]\w*|[(](([a-zA-Z0-9]\w*\s*\|?)+)[)])/,
+				},
+				// coordination source from
+				{
+					token:[
+						"keyword.control",
+						"text",
+						"variable",
+						"text",
+						],
+					regex: /(\bFROM\b)(\s+)(?:(\$\w+)|([a-zA-Z0-9]\w*))/,
+				},
+				// push: doBlock
+				{
+					token: "support.constant",
+					regex: /(\bDO\b)/,
+					push: "doBlock",
+				},
+				// pop: semi
+				{
+					token: "punctuation.operator",
+					regex: /;/,
+					next: "pop",
+				},
+				// seperator
+				{
+					token: "punctuation.operator",
+					regex: /,/,
+				},
+				// whitespace
+				{
+					token: "text",
+					regex: /\s+/,
+				},
+			],
+
+			addRelation: [
+				// relationship list
+				{
+					token: [
+						"variable",
+						"text",
+						"support.function",
+						"text",
+						"variable",
+						],
+					regex: /(\$\w+)(\s+)(IN|PRECEDES|CONTAINS|FOLLOWS)(\s+)(\$\w+)/,
+				},
+				// seperator
+				{
+					token: "text",
+					regex: /[, ]/,
+				},
+				// pop: semicolon
+				{
+					token: "punctuation.operator",
+					regex: /;/,
+					next: "pop",
+				},
+			],
+
+			doBlock: [
+				// push: addRelation
+				{
+					token: "support.function",
+					regex: /(\bADD\b)/,
+					push: "addRelation",
+				},
+				// push: share all
+				{
+					token: "text",
+					regex: /([a-zA-Z0-9]\w*)(?=[\w\s,]+\bSHARE\s+ALL\b)/,
+					push: "shareAll",
+				},
+				// push: coordinate
+				{
+					token: "keyword.control",
+					regex: /(\bCOORDINATE\b)/,
+					push: "coordinate",
+				},
+				// pop: od
+				{
+					token: "support.constant",
+					regex: /(\bOD\b)/,
+					next: "pop",
+				},
+			],
+
+			comment: [
+				// multi-line comment terminator
+				{
+					token: "comment.block",
+					regex: /.*?\*\//,
+					next: "start",
+				},
+				// stuff
+				{
+					regex: /.*/,
+					token: "comment.block",
+				},
+			],
+
+			meta: {
+				dontIndentStates: ["comment"],
+				lineComment: "//",
+			},
+
+		};
+
+		this.normalizeRules();
+	};
+
+	oop.inherits(MpHighlightRules, TextHighlightRules);
+
+	exports.MpHighlightRules = MpHighlightRules;
+
+});
+
+ace.define("ace/mode/mp",
+["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/mp_highlight_rules"],
+function(require, exports, module) {
+	"use strict";
+
+	var oop = require("../lib/oop");
+	var TextMode = require("./text").Mode;
+	var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
+	var CstyleFoldMode = require("./folding/cstyle").FoldMode;
+	var MpHighlightRules = require("./mp_highlight_rules").MpHighlightRules;
+
+	var Mode = function() {
+		this.HighlightRules = MpHighlightRules;
+
+		this.$behaviour = new CstyleBehaviour();
+		this.foldingRules = new CstyleFoldMode();
+	};
+	oop.inherits(Mode, TextMode);
+
+	(function() {
+		this.lineCommentStart = "//";
+		this.blockComment = {start:"/*", end:"*/"};
+		this.$id = "ace/mode/mp";
+
+		this.getNextLineIndent = function(state, line, tab) {
+			var indent = this.$getIndent(line);
+
+			var tokenizedLine = this.getTokenizer().getLineTokens(line, state);
+			var tokens = tokenizedLine.tokens;
+
+			if (tokens.length && tokens[tokens.length - 1].type === "comment") {
+				return indent;
+			}
+
+			var match;
+			if (state === "eventPatternList") {
+				match = line.match(/^.*(?:[:]).*$/);
+				if (match) {
+					indent += tab;
+				}
+			} else if (state[0] === "coordinate" || state[0] === "doBlock") {
+				match = line.match(/^.*(?:\bDO)\s*$/);
+				if (match) {
+					indent += tab;
+				}
+			}
+
+			return indent;
+		};
+	}).call(Mode.prototype);
+
+	exports.Mode = Mode;
+});
+
+ace.define("ace/mode/behaviour/cstyle",
+["require", "exports", "module", "ace/lib/oop", "ace/mode/behaviour", "ace/token_iterator", "ace/lib/lang"],
+function(require, exports, module) {
+	"use strict";
+
+	var oop = require("../../lib/oop");
+	var Behaviour = require("../behaviour").Behaviour;
+	var TokenIterator = require("../../token_iterator").TokenIterator;
+	var lang = require("../../lib/lang");
+
+	var SAFE_INSERT_IN_TOKENS =
+		["text", "paren.rparen", "punctuation.operator"];
+	var SAFE_INSERT_BEFORE_TOKENS =
+		["text", "paren.rparen", "punctuation.operator", "comment"];
+
+	var context;
+	var contextCache = {};
+	var initContext = function(editor) {
+		var id = -1;
+		if (editor.multiSelect) {
+			id = editor.selection.index;
+			if (contextCache.rangeCount !== editor.multiSelect.rangeCount)
+				contextCache = {rangeCount: editor.multiSelect.rangeCount};
+		}
+		if (contextCache[id])
+			return context = contextCache[id];
+		context = contextCache[id] = {
+			autoInsertedBrackets: 0,
+			autoInsertedRow: -1,
+			autoInsertedLineEnd: "",
+			maybeInsertedBrackets: 0,
+			maybeInsertedRow: -1,
+			maybeInsertedLineStart: "",
+			maybeInsertedLineEnd: "",
+		};
+	};
+
+	var getWrapped = function(selection, selected, opening, closing) {
+		var rowDiff = selection.end.row - selection.start.row;
+		return {
+			text: opening + selected + closing,
+			selection: [
+					0,
+					selection.start.column + 1,
+					rowDiff,
+					selection.end.column + (rowDiff ? 0 : 1),
+				],
+		};
+	};
+
+	var CstyleBehaviour = function() {
+		this.add("braces", "insertion", function(state, action, editor, session, text) {
+			var cursor = editor.getCursorPosition();
+			var line = session.doc.getLine(cursor.row);
+			if (text === "{") {
+				initContext(editor);
+				var selection = editor.getSelectionRange();
+				var selected = session.doc.getTextRange(selection);
+				if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) {
+					return getWrapped(selection, selected, "{", "}");
+				} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
+					if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) {
+						CstyleBehaviour.recordAutoInsert(editor, session, "}");
+						return {
+							text: "{}",
+							selection: [1, 1],
+						};
+					} else {
+						CstyleBehaviour.recordMaybeInsert(editor, session, "{");
+						return {
+							text: "{",
+							selection: [1, 1],
+						};
+					}
+				}
+			} else if (text === "}") {
+				initContext(editor);
+				var rightChar = line.substring(cursor.column, cursor.column + 1);
+				if (rightChar === "}") {
+					var matching = session.$findOpeningBracket("}", {column: cursor.column + 1, row: cursor.row});
+					if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
+						CstyleBehaviour.popAutoInsertedClosing();
+						return {
+							text: "",
+							selection: [1, 1],
+						};
+					}
+				}
+			} else if (text === "\n" || text === "\r\n") {
+				initContext(editor);
+				var closing = "";
+				if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) {
+					closing = lang.stringRepeat("}", context.maybeInsertedBrackets);
+					CstyleBehaviour.clearMaybeInsertedClosing();
+				}
+				var rightChar = line.substring(cursor.column, cursor.column + 1);
+				if (rightChar === "}") {
+					var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column + 1}, "}");
+					if (!openBracePos)
+						return null;
+					var next_indent = this.$getIndent(session.getLine(openBracePos.row));
+				} else if (closing) {
+					var next_indent = this.$getIndent(line);
+				} else {
+					CstyleBehaviour.clearMaybeInsertedClosing();
+					return;
+				}
+				var indent = next_indent + session.getTabString();
+
+				return {
+					text: "\n" + indent + "\n" + next_indent + closing,
+					selection: [1, indent.length, 1, indent.length],
+				};
+			} else {
+				CstyleBehaviour.clearMaybeInsertedClosing();
+			}
+		});
+
+		this.add("braces", "deletion", function(state, action, editor, session, range) {
+			var selected = session.doc.getTextRange(range);
+			if (!range.isMultiLine() && selected === "{") {
+				initContext(editor);
+				var line = session.doc.getLine(range.start.row);
+				var rightChar = line.substring(range.end.column, range.end.column + 1);
+				if (rightChar === "}") {
+					range.end.column++;
+					return range;
+				} else {
+					context.maybeInsertedBrackets--;
+				}
+			}
+		});
+
+		this.add("parens", "insertion", function(state, action, editor, session, text) {
+			if (text === "(") {
+				initContext(editor);
+				var selection = editor.getSelectionRange();
+				var selected = session.doc.getTextRange(selection);
+				if (selected !== "" && editor.getWrapBehavioursEnabled()) {
+					return getWrapped(selection, selected, "(", ")");
+				} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
+					CstyleBehaviour.recordAutoInsert(editor, session, ")");
+					return {
+						text: "()",
+						selection: [1, 1],
+					};
+				}
+			} else if (text === ")") {
+				initContext(editor);
+				var cursor = editor.getCursorPosition();
+				var line = session.doc.getLine(cursor.row);
+				var rightChar = line.substring(cursor.column, cursor.column + 1);
+				if (rightChar === ")") {
+					var matching = session.$findOpeningBracket(")", {column: cursor.column + 1, row: cursor.row});
+					if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
+						CstyleBehaviour.popAutoInsertedClosing();
+						return {
+							text: "",
+							selection: [1, 1],
+						};
+					}
+				}
+			}
+		});
+
+		this.add("parens", "deletion", function(state, action, editor, session, range) {
+			var selected = session.doc.getTextRange(range);
+			if (!range.isMultiLine() && selected === "(") {
+				initContext(editor);
+				var line = session.doc.getLine(range.start.row);
+				var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
+				if (rightChar === ")") {
+					range.end.column++;
+					return range;
+				}
+			}
+		});
+
+		this.add("brackets", "insertion", function(state, action, editor, session, text) {
+			if (text == "[") {
+				initContext(editor);
+				var selection = editor.getSelectionRange();
+				var selected = session.doc.getTextRange(selection);
+				if (selected !== "" && editor.getWrapBehavioursEnabled()) {
+					return getWrapped(selection, selected, "[", "]");
+				} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
+					CstyleBehaviour.recordAutoInsert(editor, session, "]");
+					return {
+						text: "[]",
+						selection: [1, 1],
+					};
+				}
+			} else if (text == "]") {
+				initContext(editor);
+				var cursor = editor.getCursorPosition();
+				var line = session.doc.getLine(cursor.row);
+				var rightChar = line.substring(cursor.column, cursor.column + 1);
+				if (rightChar == "]") {
+					var matching = session.$findOpeningBracket("]", {column: cursor.column + 1, row: cursor.row});
+					if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
+						CstyleBehaviour.popAutoInsertedClosing();
+						return {
+							text: "",
+							selection: [1, 1],
+						};
+					}
+				}
+			}
+		});
+
+		this.add("brackets", "deletion", function(state, action, editor, session, range) {
+			var selected = session.doc.getTextRange(range);
+			if (!range.isMultiLine() && selected == "[") {
+				initContext(editor);
+				var line = session.doc.getLine(range.start.row);
+				var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
+				if (rightChar == "]") {
+					range.end.column++;
+					return range;
+				}
+			}
+		});
+
+		this.add("string_dquotes", "insertion", function(state, action, editor, session, text) {
+			if (text === '"' || text === "'") {
+				initContext(editor);
+				var quote = text;
+				var selection = editor.getSelectionRange();
+				var selected = session.doc.getTextRange(selection);
+				if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) {
+					return getWrapped(selection, selected, quote, quote);
+				} else if (!selected) {
+					var cursor = editor.getCursorPosition();
+					var line = session.doc.getLine(cursor.row);
+					var leftChar = line.substring(cursor.column - 1, cursor.column);
+					var rightChar = line.substring(cursor.column, cursor.column + 1);
+
+					var token = session.getTokenAt(cursor.row, cursor.column);
+					var rightToken = session.getTokenAt(cursor.row, cursor.column + 1);
+					if (leftChar === "\\" && token && /escape/.test(token.type))
+						return null;
+
+					var stringBefore = token && /string/.test(token.type);
+					var stringAfter = !rightToken || /string/.test(rightToken.type);
+
+					var pair;
+					if (rightChar === quote) {
+						pair = stringBefore !== stringAfter;
+					} else {
+						if (stringBefore && !stringAfter)
+							return null; // wrap string with different quote
+						if (stringBefore && stringAfter)
+							return null; // do not pair quotes inside strings
+						var wordRe = session.$mode.tokenRe;
+						wordRe.lastIndex = 0;
+						var isWordBefore = wordRe.test(leftChar);
+						wordRe.lastIndex = 0;
+						var isWordAfter = wordRe.test(leftChar);
+						if (isWordBefore || isWordAfter)
+							return null; // before or after alphanumeric
+						if (rightChar && !/[\s;,.})\]\\]/.test(rightChar))
+							return null; // there is rightChar and it isn't closing
+						pair = true;
+					}
+					return {
+						text: pair ? quote + quote : "",
+						selection: [1, 1],
+					};
+				}
+			}
+		});
+
+		this.add("string_dquotes", "deletion", function(state, action, editor, session, range) {
+			var selected = session.doc.getTextRange(range);
+			if (!range.isMultiLine() && (selected === '"' || selected === "'")) {
+				initContext(editor);
+				var line = session.doc.getLine(range.start.row);
+				var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
+				if (rightChar === selected) {
+					range.end.column++;
+					return range;
+				}
+			}
+		});
+
+	};
+
+
+	CstyleBehaviour.isSaneInsertion = function(editor, session) {
+		var cursor = editor.getCursorPosition();
+		var iterator = new TokenIterator(session, cursor.row, cursor.column);
+		if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) {
+			var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1);
+			if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS))
+				return false;
+		}
+		iterator.stepForward();
+		return iterator.getCurrentTokenRow() !== cursor.row ||
+			this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS);
+	};
+
+	CstyleBehaviour.$matchTokenType = function(token, types) {
+		return types.indexOf(token.type || token) > -1;
+	};
+
+	CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) {
+		var cursor = editor.getCursorPosition();
+		var line = session.doc.getLine(cursor.row);
+		if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0]))
+			context.autoInsertedBrackets = 0;
+		context.autoInsertedRow = cursor.row;
+		context.autoInsertedLineEnd = bracket + line.substr(cursor.column);
+		context.autoInsertedBrackets++;
+	};
+
+	CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) {
+		var cursor = editor.getCursorPosition();
+		var line = session.doc.getLine(cursor.row);
+		if (!this.isMaybeInsertedClosing(cursor, line))
+			context.maybeInsertedBrackets = 0;
+		context.maybeInsertedRow = cursor.row;
+		context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket;
+		context.maybeInsertedLineEnd = line.substr(cursor.column);
+		context.maybeInsertedBrackets++;
+	};
+
+	CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) {
+		return context.autoInsertedBrackets > 0 &&
+			cursor.row === context.autoInsertedRow &&
+			bracket === context.autoInsertedLineEnd[0] &&
+			line.substr(cursor.column) === context.autoInsertedLineEnd;
+	};
+
+	CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) {
+		return context.maybeInsertedBrackets > 0 &&
+			cursor.row === context.maybeInsertedRow &&
+			line.substr(cursor.column) === context.maybeInsertedLineEnd &&
+			line.substr(0, cursor.column) === context.maybeInsertedLineStart;
+	};
+
+	CstyleBehaviour.popAutoInsertedClosing = function() {
+		context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1);
+		context.autoInsertedBrackets--;
+	};
+
+	CstyleBehaviour.clearMaybeInsertedClosing = function() {
+		if (context) {
+			context.maybeInsertedBrackets = 0;
+			context.maybeInsertedRow = -1;
+		}
+	};
+
+
+
+	oop.inherits(CstyleBehaviour, Behaviour);
+
+	exports.CstyleBehaviour = CstyleBehaviour;
+});
+
+ace.define("ace/mode/folding/cstyle",
+["require", "exports", "module", "ace/lib/oop", "ace/range", "ace/mode/folding/fold_mode"],
+function(require, exports, module) {
+	"use strict";
+
+	var oop = require("../../lib/oop");
+	var Range = require("../../range").Range;
+	var BaseFoldMode = require("./fold_mode").FoldMode;
+
+	var FoldMode = exports.FoldMode = function(commentRegex) {
+		if (commentRegex) {
+			this.foldingStartMarker = new RegExp(
+				this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start)
+			);
+			this.foldingStopMarker = new RegExp(
+				this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end)
+			);
+		}
+	};
+	oop.inherits(FoldMode, BaseFoldMode);
+
+	(function() {
+
+		this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/;
+		this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/;
+		this.singleLineBlockCommentRe = /^\s*(\/\*).*\*\/\s*$/;
+		this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/;
+		this.startRegionRe = /^\s*(\/\*|\/\/)#region\b/;
+		this._getFoldWidgetBase = this.getFoldWidget;
+		this.getFoldWidget = function(session, foldStyle, row) {
+			var line = session.getLine(row);
+
+			if (this.singleLineBlockCommentRe.test(line)) {
+				if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line))
+					return "";
+			}
+
+			var fw = this._getFoldWidgetBase(session, foldStyle, row);
+
+			if (!fw && this.startRegionRe.test(line))
+				return "start"; // lineCommentRegionStart
+
+			return fw;
+		};
+
+		this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) {
+			var line = session.getLine(row);
+
+			if (this.startRegionRe.test(line))
+				return this.getCommentRegionBlock(session, line, row);
+
+			var match = line.match(this.foldingStartMarker);
+			if (match) {
+				var i = match.index;
+
+				if (match[1])
+					return this.openingBracketBlock(session, match[1], row, i);
+
+				var range = session.getCommentFoldRange(row, i + match[0].length, 1);
+
+				if (range && !range.isMultiLine()) {
+					if (forceMultiline) {
+						range = this.getSectionRange(session, row);
+					} else if (foldStyle !== "all")
+						range = null;
+				}
+
+				return range;
+			}
+
+			if (foldStyle === "markbegin")
+				return;
+
+			match = line.match(this.foldingStopMarker);
+			if (match) {
+				var i = match.index + match[0].length;
+
+				if (match[1])
+					return this.closingBracketBlock(session, match[1], row, i);
+
+				return session.getCommentFoldRange(row, i, -1);
+			}
+		};
+
+		this.getSectionRange = function(session, row) {
+			var line = session.getLine(row);
+			var startIndent = line.search(/\S/);
+			var startRow = row;
+			var startColumn = line.length;
+			row = row + 1;
+			var endRow = row;
+			var maxRow = session.getLength();
+			while (++row < maxRow) {
+				line = session.getLine(row);
+				var indent = line.search(/\S/);
+				if (indent === -1)
+					continue;
+				if (startIndent > indent)
+					break;
+				var subRange = this.getFoldWidgetRange(session, "all", row);
+
+				if (subRange) {
+					if (subRange.start.row <= startRow) {
+						break;
+					} else if (subRange.isMultiLine()) {
+						row = subRange.end.row;
+					} else if (startIndent === indent) {
+						break;
+					}
+				}
+				endRow = row;
+			}
+
+			return new Range(startRow, startColumn, endRow, session.getLine(endRow).length);
+		};
+
+		this.getCommentRegionBlock = function(session, line, row) {
+			var startColumn = line.search(/\s*$/);
+			var maxRow = session.getLength();
+			var startRow = row;
+
+			var re = /^\s*(?:\/\*|\/\/)#(end)?region\b/;
+			var depth = 1;
+			while (++row < maxRow) {
+				line = session.getLine(row);
+				var m = re.exec(line);
+				if (!m) continue;
+				if (m[1]) depth--;
+				else depth++;
+
+				if (!depth) break;
+			}
+
+			var endRow = row;
+			if (endRow > startRow) {
+				return new Range(startRow, startColumn, endRow, line.length);
+			}
+		};
+
+	}).call(FoldMode.prototype);
+});

+ 21 - 0
src/web/assets/scripts/mp2-parser-worker.js

@@ -0,0 +1,21 @@
+/*global importScripts, postMessage, mp2*/
+importScripts("mp2-parser.js");
+
+onmessage = function(msg) { //jshint ignore:line
+	var data = msg.data,
+		results;
+	try {
+		results = {
+			id: data.id,
+			parsed: mp2.parse(data.input),
+		};
+	} catch (err) {
+		results = {
+			id: data.id,
+			parsed: {
+				errors: [err],
+			},
+		};
+	}
+	postMessage(results);
+};

+ 4363 - 0
src/web/assets/scripts/mp2-parser.js

@@ -0,0 +1,4363 @@
+mp2 = (function() {
+  /*
+   * Generated by PEG.js 0.8.0.
+   *
+   * http://pegjs.majda.cz/
+   */
+
+  function peg$subclass(child, parent) {
+    function ctor() { this.constructor = child; }
+    ctor.prototype = parent.prototype;
+    child.prototype = new ctor();
+  }
+
+  function SyntaxError(message, expected, found, offset, line, column) {
+    this.message  = message;
+    this.expected = expected;
+    this.found    = found;
+    this.offset   = offset;
+    this.line     = line;
+    this.column   = column;
+
+    this.name     = "SyntaxError";
+  }
+
+  peg$subclass(SyntaxError, Error);
+
+  function parse(input) {
+    var options = arguments.length > 1 ? arguments[1] : {},
+
+        peg$FAILED = {},
+
+        peg$startRuleFunctions = { start: peg$parsestart },
+        peg$startRuleFunction  = peg$parsestart,
+
+        peg$c0 = peg$FAILED,
+        peg$c1 = function() { ast.errors = []; },
+        peg$c2 = void 0,
+        peg$c3 = function(m) {
+            m.errors = ast.errors;
+            return m;
+          },
+        peg$c4 = null,
+        peg$c5 = [],
+        peg$c6 = function(includes, statements) { return new ast.Schema(includes, statements); },
+        peg$c7 = { type: "other", description: "INCLUDE statement" },
+        peg$c8 = function(id) { return new ast.Include(id); },
+        peg$c9 = function(s) { return s },
+        peg$c10 = function(r, id) { ast.ruleId = id.id; },
+        peg$c11 = function(r, id, pl) {
+              var rule = new (r ? ast.RootRule : ast.CompositeRule)(id, pl);
+              if (id.id in ast.rulesById) ast.errors.push(err(20, id.id));
+              ast.rulesById[rule.id.id] = rule;
+              return rule;
+            },
+        peg$c12 = function(list) { return new ast.Sequence(list); },
+        peg$c13 = function(id) {
+              if (id.id === ast.ruleId) ast.errors.push(err(5,id));
+              return id;
+            },
+        peg$c14 = function(item) {return item},
+        peg$c15 = function(item, tail) { return new ast.Alternative([item].concat(tail)); },
+        peg$c16 = function(f) { return new ast.Probability(f); },
+        peg$c17 = function(a, b) { return new ast.MinMax(a !== null ? a[0] : b, b); },
+        peg$c18 = function(s, pl) { return new ast.Iterator(s !== null ? s : new ast.MinMax(0, null), pl); },
+        peg$c19 = function(s, pl) { return new ast.Iterator(s !== null ? s : new ast.MinMax(1, null), pl); },
+        peg$c20 = function(pl) { return new ast.Set(pl); },
+        peg$c21 = function(item) { return item; },
+        peg$c22 = function(item, tail) { return [item].concat(tail); },
+        peg$c23 = function(s, pl) { return new ast.SetIterator(s !== null ? s : new ast.MinMax(0, null), pl); },
+        peg$c24 = function(s, pl) { return new ast.SetIterator(s !== null ? s : new ast.MinMax(1, null), pl); },
+        peg$c25 = function(pl) { return new ast.Optional(pl); },
+        peg$c26 = function(share, on) { return new ast.ShareAll(share, on); },
+        peg$c27 = function(id) {
+              if (!(id.id in ast.rulesById)) ast.errors.push(err(21, id.id)); //TODO: move to errors
+              else if (ast.rulesById[id.id].ruleType !== "RootRule") ast.errors.push(err(22, id.id)); //TODO: move to errors
+              return id;
+            },
+        peg$c28 = function(async, srcs, body) { return new ast.Coordinate(Boolean(async), srcs, body); },
+        peg$c29 = function(item) {
+                ast._srcs = {};
+                ast._srcs[item.id] = 1;
+                return [item];
+              },
+        peg$c30 = function(item) {
+                if (item.id in ast._srcs) ast.errors.push(err(19, item.id));
+                ast._srcs[item.id] = 1;
+                return item;
+              },
+        peg$c31 = function(head, tail) { return head.concat(tail); },
+        peg$c32 = function(item) { return item },
+        peg$c33 = function(v, s, f) {
+              var frm = f ? f[1] : null;
+              if (frm && frm[0] === "$" && !(frm in ast._srcs)) ast.errors.push(err(17, frm));
+              return new ast.CoordinateSource(v, s, frm);
+            },
+        peg$c34 = function(rels) { return new ast.AddOperation(rels); },
+        peg$c35 = function(item) {
+                if (!(item.src in ast._srcs)) ast.errors.push(err(17, item.src));
+                if (!(item.dst in ast._srcs)) ast.errors.push(err(17, item.dst));
+                return [item];
+              },
+        peg$c36 = function(item) {
+                if (!(item.src in ast._srcs)) ast.errors.push(err(17, item.src));
+                if (!(item.dst in ast._srcs)) ast.errors.push(err(17, item.dst));
+                return item;
+              },
+        peg$c37 = function(start, relType, second) { return new ast.Relationship(start, relType, second); },
+        peg$c38 = function(alts) { return new ast.Alternative(alts); },
+        peg$c39 = function(item) {return item;},
+        peg$c40 = { type: "other", description: "SCHEMA identifier" },
+        peg$c41 = "WHEN",
+        peg$c42 = { type: "literal", value: "WHEN", description: "\"WHEN\"" },
+        peg$c43 = "COORDINATE",
+        peg$c44 = { type: "literal", value: "COORDINATE", description: "\"COORDINATE\"" },
+        peg$c45 = "ENSURE",
+        peg$c46 = { type: "literal", value: "ENSURE", description: "\"ENSURE\"" },
+        peg$c47 = "DO",
+        peg$c48 = { type: "literal", value: "DO", description: "\"DO\"" },
+        peg$c49 = "OD",
+        peg$c50 = { type: "literal", value: "OD", description: "\"OD\"" },
+        peg$c51 = "FROM",
+        peg$c52 = { type: "literal", value: "FROM", description: "\"FROM\"" },
+        peg$c53 = { type: "other", description: "ROOT identifier" },
+        peg$c54 = function(id) { return new ast.Event(id); },
+        peg$c55 = { type: "other", description: "EVENT identifier" },
+        peg$c56 = { type: "other", description: "VARIABLE" },
+        peg$c57 = "$",
+        peg$c58 = { type: "literal", value: "$", description: "\"$\"" },
+        peg$c59 = function(id) { return "$" + id; },
+        peg$c60 = /^[A-Za-z]/,
+        peg$c61 = { type: "class", value: "[A-Za-z]", description: "[A-Za-z]" },
+        peg$c62 = /^[a-zA-Z0-9_]/,
+        peg$c63 = { type: "class", value: "[a-zA-Z0-9_]", description: "[a-zA-Z0-9_]" },
+        peg$c64 = function(a, b) { return a + b.join(""); },
+        peg$c65 = /^[0-9]/,
+        peg$c66 = { type: "class", value: "[0-9]", description: "[0-9]" },
+        peg$c67 = function(a) { return a.join(""); },
+        peg$c68 = /^[1-9]/,
+        peg$c69 = { type: "class", value: "[1-9]", description: "[1-9]" },
+        peg$c70 = ".",
+        peg$c71 = { type: "literal", value: ".", description: "\".\"" },
+        peg$c72 = function(a, b) { return parseFloat(b ? a.join("") + "." + b[1].join("") : a.join("")); },
+        peg$c73 = function(b) { return parseFloat("." + b.join("")); },
+        peg$c74 = "(*",
+        peg$c75 = { type: "literal", value: "(*", description: "\"(*\"" },
+        peg$c76 = "*)",
+        peg$c77 = { type: "literal", value: "*)", description: "\"*)\"" },
+        peg$c78 = "(+",
+        peg$c79 = { type: "literal", value: "(+", description: "\"(+\"" },
+        peg$c80 = "+)",
+        peg$c81 = { type: "literal", value: "+)", description: "\"+)\"" },
+        peg$c82 = "{*",
+        peg$c83 = { type: "literal", value: "{*", description: "\"{*\"" },
+        peg$c84 = "*}",
+        peg$c85 = { type: "literal", value: "*}", description: "\"*}\"" },
+        peg$c86 = "{+",
+        peg$c87 = { type: "literal", value: "{+", description: "\"{+\"" },
+        peg$c88 = "+}",
+        peg$c89 = { type: "literal", value: "+}", description: "\"+}\"" },
+        peg$c90 = "<!>",
+        peg$c91 = { type: "literal", value: "<!>", description: "\"<!>\"" },
+        peg$c92 = "|+|",
+        peg$c93 = { type: "literal", value: "|+|", description: "\"|+|\"" },
+        peg$c94 = "..",
+        peg$c95 = { type: "literal", value: "..", description: "\"..\"" },
+        peg$c96 = "(",
+        peg$c97 = { type: "literal", value: "(", description: "\"(\"" },
+        peg$c98 = ")",
+        peg$c99 = { type: "literal", value: ")", description: "\")\"" },
+        peg$c100 = "{",
+        peg$c101 = { type: "literal", value: "{", description: "\"{\"" },
+        peg$c102 = "}",
+        peg$c103 = { type: "literal", value: "}", description: "\"}\"" },
+        peg$c104 = "[",
+        peg$c105 = { type: "literal", value: "[", description: "\"[\"" },
+        peg$c106 = "]",
+        peg$c107 = { type: "literal", value: "]", description: "\"]\"" },
+        peg$c108 = "<",
+        peg$c109 = { type: "literal", value: "<", description: "\"<\"" },
+        peg$c110 = ">",
+        peg$c111 = { type: "literal", value: ">", description: "\">\"" },
+        peg$c112 = "<<",
+        peg$c113 = { type: "literal", value: "<<", description: "\"<<\"" },
+        peg$c114 = ">>",
+        peg$c115 = { type: "literal", value: ">>", description: "\">>\"" },
+        peg$c116 = ":",
+        peg$c117 = { type: "literal", value: ":", description: "\":\"" },
+        peg$c118 = ";",
+        peg$c119 = { type: "literal", value: ";", description: "\";\"" },
+        peg$c120 = ",",
+        peg$c121 = { type: "literal", value: ",", description: "\",\"" },
+        peg$c122 = "|",
+        peg$c123 = { type: "literal", value: "|", description: "\"|\"" },
+        peg$c124 = "SCHEMA",
+        peg$c125 = { type: "literal", value: "SCHEMA", description: "\"SCHEMA\"" },
+        peg$c126 = "INCLUDE",
+        peg$c127 = { type: "literal", value: "INCLUDE", description: "\"INCLUDE\"" },
+        peg$c128 = "ROOT",
+        peg$c129 = { type: "literal", value: "ROOT", description: "\"ROOT\"" },
+        peg$c130 = "SHARE",
+        peg$c131 = { type: "literal", value: "SHARE", description: "\"SHARE\"" },
+        peg$c132 = "ALL",
+        peg$c133 = { type: "literal", value: "ALL", description: "\"ALL\"" },
+        peg$c134 = "ADD",
+        peg$c135 = { type: "literal", value: "ADD", description: "\"ADD\"" },
+        peg$c136 = "IN",
+        peg$c137 = { type: "literal", value: "IN", description: "\"IN\"" },
+        peg$c138 = function() { return "IN"; },
+        peg$c139 = "CONTAINS",
+        peg$c140 = { type: "literal", value: "CONTAINS", description: "\"CONTAINS\"" },
+        peg$c141 = function() { return "CONTAINS"; },
+        peg$c142 = "PRECEDES",
+        peg$c143 = { type: "literal", value: "PRECEDES", description: "\"PRECEDES\"" },
+        peg$c144 = function() { return "PRECEDES"; },
+        peg$c145 = "FOLLOWS",
+        peg$c146 = { type: "literal", value: "FOLLOWS", description: "\"FOLLOWS\"" },
+        peg$c147 = function() { return "FOLLOWS"; },
+        peg$c148 = "this",
+        peg$c149 = { type: "literal", value: "this", description: "\"this\"" },
+        peg$c150 = function() { return "this"; },
+        peg$c151 = "BUILD",
+        peg$c152 = { type: "literal", value: "BUILD", description: "\"BUILD\"" },
+        peg$c153 = "NEW",
+        peg$c154 = { type: "literal", value: "NEW", description: "\"NEW\"" },
+        peg$c155 = "MAP",
+        peg$c156 = { type: "literal", value: "MAP", description: "\"MAP\"" },
+        peg$c157 = { type: "any", description: "any character" },
+        peg$c158 = { type: "other", description: "optional whitespace" },
+        peg$c159 = /^[ \t\n\r]/,
+        peg$c160 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
+        peg$c161 = function() { return null; },
+        peg$c162 = { type: "other", description: "required whitespace" },
+        peg$c163 = { type: "other", description: "newline" },
+        peg$c164 = /^[\n]/,
+        peg$c165 = { type: "class", value: "[\\n]", description: "[\\n]" },
+        peg$c166 = function(c) { return c },
+        peg$c167 = { type: "other", description: "comment line" },
+        peg$c168 = "//",
+        peg$c169 = { type: "literal", value: "//", description: "\"//\"" },
+        peg$c170 = /^[^\n]/,
+        peg$c171 = { type: "class", value: "[^\\n]", description: "[^\\n]" },
+        peg$c172 = function(c) { return new ast.Comment(false, c.join("")); },
+        peg$c173 = { type: "other", description: "comment block" },
+        peg$c174 = "/*",
+        peg$c175 = { type: "literal", value: "/*", description: "\"/*\"" },
+        peg$c176 = "*/",
+        peg$c177 = { type: "literal", value: "*/", description: "\"*/\"" },
+        peg$c178 = function(c) { return new ast.Comment(true, c.join("")); },
+        peg$c179 = function(c) { return c; },
+
+        peg$currPos          = 0,
+        peg$reportedPos      = 0,
+        peg$cachedPos        = 0,
+        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
+        peg$maxFailPos       = 0,
+        peg$maxFailExpected  = [],
+        peg$silentFails      = 0,
+
+        peg$result;
+
+    if ("startRule" in options) {
+      if (!(options.startRule in peg$startRuleFunctions)) {
+        throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
+      }
+
+      peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+    }
+
+    function text() {
+      return input.substring(peg$reportedPos, peg$currPos);
+    }
+
+    function offset() {
+      return peg$reportedPos;
+    }
+
+    function line() {
+      return peg$computePosDetails(peg$reportedPos).line;
+    }
+
+    function column() {
+      return peg$computePosDetails(peg$reportedPos).column;
+    }
+
+    function expected(description) {
+      throw peg$buildException(
+        null,
+        [{ type: "other", description: description }],
+        peg$reportedPos
+      );
+    }
+
+    function error(message) {
+      throw peg$buildException(message, null, peg$reportedPos);
+    }
+
+    function peg$computePosDetails(pos) {
+      function advance(details, startPos, endPos) {
+        var p, ch;
+
+        for (p = startPos; p < endPos; p++) {
+          ch = input.charAt(p);
+          if (ch === "\n") {
+            if (!details.seenCR) { details.line++; }
+            details.column = 1;
+            details.seenCR = false;
+          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+            details.line++;
+            details.column = 1;
+            details.seenCR = true;
+          } else {
+            details.column++;
+            details.seenCR = false;
+          }
+        }
+      }
+
+      if (peg$cachedPos !== pos) {
+        if (peg$cachedPos > pos) {
+          peg$cachedPos = 0;
+          peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
+        }
+        advance(peg$cachedPosDetails, peg$cachedPos, pos);
+        peg$cachedPos = pos;
+      }
+
+      return peg$cachedPosDetails;
+    }
+
+    function peg$fail(expected) {
+      if (peg$currPos < peg$maxFailPos) { return; }
+
+      if (peg$currPos > peg$maxFailPos) {
+        peg$maxFailPos = peg$currPos;
+        peg$maxFailExpected = [];
+      }
+
+      peg$maxFailExpected.push(expected);
+    }
+
+    function peg$buildException(message, expected, pos) {
+      function cleanupExpected(expected) {
+        var i = 1;
+
+        expected.sort(function(a, b) {
+          if (a.description < b.description) {
+            return -1;
+          } else if (a.description > b.description) {
+            return 1;
+          } else {
+            return 0;
+          }
+        });
+
+        while (i < expected.length) {
+          if (expected[i - 1] === expected[i]) {
+            expected.splice(i, 1);
+          } else {
+            i++;
+          }
+        }
+      }
+
+      function buildMessage(expected, found) {
+        function stringEscape(s) {
+          function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
+
+          return s
+            .replace(/\\/g,   '\\\\')
+            .replace(/"/g,    '\\"')
+            .replace(/\x08/g, '\\b')
+            .replace(/\t/g,   '\\t')
+            .replace(/\n/g,   '\\n')
+            .replace(/\f/g,   '\\f')
+            .replace(/\r/g,   '\\r')
+            .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
+            .replace(/[\x10-\x1F\x80-\xFF]/g,    function(ch) { return '\\x'  + hex(ch); })
+            .replace(/[\u0180-\u0FFF]/g,         function(ch) { return '\\u0' + hex(ch); })
+            .replace(/[\u1080-\uFFFF]/g,         function(ch) { return '\\u'  + hex(ch); });
+        }
+
+        var expectedDescs = new Array(expected.length),
+            expectedDesc, foundDesc, i;
+
+        for (i = 0; i < expected.length; i++) {
+          expectedDescs[i] = expected[i].description;
+        }
+
+        expectedDesc = expected.length > 1
+          ? expectedDescs.slice(0, -1).join(", ")
+              + " or "
+              + expectedDescs[expected.length - 1]
+          : expectedDescs[0];
+
+        foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
+
+        return "Expected " + expectedDesc + " but " + foundDesc + " found.";
+      }
+
+      var posDetails = peg$computePosDetails(pos),
+          found      = pos < input.length ? input.charAt(pos) : null;
+
+      if (expected !== null) {
+        cleanupExpected(expected);
+      }
+
+      return new SyntaxError(
+        message !== null ? message : buildMessage(expected, found),
+        expected,
+        found,
+        pos,
+        posDetails.line,
+        posDetails.column
+      );
+    }
+
+    function peg$parsestart() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      peg$reportedPos = peg$currPos;
+      s1 = peg$c1();
+      if (s1) {
+        s1 = peg$c0;
+      } else {
+        s1 = peg$c2;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseschema();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c3(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseschema() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      s2 = peg$parseSCHEMA();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parseschema_id();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parsesemi();
+          if (s4 === peg$FAILED) {
+            s4 = peg$c4;
+          }
+          if (s4 !== peg$FAILED) {
+            s2 = [s2, s3, s4];
+            s1 = s2;
+          } else {
+            peg$currPos = s1;
+            s1 = peg$c0;
+          }
+        } else {
+          peg$currPos = s1;
+          s1 = peg$c0;
+        }
+      } else {
+        peg$currPos = s1;
+        s1 = peg$c0;
+      }
+      if (s1 === peg$FAILED) {
+        s1 = peg$c4;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$parseschema_include();
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$parseschema_include();
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = [];
+          s4 = peg$parseschema_statement();
+          while (s4 !== peg$FAILED) {
+            s3.push(s4);
+            s4 = peg$parseschema_statement();
+          }
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseEOF();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c6(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseschema_include() {
+      var s0, s1, s2, s3;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      s1 = peg$parseINCLUDE();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseschema_id();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsesemi();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c8(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c7); }
+      }
+
+      return s0;
+    }
+
+    function peg$parseschema_statement() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = peg$parserule();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parsecomposition_operation();
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsesemi();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c9(s1);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parserule() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parseROOT();
+      if (s1 === peg$FAILED) {
+        s1 = peg$c4;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseroot_id();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = peg$currPos;
+          s3 = peg$c10(s1, s2);
+          if (s3) {
+            s3 = peg$c0;
+          } else {
+            s3 = peg$c2;
+          }
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parsecolon();
+            if (s4 !== peg$FAILED) {
+              s5 = peg$parsepattern_list();
+              if (s5 === peg$FAILED) {
+                s5 = peg$c4;
+              }
+              if (s5 !== peg$FAILED) {
+                peg$reportedPos = s0;
+                s1 = peg$c11(s1, s2, s5);
+                s0 = s1;
+              } else {
+                peg$currPos = s0;
+                s0 = peg$c0;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsepattern_list() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = [];
+      s2 = peg$parsepattern_unit();
+      if (s2 !== peg$FAILED) {
+        while (s2 !== peg$FAILED) {
+          s1.push(s2);
+          s2 = peg$parsepattern_unit();
+        }
+      } else {
+        s1 = peg$c0;
+      }
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = s0;
+        s1 = peg$c12(s1);
+      }
+      s0 = s1;
+
+      return s0;
+    }
+
+    function peg$parsepattern_unit() {
+      var s0, s1;
+
+      s0 = peg$currPos;
+      s1 = peg$parseevent_id();
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = s0;
+        s1 = peg$c13(s1);
+      }
+      s0 = s1;
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsealternative();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseiterator();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parseiterator_plus();
+            if (s0 === peg$FAILED) {
+              s0 = peg$parseset();
+              if (s0 === peg$FAILED) {
+                s0 = peg$parseset_iterator();
+                if (s0 === peg$FAILED) {
+                  s0 = peg$parseset_iterator_plus();
+                  if (s0 === peg$FAILED) {
+                    s0 = peg$parseoptional();
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      return s0;
+    }
+
+    function peg$parsealternative() {
+      var s0, s1, s2, s3, s4, s5, s6;
+
+      s0 = peg$currPos;
+      s1 = peg$parseparenL();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsepattern_list();
+        if (s2 !== peg$FAILED) {
+          s3 = [];
+          s4 = peg$currPos;
+          s5 = peg$parsepipe();
+          if (s5 !== peg$FAILED) {
+            s6 = peg$parsepattern_list();
+            if (s6 !== peg$FAILED) {
+              peg$reportedPos = s4;
+              s5 = peg$c14(s6);
+              s4 = s5;
+            } else {
+              peg$currPos = s4;
+              s4 = peg$c0;
+            }
+          } else {
+            peg$currPos = s4;
+            s4 = peg$c0;
+          }
+          while (s4 !== peg$FAILED) {
+            s3.push(s4);
+            s4 = peg$currPos;
+            s5 = peg$parsepipe();
+            if (s5 !== peg$FAILED) {
+              s6 = peg$parsepattern_list();
+              if (s6 !== peg$FAILED) {
+                peg$reportedPos = s4;
+                s5 = peg$c14(s6);
+                s4 = s5;
+              } else {
+                peg$currPos = s4;
+                s4 = peg$c0;
+              }
+            } else {
+              peg$currPos = s4;
+              s4 = peg$c0;
+            }
+          }
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseparenR();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c15(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseprobability() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parseltlt();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsefloat();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsegtgt();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c16(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseiterator_scope_any() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parselt();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$currPos;
+        s3 = peg$parseinteger();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parseto();
+          if (s4 !== peg$FAILED) {
+            s3 = [s3, s4];
+            s2 = s3;
+          } else {
+            peg$currPos = s2;
+            s2 = peg$c0;
+          }
+        } else {
+          peg$currPos = s2;
+          s2 = peg$c0;
+        }
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseinteger();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parsegt();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c17(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseiterator_scope_some() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parselt();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$currPos;
+        s3 = peg$parseinteger_gt0();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parseto();
+          if (s4 !== peg$FAILED) {
+            s3 = [s3, s4];
+            s2 = s3;
+          } else {
+            peg$currPos = s2;
+            s2 = peg$c0;
+          }
+        } else {
+          peg$currPos = s2;
+          s2 = peg$c0;
+        }
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseinteger_gt0();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parsegt();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c17(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseiterator() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebegin_iter();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseiterator_scope_any();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsepattern_list();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseend_iter();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c18(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseiterator_plus() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebegin_itpl();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseiterator_scope_some();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsepattern_list();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseend_itpl();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c19(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseset() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebraceL();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsepattern_lists_by_comma();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsebraceR();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c20(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsepattern_lists_by_comma() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parsepattern_list();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsecomma();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parsepattern_list();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c21(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsecomma();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parsepattern_list();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c21(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c22(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseset_iterator() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebegin_seti();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseiterator_scope_any();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsepattern_list();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseend_seti();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c23(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseset_iterator_plus() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebegin_setp();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseiterator_scope_some();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsepattern_list();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseend_setp();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c24(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseoptional() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parsebracketL();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsepattern_list();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsebracketR();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c25(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomposition_operation() {
+      var s0;
+
+      s0 = peg$parseshared_composition();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsecoordinate_composition();
+      }
+
+      return s0;
+    }
+
+    function peg$parseshared_composition() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parseroot_or_var_by_exunionstr_by_comma();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseSHARE_ALL();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseevent_id_by_comma();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c26(s1, s3);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseroot_or_var() {
+      var s0, s1;
+
+      s0 = peg$currPos;
+      s1 = peg$parseroot_id();
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = s0;
+        s1 = peg$c27(s1);
+      }
+      s0 = s1;
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsevariable();
+      }
+
+      return s0;
+    }
+
+    function peg$parseroot_or_var_by_exunionstr() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parseroot_or_var();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parseexunionstr();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parseroot_or_var();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c21(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parseexunionstr();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parseroot_or_var();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c21(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c22(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseroot_or_var_by_exunionstr_by_comma() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parseroot_or_var_by_exunionstr();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsecomma();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parseroot_or_var_by_exunionstr();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c21(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsecomma();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parseroot_or_var_by_exunionstr();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c21(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c22(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseevent_id_by_comma() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parseevent_id();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsecomma();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parseevent_id();
+          if (s5 !== peg$FAILED) {
+            s4 = [s4, s5];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsecomma();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parseevent_id();
+            if (s5 !== peg$FAILED) {
+              s4 = [s4, s5];
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c22(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecoordinate_composition() {
+      var s0, s1, s2, s3, s4, s5, s6;
+
+      s0 = peg$currPos;
+      s1 = peg$parseCOORDINATE();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseasyncstr();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsecoordination_source_by_comma();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parseDO();
+            if (s4 !== peg$FAILED) {
+              s5 = [];
+              s6 = peg$parsedo_body_statement();
+              if (s6 !== peg$FAILED) {
+                while (s6 !== peg$FAILED) {
+                  s5.push(s6);
+                  s6 = peg$parsedo_body_statement();
+                }
+              } else {
+                s5 = peg$c0;
+              }
+              if (s5 !== peg$FAILED) {
+                s6 = peg$parseOD();
+                if (s6 !== peg$FAILED) {
+                  peg$reportedPos = s0;
+                  s1 = peg$c28(s2, s3, s5);
+                  s0 = s1;
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$c0;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$c0;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecoordination_source_by_comma() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      s2 = peg$parsecoordination_source();
+      if (s2 !== peg$FAILED) {
+        peg$reportedPos = s1;
+        s2 = peg$c29(s2);
+      }
+      s1 = s2;
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsecomma();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parsecoordination_source();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c30(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsecomma();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parsecoordination_source();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c30(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c31(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsedo_body_statement() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = peg$parseadd_relation();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseshared_composition();
+        if (s1 === peg$FAILED) {
+          s1 = peg$parsecoordinate_composition();
+        }
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsesemi();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c32(s1);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecoordination_source() {
+      var s0, s1, s2, s3, s4, s5, s6;
+
+      s0 = peg$currPos;
+      s1 = peg$parsevariable();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsecolon();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseselection_pattern();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$currPos;
+            s5 = peg$parseFROM();
+            if (s5 !== peg$FAILED) {
+              s6 = peg$parseTHIS();
+              if (s6 === peg$FAILED) {
+                s6 = peg$parseroot_or_var();
+              }
+              if (s6 !== peg$FAILED) {
+                s5 = [s5, s6];
+                s4 = s5;
+              } else {
+                peg$currPos = s4;
+                s4 = peg$c0;
+              }
+            } else {
+              peg$currPos = s4;
+              s4 = peg$c0;
+            }
+            if (s4 === peg$FAILED) {
+              s4 = peg$c4;
+            }
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c33(s1, s3, s4);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseadd_relation() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = peg$parseADD();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parserelationships_by_comma();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c34(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parserelationships_by_comma() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      s2 = peg$parserelationship();
+      if (s2 !== peg$FAILED) {
+        peg$reportedPos = s1;
+        s2 = peg$c35(s2);
+      }
+      s1 = s2;
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsecomma();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parserelationship();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c36(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsecomma();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parserelationship();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c36(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c31(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parserelationship() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parsevariable();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseIN();
+        if (s2 === peg$FAILED) {
+          s2 = peg$parsePRECEDES();
+          if (s2 === peg$FAILED) {
+            s2 = peg$parseCONTAINS();
+            if (s2 === peg$FAILED) {
+              s2 = peg$parseFOLLOWS();
+            }
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parsevariable();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c37(s1, s2, s3);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseselection_pattern() {
+      var s0;
+
+      s0 = peg$parseevent_id();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsealternative_of_event_names();
+      }
+
+      return s0;
+    }
+
+    function peg$parsealternative_of_event_names() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parseparenL();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseevent_id_by_pipe();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseparenR();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c38(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseevent_id_by_pipe() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parseevent_id();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parsepipe();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parseevent_id();
+          if (s5 !== peg$FAILED) {
+            peg$reportedPos = s3;
+            s4 = peg$c39(s5);
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$c0;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parsepipe();
+          if (s4 !== peg$FAILED) {
+            s5 = peg$parseevent_id();
+            if (s5 !== peg$FAILED) {
+              peg$reportedPos = s3;
+              s4 = peg$c39(s5);
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c22(s1, s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseschema_id() {
+      var s0, s1;
+
+      peg$silentFails++;
+      s0 = peg$parseid();
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c40); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsekeyword() {
+      var s0;
+
+      if (input.substr(peg$currPos, 4) === peg$c41) {
+        s0 = peg$c41;
+        peg$currPos += 4;
+      } else {
+        s0 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c42); }
+      }
+      if (s0 === peg$FAILED) {
+        if (input.substr(peg$currPos, 10) === peg$c43) {
+          s0 = peg$c43;
+          peg$currPos += 10;
+        } else {
+          s0 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c44); }
+        }
+        if (s0 === peg$FAILED) {
+          if (input.substr(peg$currPos, 6) === peg$c45) {
+            s0 = peg$c45;
+            peg$currPos += 6;
+          } else {
+            s0 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c46); }
+          }
+          if (s0 === peg$FAILED) {
+            if (input.substr(peg$currPos, 2) === peg$c47) {
+              s0 = peg$c47;
+              peg$currPos += 2;
+            } else {
+              s0 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c48); }
+            }
+            if (s0 === peg$FAILED) {
+              if (input.substr(peg$currPos, 2) === peg$c49) {
+                s0 = peg$c49;
+                peg$currPos += 2;
+              } else {
+                s0 = peg$FAILED;
+                if (peg$silentFails === 0) { peg$fail(peg$c50); }
+              }
+              if (s0 === peg$FAILED) {
+                if (input.substr(peg$currPos, 4) === peg$c51) {
+                  s0 = peg$c51;
+                  peg$currPos += 4;
+                } else {
+                  s0 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$c52); }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      return s0;
+    }
+
+    function peg$parseroot_id() {
+      var s0, s1, s2;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      peg$silentFails++;
+      s2 = peg$parsekeyword();
+      peg$silentFails--;
+      if (s2 === peg$FAILED) {
+        s1 = peg$c2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$c0;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseid();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c54(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c53); }
+      }
+
+      return s0;
+    }
+
+    function peg$parseevent_id() {
+      var s0, s1, s2;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      peg$silentFails++;
+      s2 = peg$parsekeyword();
+      peg$silentFails--;
+      if (s2 === peg$FAILED) {
+        s1 = peg$c2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$c0;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parseid();
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c54(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c55); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsevariable() {
+      var s0, s1, s2, s3, s4;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 36) {
+          s2 = peg$c57;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c58); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parseid();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse_();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c59(s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c56); }
+      }
+
+      return s0;
+    }
+
+    function peg$parseid() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (peg$c60.test(input.charAt(peg$currPos))) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c61); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = [];
+          if (peg$c62.test(input.charAt(peg$currPos))) {
+            s4 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s4 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c63); }
+          }
+          while (s4 !== peg$FAILED) {
+            s3.push(s4);
+            if (peg$c62.test(input.charAt(peg$currPos))) {
+              s4 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s4 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c63); }
+            }
+          }
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse_();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c64(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseinteger() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        if (peg$c65.test(input.charAt(peg$currPos))) {
+          s3 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c66); }
+        }
+        if (s3 !== peg$FAILED) {
+          while (s3 !== peg$FAILED) {
+            s2.push(s3);
+            if (peg$c65.test(input.charAt(peg$currPos))) {
+              s3 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s3 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c66); }
+            }
+          }
+        } else {
+          s2 = peg$c0;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c67(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseinteger_gt0() {
+      var s0, s1, s2, s3, s4;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (peg$c68.test(input.charAt(peg$currPos))) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c69); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = [];
+          if (peg$c65.test(input.charAt(peg$currPos))) {
+            s4 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s4 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c66); }
+          }
+          while (s4 !== peg$FAILED) {
+            s3.push(s4);
+            if (peg$c65.test(input.charAt(peg$currPos))) {
+              s4 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s4 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c66); }
+            }
+          }
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse_();
+            if (s4 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c64(s2, s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsefloat() {
+      var s0, s1, s2, s3, s4, s5, s6;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        if (peg$c65.test(input.charAt(peg$currPos))) {
+          s3 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c66); }
+        }
+        if (s3 !== peg$FAILED) {
+          while (s3 !== peg$FAILED) {
+            s2.push(s3);
+            if (peg$c65.test(input.charAt(peg$currPos))) {
+              s3 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s3 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c66); }
+            }
+          }
+        } else {
+          s2 = peg$c0;
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$currPos;
+          if (input.charCodeAt(peg$currPos) === 46) {
+            s4 = peg$c70;
+            peg$currPos++;
+          } else {
+            s4 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c71); }
+          }
+          if (s4 !== peg$FAILED) {
+            s5 = [];
+            if (peg$c65.test(input.charAt(peg$currPos))) {
+              s6 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s6 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c66); }
+            }
+            if (s6 !== peg$FAILED) {
+              while (s6 !== peg$FAILED) {
+                s5.push(s6);
+                if (peg$c65.test(input.charAt(peg$currPos))) {
+                  s6 = input.charAt(peg$currPos);
+                  peg$currPos++;
+                } else {
+                  s6 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$c66); }
+                }
+              }
+            } else {
+              s5 = peg$c0;
+            }
+            if (s5 !== peg$FAILED) {
+              s4 = [s4, s5];
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$c0;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$c0;
+          }
+          if (s3 === peg$FAILED) {
+            s3 = peg$c4;
+          }
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c72(s2, s3);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parse_();
+        if (s1 !== peg$FAILED) {
+          if (input.charCodeAt(peg$currPos) === 46) {
+            s2 = peg$c70;
+            peg$currPos++;
+          } else {
+            s2 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c71); }
+          }
+          if (s2 !== peg$FAILED) {
+            s3 = [];
+            if (peg$c65.test(input.charAt(peg$currPos))) {
+              s4 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s4 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c66); }
+            }
+            if (s4 !== peg$FAILED) {
+              while (s4 !== peg$FAILED) {
+                s3.push(s4);
+                if (peg$c65.test(input.charAt(peg$currPos))) {
+                  s4 = input.charAt(peg$currPos);
+                  peg$currPos++;
+                } else {
+                  s4 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$c66); }
+                }
+              }
+            } else {
+              s3 = peg$c0;
+            }
+            if (s3 !== peg$FAILED) {
+              peg$reportedPos = s0;
+              s1 = peg$c73(s3);
+              s0 = s1;
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      }
+
+      return s0;
+    }
+
+    function peg$parsebegin_iter() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c74) {
+          s2 = peg$c74;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c75); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseend_iter() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c76) {
+          s2 = peg$c76;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c77); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebegin_itpl() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c78) {
+          s2 = peg$c78;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c79); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseend_itpl() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c80) {
+          s2 = peg$c80;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c81); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebegin_seti() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c82) {
+          s2 = peg$c82;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c83); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseend_seti() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c84) {
+          s2 = peg$c84;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c85); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebegin_setp() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c86) {
+          s2 = peg$c86;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c87); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseend_setp() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c88) {
+          s2 = peg$c88;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c89); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseasyncstr() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 3) === peg$c90) {
+          s2 = peg$c90;
+          peg$currPos += 3;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c91); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseexunionstr() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 3) === peg$c92) {
+          s2 = peg$c92;
+          peg$currPos += 3;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c93); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseto() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c94) {
+          s2 = peg$c94;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c95); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseparenL() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 40) {
+          s2 = peg$c96;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c97); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseparenR() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 41) {
+          s2 = peg$c98;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c99); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebraceL() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 123) {
+          s2 = peg$c100;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c101); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebraceR() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 125) {
+          s2 = peg$c102;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c103); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebracketL() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 91) {
+          s2 = peg$c104;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c105); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsebracketR() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 93) {
+          s2 = peg$c106;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c107); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parselt() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 60) {
+          s2 = peg$c108;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c109); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsegt() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 62) {
+          s2 = peg$c110;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c111); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseltlt() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c112) {
+          s2 = peg$c112;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c113); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsegtgt() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c114) {
+          s2 = peg$c114;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c115); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecolon() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 58) {
+          s2 = peg$c116;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c117); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsesemi() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 59) {
+          s2 = peg$c118;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c119); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomma() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 44) {
+          s2 = peg$c120;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c121); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsepipe() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 124) {
+          s2 = peg$c122;
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c123); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseSCHEMA() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 6) === peg$c124) {
+          s2 = peg$c124;
+          peg$currPos += 6;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c125); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseINCLUDE() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 7) === peg$c126) {
+          s2 = peg$c126;
+          peg$currPos += 7;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c127); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseROOT() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 4) === peg$c128) {
+          s2 = peg$c128;
+          peg$currPos += 4;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c129); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseSHARE_ALL() {
+      var s0, s1, s2, s3, s4, s5;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 5) === peg$c130) {
+          s2 = peg$c130;
+          peg$currPos += 5;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c131); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            if (input.substr(peg$currPos, 3) === peg$c132) {
+              s4 = peg$c132;
+              peg$currPos += 3;
+            } else {
+              s4 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$c133); }
+            }
+            if (s4 !== peg$FAILED) {
+              s5 = peg$parse__();
+              if (s5 !== peg$FAILED) {
+                s1 = [s1, s2, s3, s4, s5];
+                s0 = s1;
+              } else {
+                peg$currPos = s0;
+                s0 = peg$c0;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$c0;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseCOORDINATE() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 10) === peg$c43) {
+          s2 = peg$c43;
+          peg$currPos += 10;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c44); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseFROM() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 4) === peg$c51) {
+          s2 = peg$c51;
+          peg$currPos += 4;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c52); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseADD() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 3) === peg$c134) {
+          s2 = peg$c134;
+          peg$currPos += 3;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c135); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseIN() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c136) {
+          s2 = peg$c136;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c137); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c138();
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseCONTAINS() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 8) === peg$c139) {
+          s2 = peg$c139;
+          peg$currPos += 8;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c140); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c141();
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parsePRECEDES() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 8) === peg$c142) {
+          s2 = peg$c142;
+          peg$currPos += 8;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c143); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c144();
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseFOLLOWS() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 7) === peg$c145) {
+          s2 = peg$c145;
+          peg$currPos += 7;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c146); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c147();
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseTHIS() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 4) === peg$c148) {
+          s2 = peg$c148;
+          peg$currPos += 4;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c149); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c150();
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseDO() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c47) {
+          s2 = peg$c47;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c48); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseOD() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c49) {
+          s2 = peg$c49;
+          peg$currPos += 2;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c50); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseBUILD() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 5) === peg$c151) {
+          s2 = peg$c151;
+          peg$currPos += 5;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c152); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseNEW() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 3) === peg$c153) {
+          s2 = peg$c153;
+          peg$currPos += 3;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c154); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseMAP() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 3) === peg$c155) {
+          s2 = peg$c155;
+          peg$currPos += 3;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c156); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseENSURE() {
+      var s0, s1, s2, s3;
+
+      s0 = peg$currPos;
+      s1 = peg$parse_();
+      if (s1 !== peg$FAILED) {
+        if (input.substr(peg$currPos, 6) === peg$c45) {
+          s2 = peg$c45;
+          peg$currPos += 6;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c46); }
+        }
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse_();
+          if (s3 !== peg$FAILED) {
+            s1 = [s1, s2, s3];
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parseEOF() {
+      var s0, s1;
+
+      s0 = peg$currPos;
+      peg$silentFails++;
+      if (input.length > peg$currPos) {
+        s1 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c157); }
+      }
+      peg$silentFails--;
+      if (s1 === peg$FAILED) {
+        s0 = peg$c2;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+    function peg$parse_() {
+      var s0, s1, s2;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      s1 = [];
+      if (peg$c159.test(input.charAt(peg$currPos))) {
+        s2 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s2 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c160); }
+      }
+      if (s2 === peg$FAILED) {
+        s2 = peg$parsecomment();
+      }
+      while (s2 !== peg$FAILED) {
+        s1.push(s2);
+        if (peg$c159.test(input.charAt(peg$currPos))) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c160); }
+        }
+        if (s2 === peg$FAILED) {
+          s2 = peg$parsecomment();
+        }
+      }
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = s0;
+        s1 = peg$c161();
+      }
+      s0 = s1;
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c158); }
+      }
+
+      return s0;
+    }
+
+    function peg$parse__() {
+      var s0, s1, s2;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      if (peg$c159.test(input.charAt(peg$currPos))) {
+        s1 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c160); }
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse_();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c161();
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c162); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsenl() {
+      var s0, s1;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      if (peg$c164.test(input.charAt(peg$currPos))) {
+        s1 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c165); }
+      }
+      if (s1 !== peg$FAILED) {
+        peg$reportedPos = s0;
+        s1 = peg$c161();
+      }
+      s0 = s1;
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c163); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomment() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = peg$parsecomment_line();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsenl();
+        if (s2 === peg$FAILED) {
+          s2 = peg$c4;
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c166(s1);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parsecomment_block();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parsenl();
+          if (s2 === peg$FAILED) {
+            s2 = peg$c4;
+          }
+          if (s2 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c166(s1);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomment_line() {
+      var s0, s1, s2, s3;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      if (input.substr(peg$currPos, 2) === peg$c168) {
+        s1 = peg$c168;
+        peg$currPos += 2;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c169); }
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        if (peg$c170.test(input.charAt(peg$currPos))) {
+          s3 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c171); }
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          if (peg$c170.test(input.charAt(peg$currPos))) {
+            s3 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s3 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c171); }
+          }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c172(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c167); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomment_block() {
+      var s0, s1, s2, s3;
+
+      peg$silentFails++;
+      s0 = peg$currPos;
+      if (input.substr(peg$currPos, 2) === peg$c174) {
+        s1 = peg$c174;
+        peg$currPos += 2;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c175); }
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$parsecomment_block_char();
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$parsecomment_block_char();
+        }
+        if (s2 !== peg$FAILED) {
+          if (input.substr(peg$currPos, 2) === peg$c176) {
+            s3 = peg$c176;
+            peg$currPos += 2;
+          } else {
+            s3 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$c177); }
+          }
+          if (s3 !== peg$FAILED) {
+            peg$reportedPos = s0;
+            s1 = peg$c178(s2);
+            s0 = s1;
+          } else {
+            peg$currPos = s0;
+            s0 = peg$c0;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+      peg$silentFails--;
+      if (s0 === peg$FAILED) {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c173); }
+      }
+
+      return s0;
+    }
+
+    function peg$parsecomment_block_char() {
+      var s0, s1, s2;
+
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      peg$silentFails++;
+      if (input.substr(peg$currPos, 2) === peg$c176) {
+        s2 = peg$c176;
+        peg$currPos += 2;
+      } else {
+        s2 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$c177); }
+      }
+      peg$silentFails--;
+      if (s2 === peg$FAILED) {
+        s1 = peg$c2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$c0;
+      }
+      if (s1 !== peg$FAILED) {
+        if (input.length > peg$currPos) {
+          s2 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s2 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$c157); }
+        }
+        if (s2 !== peg$FAILED) {
+          peg$reportedPos = s0;
+          s1 = peg$c179(s2);
+          s0 = s1;
+        } else {
+          peg$currPos = s0;
+          s0 = peg$c0;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$c0;
+      }
+
+      return s0;
+    }
+
+
+      /*global parse, options, offset, line, column, text, SyntaxError*/
+      //TODO: the 'MP2-parser.rig' takes a scope and bakes it into the output we will do that elsewhere
+      //TODO: the 'MP2-parser.rig' checks for various error scenarios that we might bake into this
+      //TODO: when we get to bool_expr might look into using the `ast-types` npm to make any code generation easier (escodegen)
+      var opts = arguments[2] || options,
+        fileName = opts.fileName || "NOFILENAME",
+        locations = opts.locations !== undefined ? opts.locations : false,
+        comments = opts.comments !== undefined ? opts.comments : false;
+
+      var uniqueNumber = 0,
+        getUniqueNumber = function getUniqueNumber() {
+          return uniqueNumber++;
+        };
+
+      var err = function err(msg, suffix) {
+          if (typeof msg === "number") msg = "ERR" + msg + ": " + errors[msg];
+          if (suffix) msg += suffix;
+          return new SyntaxError(msg, null, null, offset(), line(), column());
+      };
+
+      var ast = {
+
+        errors: [], // tracks all of the non-grammatical errors
+
+        rulesById: {}, // track all of the rules by their ID
+
+        Base: function Base(type) {
+          this.type = type;
+          if (locations) {
+            this.location = {
+              pos: offset(),
+              line: line(),
+              col: column(),
+              len: text().length,
+            };
+          }
+          if (comments && type !== "Comment") {
+            //TODO: not attached in right place
+             this.comments = ast._comments;
+             ast._comments = [];
+          }
+        },
+
+        _comments: [],
+        Comment: function Comment(block, text) {
+          ast.Base.call(this, "Comment");
+          this.block = block;
+          this.text = text;
+          ast._comments.push(this);
+        },
+
+        Id: function Id(type, id) {
+          ast.Base.call(this, type);
+          this.id = id;
+        },
+
+        Schema: function Schema(includes, statements) {
+          ast.Id.call(this, "Schema", fileName);
+          this.includes = includes;
+          this.statements = statements;
+        },
+
+        Include: function Include(id) {
+          throw err(12, "INCLUDE");
+          ast.Id.call(this, "Include", id);
+        },
+
+        Rule: function Rule(id, ruleType, patterns, buildBlock) {
+          ast.Id.call(this, "Rule", id);
+          this.ruleType = ruleType;
+          // this.refId = "Comp_" + getUniqueNumber(); // aka "work_name" in RIGAL code
+          this.patterns = patterns;
+          // this.buildBlock = buildBlock;
+        },
+
+        RootRule: function RootRule(id, patterns, buildBlock) {
+          ast.Rule.call(this, id, "RootRule", patterns, buildBlock);
+        },
+
+        CompositeRule: function CompositeRule(id, patterns, buildBlock) {
+          ast.Rule.call(this, id, "CompositeRule", patterns, buildBlock);
+        },
+
+        Event: function Event(id) {
+          ast.Id.call(this, "Event", id);
+        },
+
+        Sequence: function Sequence(body) { // aka pattern_list
+          ast.Base.call(this, "Sequence");
+          // this.refId = "Sq_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.body = body;
+        },
+
+        Alternative: function Alternative(body) {
+          ast.Base.call(this, "Alternative");
+          // this.refId = "Alt_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.body = body;  // aka "patterns" in the RIGAL codye
+        },
+
+        Probability: function Probability(p) {
+          throw err(12, "PROBABILITY");
+          ast.Base.call(this, "Probability");
+          this.p = p;
+        },
+
+        MinMax: function MinMax(min, max) {
+          ast.Base.call(this, "MinMax");
+          this.min = min;
+          this.max = max;
+        },
+
+        Iterator: function Iterator(scope, body) {
+          ast.Base.call(this, "Iterator");
+          // this.refId = "Itr_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.scope = scope;
+          this.body = body;
+        },
+
+        Set: function Set(body) {
+          ast.Base.call(this, "Set");
+          // this.refId = "Set_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.body = body;
+        },
+
+        SetIterator: function SetIterator(scope, body) {
+          ast.Base.call(this, "SetIterator");
+          // this.refId = "SetIterator_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.scope = scope;
+          this.body = body;
+        },
+
+        Optional: function Optional(body) {
+          ast.Base.call(this, "Optional");
+          // this.refId = "Opt_" + getUniqueNumber(); // aka "name" in RIGAL code
+          this.body = body;
+        },
+
+        Coordinate: function Coordinate(async, srcs, body) {
+          ast.Base.call(this, "Coordinate");
+          // this.refId = "Coordinate_" + getUniqueNumber(); // aka "work" in RIGAL code
+          this.async = async;
+          this.srcs = srcs;
+          this.body = body;
+        },
+
+        CoordinateSource: function CoordinateSource(id, select, from) {
+          ast.Id.call(this, "CoordinateSource", id);
+          this.select = select;
+          this.from = from || "<this>";
+        },
+
+        ShareAll: function ShareAll(hosts, events) {
+          ast.Base.call(this, "ShareAll");
+          // this.refId = "ShareAll_" + getUniqueNumber(); // aka "work" in RIGAL code
+          this.hosts = hosts;
+          this.events = events;
+        },
+
+        Relationship: function Relationship(src, relType, dst) {
+            ast.Base.call(this, "Relationship");
+            this.relType = relType;
+            this.src = src;
+            this.dst = dst;
+        },
+
+        AddOperation: function AddOperation(rels) {
+          ast.Base.call(this, "Add");
+          this.relationships = rels;
+        },
+
+      };
+
+      parse.ast = ast;
+
+      if (opts.ast) {
+        /*TODO: setup overrides from opts.ast on top of ast*/
+      }
+
+      var errors = {
+        // 1: "wrong schema name $a identifier expected/ !", //NOTE: probably not applicable if we make SCHEMA go away (or at least optional silliness)
+        // 2: "wrong event pattern $a / !",  //NOTE: errors handled by our generated parser
+        3: "trigger event $a should not appear in WHEN pattern list / !",
+        //// 4: "detected around token $a/ !", //NOTE: errors handled by our generated parser
+        5: "defined event name should not appear in rule body: ",
+        //TODO: 6: "recursion for event $a is detected/ !", //TODO: check for this
+        // 7: "syntax error in probability definition detected at $a/ !", //NOTE: just took out of parser for now
+        // 8: "schema name $a should be the same as input parameter/ !", //NOTE: disabled this restriction
+        // 9: "keyword 'DO' is expected in COORDINATE when actual token is $a / !", //NOTE: errors handled by our generated parser
+        // 10: "keyword 'OD' is expected in COORDINATE when actual token is $a / !", //NOTE: errors handled by our generated parser
+        // 11: "semicolon is expected when actual token is $a / !", //NOTE: errors handled by our generated parser
+        12: "not implemented yet: ",
+        // 13: "':' is expected when actual token is $a / !", //NOTE: errors handled by our generated parser
+        // 14: "incorrect variable name $a in the COORDINATE source / !", //NOTE: errors handled by our generated parser
+        // 15: "derivation for root $a should be completed before composition/ !", //NOTE: handled by 21
+        // 16: "wrong relation name $a in the ADD composition/ !", //NOTE: errors handled by our generated parser
+        17: "variable is not defined: ",
+        //TODO: 18: "shared event $a has not been defined in any grammar rule / !", //TODO: not sure how to recreate to test this
+        19: "variable has been defined twice: ",
+        //NOTE: additional errors added by us
+        20: "rule defined more than once: ",
+        21: "reference to undefined item: ",
+        22: "reference to non-root event: ",
+      };
+
+
+
+    peg$result = peg$startRuleFunction();
+
+    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+      return peg$result;
+    } else {
+      if (peg$result !== peg$FAILED && peg$currPos < input.length) {
+        peg$fail({ type: "end", description: "end of input" });
+      }
+
+      throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
+    }
+  }
+
+  return {
+    SyntaxError: SyntaxError,
+    parse:       parse
+  };
+})();

+ 17 - 0
src/web/assets/scripts/snippets-mp2.js

@@ -0,0 +1,17 @@
+/*global ace*/
+
+ace.define("ace/snippets/mp2",
+["require", "exports", "module"],
+function(require, exports, module) {
+	"use strict";
+
+	exports.snippetText = "# SCHEMA\n" +
+		"snippet schema\n" +
+		"	SCHEMA ${1:schema_name};\n" +
+		"# ROOT\n" +
+		"snippet root\n" +
+		"	ROOT ${1:root_name}: ${2:next_events_expression}\n"
+		;
+
+	exports.scope = "mp2";
+});

+ 111 - 0
src/web/components/data/files.js

@@ -0,0 +1,111 @@
+angular.module("mp-ide.components.editor", [
+	"ui-ace",
+])
+
+.factory("FilesSvc", [
+"$q",
+function($q) {
+	var FilesSvc = {
+
+		/**
+		 * getPathParts  Get the parts of the given path. Only accepts absolute paths.
+		 * @param {String} path  The path
+		 * @return {Object}  The path parts as the following keys in a new Object: dirname, basename
+		 */
+		getPathParts: function(path) {
+			// minor path cleanup //TODO: get around to using real 'path' library once this is a real service for a real backend
+			path = path.trim()
+				.replace(/\/\//g, "/")
+				.replace(/(\/?[^/]*)\/\.\.\//g, "/");
+			var match = /^(.*\/)?(.+)?$/.exec(path);
+			if (!match) throw new Error("Unable to get path parts");
+			var dirname = match[1],
+				basename = match[2];
+			if (dirname[0] !== "/") throw new Error("Expected the directory part of the path must start with a leading slash");
+			if (!dirname) throw new Error("Expected the directory part of the path to exist. Absolute paths only.");
+			return {
+				dirname: dirname,
+				basename: basename,
+			};
+		},
+
+		/**
+		 * _getRoot  Internal method to get the root files Object
+		 * @private
+		 */
+		_getRoot: function() {
+			var filesObj = localStorage.getItem("files");
+			return filesObj ? JSON.parse(filesObj) : {};
+		},
+
+		/**
+		 * _setRoot  Internal method to set the root files Object
+		 * @param {Object} filesObj  The files Object to set
+		 * @private
+		 */
+		_setRoot: function(filesObj) {
+			localStorage.setItem("files", JSON.stringify(filesObj));
+		},
+
+		/**
+		 * get  Gets the dir or file at the given `path`
+		 * @param  {String} path  The absolute path to the file
+		 * @return {Promise<Object>}  A Promise that resolves to requested dir/file Object
+		 */
+		get: function(path) {
+			return $q(function(resolve, reject) {
+				var pathParts = FilesSvc.getPathParts(path),
+					dirParts = pathParts.split(pathParts.dirname),
+					filesObj = FilesSvc._getRoot(),
+					dirObj = dirParts.reduce(function(ptr, key) {
+						return ptr[key] || (ptr[key] = {});
+					}, filesObj);
+				return resolve(pathParts.basename ? dirObj[pathParts.basename] : dirObj);
+			});
+		},
+
+		/**
+		 * set  Sets the dir or file at the given `path` to the given `data` value
+		 * @param  {String} path  The absolute path to the file
+		 * @return {Promise}  A Promise that resolves once data has been set
+		 */
+		set: function(path, data) {
+			return $q(function(resolve, reject) {
+				var pathParts = FilesSvc.getPathParts(path),
+					dirParts = pathParts.split(pathParts.dirname),
+					filesObj = FilesSvc._getRoot(),
+					dirObj = dirParts.reduce(function(ptr, key) {
+						return ptr[key] || (ptr[key] = {});
+					}, filesObj);
+				if (pathParts.basename) dirObj[pathParts.basename] = data;
+				FilesSvc._setRoot(filesObj);
+				return resolve();
+			});
+		},
+
+		/**
+		 * delete  Deletes the dir or file at the given `path` to the given `data` value
+		 * @param  {String} path  The absolute path to the file
+		 * @return {Promise}  A Promise that resolves once data has been deleted
+		 */
+		delete: function(path) {
+			return $q(function(resolve, reject) {
+				var pathParts = FilesSvc.getPathParts(path),
+					dirParts = pathParts.split(pathParts.dirname),
+					filesObj = FilesSvc._getRoot();
+				if (!pathParts.basename) { // we need to be one object above
+					pathParts.basename = dirParts[dirParts.length - 1], pathParts.dirName = dirParts.join("/"), dirParts.pop();
+				}
+				var dirObj = dirParts.reduce(function(ptr, key) {
+					return ptr[key] || (ptr[key] = {});
+				}, filesObj);
+				delete dirObj[pathParts.basename];
+				FilesSvc._setRoot(filesObj);
+				return resolve();
+			});
+		},
+
+	};
+	return FilesSvc;
+},
+]);

+ 108 - 0
src/web/components/editor/editor.css

@@ -0,0 +1,108 @@
+/* dark theme tweaks */
+editor .ace-tomorrow-night .ace_marker-layer .ace_selected-word {
+	box-shadow: 0 0 1px #CCC;
+}
+
+
+/* statusbar tweaks */
+editor .ace_status-indicator {
+	position: absolute;
+	right: 0.5em;
+	bottom: 0.5em;
+	z-index: 99;
+	opacity: 0.5;
+}
+
+
+/* autocomplete plugin tweaks */
+body .ace_editor.ace_autocomplete {
+	background: inherit;
+	color: inherit;
+	box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.3);
+	border-radius: 0.25em;
+	border: 1px #444 solid;
+}
+body .ace_editor.ace_autocomplete .ace_line {
+	color: #888;
+}
+body .ace_editor.ace_autocomplete .ace_line .ace_completion-highlight {
+	color: #DDD;
+}
+body .ace_editor.ace_autocomplete .ace_line.ace_selected {
+	color: #444;
+}
+body .ace_editor.ace_autocomplete .ace_line.ace_selected .ace_completion-highlight {
+	color: #FFF;
+	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
+}
+body .ace_editor.ace_autocomplete .ace_marker-layer .ace_line-hover {
+	opacity: 0.5;
+}
+body .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
+	background-color: #ABC;
+}
+
+
+/* search plugin tweaks */
+editor .ace_search {
+	position: absolute;
+	left: 0;
+	top: inherit;
+	bottom: 0;
+	right: inherit;
+	max-width: inherit;
+	width: 100%;
+	padding-top: 5px;
+	margin: 0;
+	border: 0;
+	border-top: 2px solid #ABC;
+	background: inherit;
+	color: #CCD;
+}
+
+editor .ace_search > * {
+	float: none;
+	display: table;
+}
+
+editor .ace_search .ace_replace_form > * {
+	float: none;
+}
+editor .ace_search .ace_replace_form .ace_replacebtn {
+	padding: 4px;
+}
+
+editor .ace_search .ace_searchbtn_close {
+	position: absolute;
+	top: 0;
+	right: 4px;
+}
+
+editor .ace_search .ace_search_options {
+	position: absolute;
+	top: 5px;
+	right: 40px;
+}
+
+editor .ace_search input,
+editor .ace_search button,
+editor .ace_search .ace_button {
+	background-color: #234;
+	color: #CCD;
+	transition: background-color 0.1s, color 0.1s;
+	opacity: 1.0;
+}
+
+editor .ace_search input:focus,
+editor .ace_search button:focus,
+editor .ace_search .ace_button:focus {
+	background-color: #345;
+	border-color: #345;
+}
+
+editor .ace_search button:hover,
+editor .ace_search .ace_button:hover {
+	transition: background-color 0.3s, color 0.3s;
+	background-color: #ABC;
+	color: #234;
+}

+ 4 - 0
src/web/components/editor/editor.html

@@ -0,0 +1,4 @@
+<div style="height:100%"
+	ng-model="model.data"
+	ui-ace="model.options"
+></div>

+ 156 - 0
src/web/components/editor/editor.js

@@ -0,0 +1,156 @@
+"use strict";
+/*global ace*/
+
+angular.module("mp-ide.components.editor", [
+	"ui.ace",
+])
+
+.service("parser", //ideally this should probably be an ACE plugin but this was easier for now
+["$window", "$q",
+function($window, $q) {
+	var worker = null,
+		working = {},
+		worked = 0;
+	if (Boolean($window.Worker)) {
+		worker = new Worker("assets/mp2-parser-worker.js");
+		worker.onmessage = function onParserWorkerMessage(msg) {
+			var data = msg.data,
+				work = working[data.id];
+			delete working[data.id];
+			work.resolve(data.parsed);
+		};
+	}
+	return {
+		parse: function(input) {
+			var id = worked++,
+				work = $q.defer();
+			if (worker !== null) {
+				worker.postMessage({
+					id: id,
+					input: input,
+				});
+				working[id] = work;
+			} else {
+				$q.all($window.mp2 ? [] : [$.getScript("assets/mp2-parser.js")])
+					.then(function() {
+						var parsed;
+						try {
+							parsed = $window.mp2.parse(input);
+						} catch (err) {
+							parsed = {
+								errors: [err],
+							};
+						}
+						work.resolve(parsed);
+					});
+			}
+			return work.promise;
+		}
+	};
+},
+])
+
+.directive("editor",
+["$timeout", "parser",
+function($timeout, parser) {
+	return {
+		restrict: "E",
+		scope: {
+			model: "=editorModel",
+		},
+		controller: "EditorCtrl",
+		controllerAs: "ctrl",
+		templateUrl: "components/editor/editor.html",
+		link: {
+			pre: function(scope, element, attrs, ctrl) {
+
+				scope.model.options.onLoad = function onEditorLoaded(editor) {
+
+					editor.$blockScrolling = Infinity; //fix warning
+
+					//var session = editor.getSession();
+					//TODO:  there is a flicker on load... AAAAAAHAHHAHAHAHAH!
+
+					//TODO: disable this syntax debugging code
+					var ttExt = ace.require("ace/token_tooltip");
+					new ttExt.TokenTooltip(editor); //jshint ignore:line
+
+					//TODO: grab list of commands from Kyle's MongoDB IDE
+
+					//TODO: integrate whitespace: use debounced `onchange` handler to call `wsExt.trimTrailingSpace(session);`
+					//var wsExt = ace.require("ace/ext/whitespace");
+
+					// TODO: fork statusbar:  row/col should start at 1 not 0
+					var sbExt = ace.require("ace/ext/statusbar"),
+						sb = new sbExt.StatusBar(editor, editor.container);
+
+					//TODO: fork keybinding_menu:  bindKey, styling, could have more explanatory text, modal, maybe a Ctrl-P feature?
+					// var kmExt = ace.require("ace/ext/keybinding_menu");
+					// kmExt.init(editor);
+					// editor.commands.addCommands([
+					// 	{
+					// 		name: "showKeyboardShortcuts",
+					// 		bindKey: {win: "Ctrl-Alt-/", mac: "Command-Alt-/"},
+					// 		exec: function(editor, line) {
+					// 			editor.showKeyboardShortcuts();
+					// 		},
+					// 	},
+					// ]);
+
+					//TODO: redirect all window keys w/ modifiers to the most recently selected editor (to avoid editor find vs browser find)
+
+					//TODO: use themed inline line number dialog, map to Ctrl+G as well please
+
+					var pendingParse;
+					scope.$watch("model.data", function onDataChanged(data) {
+						$timeout.cancel(pendingParse);
+						pendingParse = $timeout(parser.parse, 100, true, data)
+							.then(function(parsed) {
+								var annotations = parsed.errors.map(function(err) {
+									return {
+										row: err.line - 1,
+										column: err.column - 1,
+										text: err.name + ": " + err.message,
+										type: "error",
+									};
+								});
+								editor.getSession().setAnnotations(annotations);
+							});
+					});
+
+				};
+
+			}
+		},
+	};
+},
+])
+
+.controller("EditorCtrl",
+["$scope",
+function($scope) {
+	var defaults = {
+		mode: "mp",
+		theme: "tomorrow_night",
+		require: ["ace/ext/language_tools"],
+		useSoftTabs: false,
+		advanced: {
+			enableSnippets: true,
+			enableBasicAutocompletion: true,
+			enableLiveAutocompletion: true,
+		},
+		rendererOptions: {
+			fontSize: "13px",
+			fontFamily: "Inconsolata, Monaco, Consolas, Courier New, Courier",
+			fadeFoldWidgets: true,
+			scrollPastEnd: true,
+		},
+	};
+	if (!$scope.model) $scope.model = {};
+	$scope.model.options = Object.keys(defaults).reduce(function(opts, optName) {
+		if (!(optName in opts)) opts[optName] = defaults[optName];
+		return opts;
+	}, $scope.model.options || {});
+	if (!$scope.model.data) $scope.model.data = "";
+},
+]);

+ 5 - 0
src/web/components/layout/layout.css

@@ -0,0 +1,5 @@
+layout {
+	display: block;
+	min-height: 100%;
+	height: 100%;
+}

+ 167 - 0
src/web/components/layout/layout.js

@@ -0,0 +1,167 @@
+"use strict";
+/*global GoldenLayout*/
+
+//TODO: this works for now but probably still needs a bit of work
+//TODO: may eventually want to wrap up registering named component templates as a directive to reduce the amount of info in the toConfig()
+
+
+angular.module("mp-ide.components.layout", [
+	// deps go here
+])
+
+.directive("layout", [
+"$window", "$compile",
+function($window, $compile) {
+	return {
+		restrict: "E",
+		scope: true,
+		controllerAs: "ctrl",
+		link: function(scope, element, attrs, ctrl, transcludeFn) {
+
+			if (attrs.layoutModel) { //TODO: watch
+				var model = scope.$parent.$eval(attrs.layoutModel);
+				if (model.options.settings) scope.model.settings = model.options.settings;
+				if (model.options.dimensions) scope.model.dimensions = model.options.dimensions;
+			}
+
+			scope.goldenLayoutConfig = {
+				settings: scope.model.settings,
+				dimensions: scope.model.dimensions,
+				content: scope.model.data,
+			};
+			scope.goldenLayout = new GoldenLayout(scope.goldenLayoutConfig, element);
+			Object.keys(scope.templates).forEach(function(tmplName) {
+				var tmpl = scope.templates[tmplName];
+				scope.goldenLayout.registerComponent(tmplName, function(container, state) {
+					var element = container.getElement();
+					element.html(tmpl);
+					$compile(element.contents())(scope.$parent);
+				});
+			});
+			scope.goldenLayout.registerComponent("angularTemplate", function createAngularTemplate(container, state) {
+				var element = container.getElement();
+				element.html(state.template);
+				if (typeof state.template === "string") {
+					$compile(element.contents())(scope.$parent);
+				}
+			});
+			scope.goldenLayout.init();
+
+			scope.$watch(
+				function getDimensions() {
+					return {
+						w: element.width(),
+						h: element.height(),
+					};
+				},
+				function onDimensionsChanged(dim, oldDim) {
+					if (!dim) return;
+					scope.goldenLayout.updateSize(dim.w, dim.h);
+				},
+				true //deep
+			);
+
+			$($window).on("resize", function() {
+				scope.$apply();
+			});
+		},
+		controller: function($scope) {
+			if (!$scope.model) $scope.model = {};
+			if (!$scope.model.data) $scope.model.data = [];
+			$scope.templates = {};
+			this.register = function(name, tmpl) {
+				$scope.templates[name] = tmpl;
+			};
+		},
+	};
+},
+])
+
+.directive("layoutRow", function() {
+	return {
+		restrict: "E",
+		require: "^^layout",
+		scope: true,
+		link: function(scope, element, attrs, layoutCtrl) {
+			var options = attrs.layoutOptions ? scope.$parent.$eval(attrs.layoutOptions) : {},
+				config = {
+					type: "row",
+					content: scope.model.data,
+				},
+				item = angular.extend({}, options, config);
+			scope.$parent.model.data.push(item);
+		},
+		controller: function($scope) {
+			if (!$scope.hasOwnProperty("model")) $scope.model = {};
+			if (!$scope.model.data) $scope.model.data = [];
+		},
+	};
+})
+
+.directive("layoutColumn", function() {
+	return {
+		restrict: "E",
+		require: "^^layout",
+		scope: true,
+		link: function(scope, element, attrs, layoutCtrl) {
+			var options = attrs.layoutOptions ? scope.$parent.$eval(attrs.layoutOptions) : {},
+				config = {
+					type: "column",
+					content: scope.model.data,
+				},
+				item = angular.extend({}, options, config);
+			scope.$parent.model.data.push(item);
+		},
+		controller: function($scope) {
+			if (!$scope.hasOwnProperty("model")) $scope.model = {};
+			if (!$scope.model.data) $scope.model.data = [];
+		},
+	};
+})
+
+.directive("layoutStack", function() {
+	return {
+		restrict: "E",
+		require: "^^layout",
+		scope: true,
+		link: function(scope, element, attrs, layoutCtrl) {
+			var options = attrs.layoutOptions ? scope.$parent.$eval(attrs.layoutOptions) : {},
+				config = {
+					type: "stack",
+					content: scope.model.data,
+				},
+				item = angular.extend({}, options, config);
+			scope.$parent.model.data.push(item);
+		},
+		controller: function($scope) {
+			if (!$scope.hasOwnProperty("model")) $scope.model = {};
+			if (!$scope.model.data) $scope.model.data = [];
+		},
+	};
+})
+
+.directive("layoutContent", function() {
+	return {
+		restrict: "E",
+		require: "^^layout",
+		scope: true,
+		link: {
+			pre: function(scope, element, attrs, layoutCtrl) {
+				var options = attrs.layoutOptions ? scope.$parent.$eval(attrs.layoutOptions) : {},
+					config = {
+						type: "component",
+						componentName: "angularTemplate",
+						componentState: {
+							template: element.remove(),
+						},
+					},
+					item = angular.extend({}, options, config);
+				scope.$parent.model.data.push(item);
+			},
+		},
+		controller: function($scope) {
+			if (!$scope.hasOwnProperty("model")) $scope.model = {};
+			if (!$scope.model.data) $scope.model.data = [];
+		},
+	};
+});

+ 38 - 0
src/web/components/menu/menu.css

@@ -0,0 +1,38 @@
+menu {
+	margin: 0;
+	padding: 0;
+}
+
+/* navbar-xs */
+menu .navbar-xs {
+	min-height: 28px;
+	height: 28px;
+    margin-bottom: 0;
+}
+menu .navbar-xs .navbar-brand {
+	padding: 0 12px;
+	font-size: 16px;
+	line-height: 28px;
+}
+menu .navbar-xs .navbar-nav > li > a {
+	padding-top: 0;
+	padding-bottom: 0;
+	line-height: 28px;
+}
+
+/* navbar-inverse dropdowns */
+menu .navbar-inverse .dropdown,
+menu .navbar-inverse .dropdown-menu {
+    background-color: #222;
+    border-color: #080808;
+}
+menu .navbar-inverse .dropdown li a {
+    background-color: #222;
+    border-color: #080808;
+    color: #999;
+}
+menu .navbar-inverse .dropdown li a:hover {
+    border-color: #080808;
+    color: #fff;
+    background-color: #000;
+}

+ 29 - 0
src/web/components/menu/menu.html

@@ -0,0 +1,29 @@
+<div class="navbar navbar-xs navbar-inverse navbar-static-top">
+    <div class="container-fluid">
+
+        <!-- Brand and toggle get grouped for better mobile display -->
+        <div class="navbar-header">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+            <span class="sr-only">Toggle navigation</span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+          </button>
+          <!-- <a class="navbar-brand" href>MP</a> -->
+        </div>
+
+        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+            <ul class="nav navbar-nav">
+                <li class="dropdown">
+                    <a href class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
+                        File <span class="caret"></span>
+                    </a>
+                    <ul class="dropdown-menu" role="menu">
+                        <li><a ng-click="pageCtrl.open()">Open ...</a></li>
+                        <li><a ng-click="ctrl.save()">Save</a></li>
+                    </ul>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>

+ 24 - 0
src/web/components/menu/menu.js

@@ -0,0 +1,24 @@
+"use strict";
+
+angular.module("mp-ide.components.menu",
+[//deps
+])
+
+.directive("menu", function() {
+	return {
+		restrict: "E",
+		scope: false,
+		controller: "MenuCtrl",
+		controllerAs: "ctrl",
+		templateUrl: "components/menu/menu.html",
+		link: function(scope, element, attrs) {
+		},
+	};
+})
+
+.controller("MenuCtrl",
+["$scope",
+function($scope) {
+
+},
+]);

+ 22 - 0
src/web/index.css

@@ -0,0 +1,22 @@
+/* app css stylesheet */
+
+html, body {
+    min-height: 100%;
+    height: 100%;
+    background-color: #222222;
+    color: #eeeeee;
+}
+
+.ng-scope {
+    height: 100%;
+}
+
+div[ng-view] {
+    height: calc(100% - 28px);
+}
+
+
+/* see https://angular-ui.github.io/bootstrap/#/getting_started */
+.nav, .pagination, .carousel, .panel-title a {
+    cursor: pointer;
+}

+ 79 - 0
src/web/index.html

@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<!--[if lt IE 7]>      <html lang="en" ng-app="modellang-ide" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]>         <html lang="en" ng-app="modellang-ide" class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]>         <html lang="en" ng-app="modellang-ide" class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!-->
+<html lang="en" ng-app="modellang-ide" class="no-js">
+<!--<![endif]-->
+
+<head>
+
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>model-lang Editor</title>
+
+    <!-- CSS -->
+    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
+    <link rel="stylesheet" href="bower_components/html5-boilerplate/css/main.css">
+    <link rel="stylesheet" href="bower_components/golden-layout/src/css/goldenlayout-base.css">
+    <link rel="stylesheet" href="bower_components/golden-layout/src/css/goldenlayout-dark-theme.css">
+
+    <!-- CSS: App-->
+    <link rel="stylesheet" href="components/menu/menu.css">
+    <link rel="stylesheet" href="components/layout/layout.css">
+    <link rel="stylesheet" href="components/editor/editor.css">
+    <link rel="stylesheet" href="home/home.css">
+    <link rel="stylesheet" href="index.css">
+
+</head>
+
+<body>
+    <!--[if lt IE 7]>
+        <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+    <![endif]-->
+
+    <menu></menu>
+
+    <div ng-view></div>
+
+
+    <!-- JS: initialization -->
+    <script src="bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
+
+    <!-- JS: jQuery -->
+    <script src="bower_components/jquery/dist/jquery.min.js"></script>
+    <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
+    <script src="bower_components/golden-layout/dist/goldenlayout.min.js"></script>
+
+    <!-- JS: AngularJS -->
+    <script src="bower_components/angular/angular.js"></script>
+    <script src="bower_components/angular-route/angular-route.js"></script>
+
+    <!-- JS: ACE -->
+    <script src="bower_components/ace-builds/src-noconflict/ace.js"></script>
+    <script src="bower_components/ace-builds/src-noconflict/ext-language_tools.js"></script>
+    <script src="bower_components/ace-builds/src-noconflict/ext-statusbar.js"></script>
+    <script src="bower_components/angular-ui-ace/ui-ace.min.js"></script>
+    <script src="assets/scripts/debug_ace_token_tooltip.js"></script>
+    <script src="assets/scripts/mp.js"></script>
+    <script src="assets/scripts/snippets-mp.js"></script>
+    <script>
+        /*global ace*/
+        var aceConfig = ace.require("ace/config");
+        aceConfig.setModuleUrl("ace/mode/mp", "assets/scripts/mp.js");
+        aceConfig.setModuleUrl("ace/mode/mp", "assets/scripts/snippets-mp.js");
+    </script>
+
+    <!-- JS: App -->
+    <script src="components/menu/menu.js"></script>
+    <script src="components/layout/layout.js"></script>
+    <script src="components/editor/editor.js"></script>
+    <script src="pages/home/home.js"></script>
+    <script src="index.js"></script>
+
+</body>
+
+</html>

+ 23 - 0
src/web/index.js

@@ -0,0 +1,23 @@
+"use strict";
+
+// Declare app level module which depends on views, and components
+angular.module("mp-ide", [
+	"ngRoute",
+	"mp-ide.components.menu",
+	"mp-ide.home",
+])
+
+.config(
+["$routeProvider",
+function($routeProvider) {
+	$routeProvider
+		.when("/:page", {
+			template: function(args) {
+				return "<div " + args.page + "/>";
+			},
+		})
+		.otherwise({
+			redirectTo: "/home",
+		});
+},
+]);

+ 0 - 0
src/web/pages/home/home.css


+ 50 - 0
src/web/pages/home/home.html

@@ -0,0 +1,50 @@
+<layout
+	layout-commands="layoutCommands"
+	layout-model="{
+		options: {
+			settings: {
+				showPopoutIcon: false,
+				showCloseIcon: false,
+			},
+		},
+	}"
+>
+
+	<layout-row>
+
+		<layout-column layout-options="{width:10}">
+			<layout-content layout-options="{title:'Schema Tree'}">
+				<p><b>TODO:</b> Schemas</p>
+			</layout-content>
+		</layout-column>
+
+		<layout-column layout-options="{width:60}">
+
+			<layout-content layout-options="{title:'Edit'}">
+				<editor
+					editor-model="editorModel"
+				/></editor>
+			</layout-content>
+
+
+		</layout-column>
+
+		<layout-column layout-options="{width:30}">
+
+			<layout-content layout-options="{title:'Constraints', height:10}">
+				<p><b>TODO:</b> Constraints</p>
+			</layout-content>
+
+			<layout-content layout-options="{title:'Relationship Graph'}">
+				<p><b>TODO:</b> Relationship Graph</p>
+			</layout-content>
+
+			<layout-content layout-options="{title:'Event Info'}">
+				<p><b>TODO:</b> Event Info</p>
+			</layout-content>
+
+		</layout-column>
+
+	</layout-row>
+
+</layout>

+ 112 - 0
src/web/pages/home/home.js

@@ -0,0 +1,112 @@
+"use strict";
+
+angular.module("mp-ide.home", [
+	"mp-ide.components.layout",
+	"mp-ide.components.editor",
+])
+
+.directive("home", function() {
+	return {
+		scope: false,
+		controller: "HomeCtrl",
+		controllerAs: "pageCtrl",
+		templateUrl: "pages/home/home.html",
+		link: function(scope, element, attrs) {
+		},
+	};
+})
+
+.controller("HomeCtrl",
+["$scope", "$compile",
+function($scope, $compile) {
+
+	$scope.editorModel = {
+		data: //TODO: remove this and move elsewhere very soon
+		"// line comment\n" +
+		"\n" +
+		"/* this is a\n" +
+		" * a block comment\n" +
+		" */\n" +
+		"\n" +
+		"\n" +
+		"// Example 1: car race scenarios\n" +
+		"SCHEMA ex1_car_race\n" +
+		"ROOT car_race:  {+ driving_a_car +};\n" +
+		"driving_a_car:  go_straight (* ( go_straight | turn_left | turn_right ) *) stop;\n" +
+		"go_straight:    ( accelerate | decelerate | cruise );\n" +
+		"\n" +
+		"\n" +
+		"// Example 2: Simple pipe/filter architecture pattern\n" +
+		"SCHEMA ex2_simple_message_flow\n" +
+		"ROOT Task_A: (* send *);\n" +
+		"ROOT Task_B: (* receive *);\n" +
+		"COORDINATE (* $x: send *) FROM Task_A, (* $y: receive *) FROM Task_B\n" +
+		"                                                            ADD $x PRECEDES $y;\n" +
+		"\n" +
+		"\n" +
+		"// Example 3. Data items as behaviors. Data flow.\n" +
+		"SCHEMA Data_flow\n" +
+		"ROOT Process_1: (* work write *);\n" +
+		"ROOT Process_2: (* ( read | work ) *);\n" +
+		"ROOT File: (* write *) (* read *);\n" +
+		"Process_1, File SHARE ALL write;\n" +
+		"Process_2, File SHARE ALL read;\n" +
+		"\n" +
+		"\n" +
+		"// Example 4. Stack behavior\n" +
+		"SCHEMA Stack\n" +
+		"ROOT Stack_operation: (* ( push | pop) *);\n" +
+		"SATISFIES FOREACH $x: pop FROM Stack_operation\n" +
+		"              ( Number_of (pop) before ($x) < Number_of (push) before ($x) );\n" +
+		"\n" +
+		"\n" +
+		"// Example 5 (from the PDF)\n" +
+		"SCHEMA Two_stacks_in_use\n" +
+		"INCLUDE Stack;\n" +
+		"ROOT Main: {* (do_something | use_S1 | use_S2) *};\n" +
+		" use_S1:   (push | pop);\n" +
+		" use_S2:   (push | pop);\n" +
+		"ROOT S1:   (* use_S1 *);\n" +
+		"ROOT S2:   (* use_S2 *);\n" +
+		"\n" +
+		"S1, Main SHARE ALL use_S1;\n" +
+		"S2, Main SHARE ALL use_S2;\n" +
+		"\n" +
+		"\n" +
+		"// Example 6. Components and connectors\n" +
+		"SCHEMA Buffered_transaction\n" +
+		"ROOT Task_A:: (* Send *);\n" +
+		"ROOT Task_B:: (* Receive *);\n" +
+		"ROOT Buffered_channel: {* (Send [ Receive ] ) *} (Overflow | Normal);\n" +
+		"\n" +
+		"Task_A, Buffered_channel SHARE ALL Send;\n" +
+		"Task_B, Buffered_channel SHARE ALL Receive;\n" +
+		"\n" +
+		"SATISFIES FOREACH $x: Receive FROM Buffered_channel\n" +
+		"   ( Number_of (Send) before ($x) - Number_of (Receive) before ($x) ) <= max_buffer_size;\n" +
+		"SATISFIES FOREACH $x: Overflow FROM Buffered_channel\n" +
+		"   ( Number_of (Send) before ($x) - Number_of (Receive) before ($x) ) > max_buffer_size;\n" +
+		"SATISFIES FOREACH $x: Normal FROM Buffered_channel\n" +
+		"   ( Number_of (Send) before ($x) - Number_of (Receive) before ($x) ) <= max_buffer_size;\n" +
+		"\n" +
+		"\n" +
+		"//TODO: Example 7\n" +
+		"//TODO: Example 8\n" +
+		"//TODO: Example 9\n" +
+		"//TODO: Example 10\n" +
+		"//TODO: Example 11\n" +
+		"//TODO: Example 12\n" +
+		"//TODO: Example 13\n" +
+		"//TODO: Example 14\n" +
+		"//TODO: Example 15\n" +
+		"\n"
+	};
+
+	$scope.menus = "File";
+
+	$scope.save = function() {
+		localStorage.setItem("code", $scope.editor.doc.getValue());
+	};
+
+},
+]);