(function () { /** * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. * Released under MIT license, http://github.com/requirejs/almond/LICENSE */ //Going sloppy to avoid 'use strict' string cost, but strict practices should //be followed. /*global setTimeout: false */ var requirejs, require, define; (function (undef) { var main, req, makeMap, handlers, defined = {}, waiting = {}, config = {}, defining = {}, hasOwn = Object.prototype.hasOwnProperty, aps = [].slice, jsSuffixRegExp = /\.js$/; function hasProp(obj, prop) { return hasOwn.call(obj, prop); } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @returns {String} normalized name */ function normalize(name, baseName) { var nameParts, nameSegment, mapValue, foundMap, lastIndex, foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {}; //Adjust any relative paths. if (name) { name = name.split('/'); lastIndex = name.length - 1; // If wanting node ID compatibility, strip .js from end // of IDs. Have to do this here, and not in nameToUrl // because node allows either .js or non .js to map // to same file. if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); } // Starts with a '.' so need the baseName if (name[0].charAt(0) === '.' && baseParts) { //Convert baseName to array, and lop off the last part, //so that . matches that 'directory' and not name of the baseName's //module. For instance, baseName of 'one/two/three', maps to //'one/two/three.js', but we want the directory, 'one/two' for //this normalization. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); name = normalizedBaseParts.concat(name); } //start trimDots for (i = 0; i < name.length; i++) { part = name[i]; if (part === '.') { name.splice(i, 1); i -= 1; } else if (part === '..') { // If at the start, or previous value is still .., // keep them so that when converted to a path it may // still work when converted to a path, even though // as an ID it is less than ideal. In larger point // releases, may be better to just kick out an error. if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') { continue; } else if (i > 0) { name.splice(i - 1, 2); i -= 2; } } } //end trimDots name = name.join('/'); } //Apply map config if available. if ((baseParts || starMap) && map) { nameParts = name.split('/'); for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join("/"); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = map[baseParts.slice(0, j).join('/')]; //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = mapValue[nameSegment]; if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break; } } } } if (foundMap) { break; } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && starMap[nameSegment]) { foundStarMap = starMap[nameSegment]; starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join('/'); } } return name; } function makeRequire(relName, forceSync) { return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName var args = aps.call(arguments, 0); //If first arg is not require('string'), and there is only //one arg, it is the array form without a callback. Insert //a null so that the following concat is correct. if (typeof args[0] !== 'string' && args.length === 1) { args.push(null); } return req.apply(undef, args.concat([relName, forceSync])); }; } function makeNormalize(relName) { return function (name) { return normalize(name, relName); }; } function makeLoad(depName) { return function (value) { defined[depName] = value; }; } function callDep(name) { if (hasProp(waiting, name)) { var args = waiting[name]; delete waiting[name]; defining[name] = true; main.apply(undef, args); } if (!hasProp(defined, name) && !hasProp(defining, name)) { throw new Error('No ' + name); } return defined[name]; } //Turns a plugin!resource to [plugin, resource] //with the plugin being undefined if the name //did not have a plugin prefix. function splitPrefix(name) { var prefix, index = name ? name.indexOf('!') : -1; if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } return [prefix, name]; } //Creates a parts array for a relName where first part is plugin ID, //second part is resource ID. Assumes relName has already been normalized. function makeRelParts(relName) { return relName ? splitPrefix(relName) : []; } /** * Makes a name map, normalizing the name, and using a plugin * for normalization if necessary. Grabs a ref to plugin * too, as an optimization. */ makeMap = function (name, relParts) { var plugin, parts = splitPrefix(name), prefix = parts[0], relResourceName = relParts[1]; name = parts[1]; if (prefix) { prefix = normalize(prefix, relResourceName); plugin = callDep(prefix); } //Normalize according if (prefix) { if (plugin && plugin.normalize) { name = plugin.normalize(name, makeNormalize(relResourceName)); } else { name = normalize(name, relResourceName); } } else { name = normalize(name, relResourceName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; if (prefix) { plugin = callDep(prefix); } } //Using ridiculous property names for space reasons return { f: prefix ? prefix + '!' + name : name, //fullName n: name, pr: prefix, p: plugin }; }; function makeConfig(name) { return function () { return (config && config.config && config.config[name]) || {}; }; } handlers = { require: function (name) { return makeRequire(name); }, exports: function (name) { var e = defined[name]; if (typeof e !== 'undefined') { return e; } else { return (defined[name] = {}); } }, module: function (name) { return { id: name, uri: '', exports: defined[name], config: makeConfig(name) }; } }; main = function (name, deps, callback, relName) { var cjsModule, depName, ret, map, i, relParts, args = [], callbackType = typeof callback, usingExports; //Use name if no relName relName = relName || name; relParts = makeRelParts(relName); //Call the callback to define the module, if necessary. if (callbackType === 'undefined' || callbackType === 'function') { //Pull out the defined dependencies and pass the ordered //values to the callback. //Default to [require, exports, module] if no deps deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; for (i = 0; i < deps.length; i += 1) { map = makeMap(deps[i], relParts); depName = map.f; //Fast path CommonJS standard dependencies. if (depName === "require") { args[i] = handlers.require(name); } else if (depName === "exports") { //CommonJS module spec 1.1 args[i] = handlers.exports(name); usingExports = true; } else if (depName === "module") { //CommonJS module spec 1.1 cjsModule = args[i] = handlers.module(name); } else if (hasProp(defined, depName) || hasProp(waiting, depName) || hasProp(defining, depName)) { args[i] = callDep(depName); } else if (map.p) { map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); args[i] = defined[depName]; } else { throw new Error(name + ' missing ' + depName); } } ret = callback ? callback.apply(defined[name], args) : undefined; if (name) { //If setting exports via "module" is in play, //favor that over return value and exports. After that, //favor a non-undefined return value over exports use. if (cjsModule && cjsModule.exports !== undef && cjsModule.exports !== defined[name]) { defined[name] = cjsModule.exports; } else if (ret !== undef || !usingExports) { //Use the return value from the function. defined[name] = ret; } } } else if (name) { //May just be an object definition for the module. Only //worry about defining if have a module name. defined[name] = callback; } }; requirejs = require = req = function (deps, callback, relName, forceSync, alt) { if (typeof deps === "string") { if (handlers[deps]) { //callback in this case is really relName return handlers[deps](callback); } //Just return the module wanted. In this scenario, the //deps arg is the module name, and second arg (if passed) //is just the relName. //Normalize module name, if it contains . or .. return callDep(makeMap(deps, makeRelParts(callback)).f); } else if (!deps.splice) { //deps is a config object, not an array. config = deps; if (config.deps) { req(config.deps, config.callback); } if (!callback) { return; } if (callback.splice) { //callback is an array, which means it is a dependency list. //Adjust args if there are dependencies deps = callback; callback = relName; relName = null; } else { deps = undef; } } //Support require(['a']) callback = callback || function () {}; //If relName is a function, it is an errback handler, //so remove it. if (typeof relName === 'function') { relName = forceSync; forceSync = alt; } //Simulate async callback; if (forceSync) { main(undef, deps, callback, relName); } else { //Using a non-zero value because of concern for what old browsers //do, and latest browsers "upgrade" to 4 if lower value is used: //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: //If want a value immediately, use require('id') instead -- something //that works in almond on the global level, but not guaranteed and //unlikely to work in other AMD implementations. setTimeout(function () { main(undef, deps, callback, relName); }, 4); } return req; }; /** * Just drops the config on the floor, but returns req in case * the config return value is used. */ req.config = function (cfg) { return req(cfg); }; /** * Expose module registry for debugging and tooling */ requirejs._defined = defined; define = function (name, deps, callback) { if (typeof name !== 'string') { throw new Error('See almond README: incorrect module build, no module name'); } //This module may not have dependencies if (!deps.splice) { //deps is not an array, so probably means //an object literal or factory function for //the value. Adjust args. callback = deps; deps = []; } if (!hasProp(defined, name) && !hasProp(waiting, name)) { waiting[name] = [name, deps, callback]; } }; define.amd = { jQuery: true }; }()); define("../node_modules/almond/almond", function(){}); define('core/EventObject',[],() => { 'use strict'; return class EventObject { constructor() { this.listeners = new Map(); this.forwards = new Set(); } addEventListener(type, callback) { const l = this.listeners.get(type); if(l) { l.push(callback); } else { this.listeners.set(type, [callback]); } } removeEventListener(type, fn) { const l = this.listeners.get(type); if(!l) { return; } const i = l.indexOf(fn); if(i !== -1) { l.splice(i, 1); } } countEventListeners(type) { return (this.listeners.get(type) || []).length; } removeAllEventListeners(type) { if(type) { this.listeners.delete(type); } else { this.listeners.clear(); } } addEventForwarding(target) { this.forwards.add(target); } removeEventForwarding(target) { this.forwards.delete(target); } removeAllEventForwardings() { this.forwards.clear(); } trigger(type, params = []) { (this.listeners.get(type) || []).forEach( (listener) => listener.apply(null, params) ); this.forwards.forEach((fwd) => fwd.trigger(type, params)); } }; }); define('core/ArrayUtilities',[],() => { 'use strict'; function indexOf(list, element, equalityCheck = null) { if(equalityCheck === null) { return list.indexOf(element); } for(let i = 0; i < list.length; ++ i) { if(equalityCheck(list[i], element)) { return i; } } return -1; } function mergeSets(target, b = null, equalityCheck = null) { if(!b) { return; } for(let i = 0; i < b.length; ++ i) { if(indexOf(target, b[i], equalityCheck) === -1) { target.push(b[i]); } } } function hasIntersection(a, b, equalityCheck = null) { for(let i = 0; i < b.length; ++ i) { if(indexOf(a, b[i], equalityCheck) !== -1) { return true; } } return false; } function removeAll(target, b = null, equalityCheck = null) { if(!b) { return; } for(let i = 0; i < b.length; ++ i) { const p = indexOf(target, b[i], equalityCheck); if(p !== -1) { target.splice(p, 1); } } } function remove(list, item, equalityCheck = null) { const p = indexOf(list, item, equalityCheck); if(p !== -1) { list.splice(p, 1); } } function last(list) { return list[list.length - 1]; } function combineRecur(parts, position, current, target) { if(position >= parts.length) { target.push(current.slice()); return; } const choices = parts[position]; if(!Array.isArray(choices)) { current.push(choices); combineRecur(parts, position + 1, current, target); current.pop(); return; } for(let i = 0; i < choices.length; ++ i) { current.push(choices[i]); combineRecur(parts, position + 1, current, target); current.pop(); } } function combine(parts) { const target = []; combineRecur(parts, 0, [], target); return target; } function flatMap(list, fn) { const result = []; list.forEach((item) => { result.push(...fn(item)); }); return result; } return { indexOf, mergeSets, hasIntersection, removeAll, remove, last, combine, flatMap, }; }); define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => { 'use strict'; const CM_ERROR = {type: 'error line-error', then: {'': 0}}; const makeCommands = ((() => { // The order of commands inside "then" blocks directly influences the // order they are displayed to the user in autocomplete menus. // This relies on the fact that common JS engines maintain insertion // order in objects, though this is not guaranteed. It could be switched // to use Map objects instead for strict compliance, at the cost of // extra syntax. const end = {type: '', suggest: '\n', then: {}}; const hiddenEnd = {type: '', then: {}}; function textTo(exit) { return {type: 'string', then: Object.assign({'': 0}, exit)}; } const textToEnd = textTo({'\n': end}); const aliasListToEnd = {type: 'variable', suggest: 'Agent', then: { '': 0, '\n': end, ',': {type: 'operator', suggest: true, then: {'': 1}}, 'as': {type: 'keyword', suggest: true, then: { '': {type: 'variable', suggest: 'Agent', then: { '': 0, ',': {type: 'operator', suggest: true, then: {'': 3}}, '\n': end, }}, }}, }}; function agentListTo(exit) { return {type: 'variable', suggest: 'Agent', then: Object.assign({}, exit, { '': 0, ',': {type: 'operator', suggest: true, then: {'': 1}}, } )}; } const colonTextToEnd = { type: 'operator', suggest: true, then: {'': textToEnd, '\n': hiddenEnd}, }; const agentListToText = agentListTo({ ':': colonTextToEnd, }); const agentList2ToText = {type: 'variable', suggest: 'Agent', then: { '': 0, ',': {type: 'operator', suggest: true, then: {'': agentListToText}}, ':': CM_ERROR, }}; const singleAgentToText = {type: 'variable', suggest: 'Agent', then: { '': 0, ',': CM_ERROR, ':': colonTextToEnd, }}; const agentToOptText = {type: 'variable', suggest: 'Agent', then: { '': 0, ':': {type: 'operator', suggest: true, then: { '': textToEnd, '\n': hiddenEnd, }}, '\n': end, }}; const referenceName = { ':': {type: 'operator', suggest: true, then: { '': textTo({ 'as': {type: 'keyword', suggest: true, then: { '': {type: 'variable', suggest: 'Agent', then: { '': 0, '\n': end, }}, }}, }), }}, }; const refDef = {type: 'keyword', suggest: true, then: Object.assign({ 'over': {type: 'keyword', suggest: true, then: { '': agentListTo(referenceName), }}, }, referenceName)}; function makeSideNote(side) { return { type: 'keyword', suggest: [side + ' of ', side + ': '], then: { 'of': {type: 'keyword', suggest: true, then: { '': agentListToText, }}, ':': {type: 'operator', suggest: true, then: { '': textToEnd, }}, '': agentListToText, }, }; } function makeOpBlock(exit, sourceExit) { const op = {type: 'operator', suggest: true, then: { '+': CM_ERROR, '-': CM_ERROR, '*': CM_ERROR, '!': CM_ERROR, '': exit, }}; return { '+': {type: 'operator', suggest: true, then: { '+': CM_ERROR, '-': CM_ERROR, '*': op, '!': CM_ERROR, '': exit, }}, '-': {type: 'operator', suggest: true, then: { '+': CM_ERROR, '-': CM_ERROR, '*': op, '!': {type: 'operator', then: { '+': CM_ERROR, '-': CM_ERROR, '*': CM_ERROR, '!': CM_ERROR, '': exit, }}, '': exit, }}, '*': {type: 'operator', suggest: true, then: Object.assign({ '+': op, '-': op, '*': CM_ERROR, '!': CM_ERROR, '': exit, }, sourceExit)}, '!': op, '': exit, }; } function makeCMConnect(arrows) { const connect = { type: 'keyword', suggest: true, then: makeOpBlock(agentToOptText, { ':': colonTextToEnd, '\n': hiddenEnd, }), }; const then = {'': 0}; arrows.forEach((arrow) => (then[arrow] = connect)); then[':'] = { type: 'operator', suggest: true, override: 'Label', then: {}, }; return makeOpBlock( {type: 'variable', suggest: 'Agent', then}, then ); } const BASE_THEN = { 'title': {type: 'keyword', suggest: true, then: { '': textToEnd, }}, 'theme': {type: 'keyword', suggest: true, then: { '': { type: 'string', suggest: { global: 'themes', suffix: '\n', }, then: { '': 0, '\n': end, }, }, }}, 'headers': {type: 'keyword', suggest: true, then: { 'none': {type: 'keyword', suggest: true, then: {}}, 'cross': {type: 'keyword', suggest: true, then: {}}, 'box': {type: 'keyword', suggest: true, then: {}}, 'fade': {type: 'keyword', suggest: true, then: {}}, 'bar': {type: 'keyword', suggest: true, then: {}}, }}, 'terminators': {type: 'keyword', suggest: true, then: { 'none': {type: 'keyword', suggest: true, then: {}}, 'cross': {type: 'keyword', suggest: true, then: {}}, 'box': {type: 'keyword', suggest: true, then: {}}, 'fade': {type: 'keyword', suggest: true, then: {}}, 'bar': {type: 'keyword', suggest: true, then: {}}, }}, 'define': {type: 'keyword', suggest: true, then: { '': aliasListToEnd, 'as': CM_ERROR, }}, 'begin': {type: 'keyword', suggest: true, then: { '': aliasListToEnd, 'reference': refDef, 'as': CM_ERROR, }}, 'end': {type: 'keyword', suggest: true, then: { '': aliasListToEnd, 'as': CM_ERROR, '\n': end, }}, 'if': {type: 'keyword', suggest: true, then: { '': textToEnd, ':': {type: 'operator', suggest: true, then: { '': textToEnd, }}, '\n': end, }}, 'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: { 'if': {type: 'keyword', suggest: 'if: ', then: { '': textToEnd, ':': {type: 'operator', suggest: true, then: { '': textToEnd, }}, }}, '\n': end, }}, 'repeat': {type: 'keyword', suggest: true, then: { '': textToEnd, ':': {type: 'operator', suggest: true, then: { '': textToEnd, }}, '\n': end, }}, 'note': {type: 'keyword', suggest: true, then: { 'over': {type: 'keyword', suggest: true, then: { '': agentListToText, }}, 'left': makeSideNote('left'), 'right': makeSideNote('right'), 'between': {type: 'keyword', suggest: true, then: { '': agentList2ToText, }}, }}, 'state': {type: 'keyword', suggest: 'state over ', then: { 'over': {type: 'keyword', suggest: true, then: { '': singleAgentToText, }}, }}, 'text': {type: 'keyword', suggest: true, then: { 'left': makeSideNote('left'), 'right': makeSideNote('right'), }}, 'autolabel': {type: 'keyword', suggest: true, then: { 'off': {type: 'keyword', suggest: true, then: {}}, '': textToEnd, }}, 'simultaneously': {type: 'keyword', suggest: true, then: { ':': {type: 'operator', suggest: true, then: {}}, 'with': {type: 'keyword', suggest: true, then: { '': {type: 'variable', suggest: 'Label', then: { '': 0, ':': {type: 'operator', suggest: true, then: {}}, }}, }}, }}, }; return (arrows) => { return { type: 'error line-error', then: Object.assign({}, BASE_THEN, makeCMConnect(arrows)), }; }; })()); function cmCappedToken(token, current) { if(Object.keys(current.then).length > 0) { return token + ' '; } else { return token + '\n'; } } function cmGetVarSuggestions(state, previous, current) { if(typeof current.suggest === 'object' && current.suggest.global) { return [current.suggest]; } if( typeof current.suggest !== 'string' || previous.suggest === current.suggest ) { return null; } return state['known' + current.suggest]; } function cmGetSuggestions(state, token, previous, current) { if(token === '') { return cmGetVarSuggestions(state, previous, current); } else if(current.suggest === true) { return [cmCappedToken(token, current)]; } else if(Array.isArray(current.suggest)) { return current.suggest; } else if(current.suggest) { return [current.suggest]; } else { return null; } } function cmMakeCompletions(state, path) { const comp = []; const current = array.last(path); Object.keys(current.then).forEach((token) => { let next = current.then[token]; if(typeof next === 'number') { next = path[path.length - next - 1]; } array.mergeSets( comp, cmGetSuggestions(state, token, current, next) ); }); return comp; } function updateSuggestion(state, locals, token, {suggest, override}) { if(locals.type) { if(suggest !== locals.type) { if(override) { locals.type = override; } array.mergeSets( state['known' + locals.type], [locals.value + ' '] ); locals.type = ''; locals.value = ''; } } if(typeof suggest === 'string' && state['known' + suggest]) { locals.type = suggest; if(locals.value) { locals.value += token.s; } locals.value += token.v; } } function cmCheckToken(state, eol, commands) { const suggestions = { type: '', value: '', }; let current = commands; const path = [current]; state.line.forEach((token, i) => { if(i === state.line.length - 1) { state.completions = cmMakeCompletions(state, path); } const keywordToken = token.q ? '' : token.v; const found = current.then[keywordToken] || current.then['']; if(typeof found === 'number') { path.length -= found; } else { path.push(found || CM_ERROR); } current = array.last(path); updateSuggestion(state, suggestions, token, current); }); if(eol) { updateSuggestion(state, suggestions, null, {}); } state.nextCompletions = cmMakeCompletions(state, path); state.valid = ( Boolean(current.then['\n']) || Object.keys(current.then).length === 0 ); return current.type; } function getInitialToken(block) { const baseToken = (block.baseToken || {}); return { value: baseToken.v || '', quoted: baseToken.q || false, }; } return class Mode { constructor(tokenDefinitions, arrows) { this.tokenDefinitions = tokenDefinitions; this.commands = makeCommands(arrows); this.lineComment = '#'; } startState() { return { currentType: -1, current: '', currentSpace: '', currentQuoted: false, knownAgent: [], knownLabel: [], beginCompletions: cmMakeCompletions({}, [this.commands]), completions: [], nextCompletions: [], valid: true, line: [], indent: 0, }; } _matchPattern(stream, pattern, consume) { if(!pattern) { return null; } pattern.lastIndex = 0; return stream.match(pattern, consume); } _tokenBegin(stream, state) { state.currentSpace = ''; let lastChar = ''; while(true) { if(stream.eol()) { return false; } state.currentSpace += lastChar; for(let i = 0; i < this.tokenDefinitions.length; ++ i) { const block = this.tokenDefinitions[i]; if(this._matchPattern(stream, block.start, true)) { state.currentType = i; const {value, quoted} = getInitialToken(block); state.current = value; state.currentQuoted = quoted; return true; } } lastChar = stream.next(); } } _tokenCheckEscape(stream, state, block) { const match = this._matchPattern(stream, block.escape, true); if(match) { state.current += block.escapeWith(match); } } _addToken(state) { state.line.push({ v: state.current, s: state.currentSpace, q: state.currentQuoted, }); } _tokenEndFound(stream, state, block, match) { state.currentType = -1; if(block.includeEnd) { state.current += match[0]; } if(block.omit) { return 'comment'; } this._addToken(state); return cmCheckToken(state, stream.eol(), this.commands); } _tokenEOLFound(stream, state, block) { state.current += '\n'; if(block.omit) { return 'comment'; } this._addToken(state); const type = cmCheckToken(state, false, this.commands); state.line.pop(); return type; } _tokenEnd(stream, state) { while(true) { const block = this.tokenDefinitions[state.currentType]; this._tokenCheckEscape(stream, state, block); if(!block.end) { return this._tokenEndFound(stream, state, block, null); } else { const match = this._matchPattern(stream, block.end, true); if(match) { return this._tokenEndFound(stream, state, block, match); } } if(stream.eol()) { return this._tokenEOLFound(stream, state, block); } state.current += stream.next(); } } token(stream, state) { state.completions = state.nextCompletions; if(stream.sol() && state.currentType === -1) { state.line.length = 0; } let type = ''; if(state.currentType !== -1 || this._tokenBegin(stream, state)) { type = this._tokenEnd(stream, state); } if(state.currentType === -1 && stream.eol() && !state.valid) { return 'line-error ' + type; } else { return type; } } indent(state) { return state.indent; } }; }); define('sequence/Tokeniser',['./CodeMirrorMode'], (CMMode) => { 'use strict'; function execAt(str, reg, i) { reg.lastIndex = i; return reg.exec(str); } function unescape(match) { const c = match[1]; if(c === 'n') { return '\n'; } return match[1]; } const TOKENS = [ {start: /#/y, end: /(?=\n)|$/y, omit: true}, { start: /"/y, end: /"/y, escape: /\\(.)/y, escapeWith: unescape, baseToken: {q: true}, }, { start: /'/y, end: /'/y, escape: /\\(.)/y, escapeWith: unescape, baseToken: {q: true}, }, {start: /(?=[^ \t\r\n:+\-~*!<>,])/y, end: /(?=[ \t\r\n:+\-~*!<>,])|$/y}, { start: /(?=[\-~<])/y, end: /(?=[^\-~<>x])|[\-~]x|[<>](?=x)|$/y, includeEnd: true, }, {start: /,/y, baseToken: {v: ','}}, {start: /:/y, baseToken: {v: ':'}}, {start: /!/y, baseToken: {v: '!'}}, {start: /\+/y, baseToken: {v: '+'}}, {start: /\*/y, baseToken: {v: '*'}}, {start: /\n/y, baseToken: {v: '\n'}}, ]; function tokFindBegin(src, i) { for(let j = 0; j < TOKENS.length; ++ j) { const block = TOKENS[j]; const match = execAt(src, block.start, i); if(match) { return { newBlock: block, end: !block.end, appendSpace: '', appendValue: '', skip: match[0].length, }; } } return { newBlock: null, end: false, appendSpace: src[i], appendValue: '', skip: 1, }; } function tokContinuePart(src, i, block) { if(block.escape) { const match = execAt(src, block.escape, i); if(match) { return { newBlock: null, end: false, appendSpace: '', appendValue: block.escapeWith(match), skip: match[0].length, }; } } const match = execAt(src, block.end, i); if(match) { return { newBlock: null, end: true, appendSpace: '', appendValue: block.includeEnd ? match[0] : '', skip: match[0].length, }; } return { newBlock: null, end: false, appendSpace: '', appendValue: src[i], skip: 1, }; } function tokAdvance(src, i, block) { if(block) { return tokContinuePart(src, i, block); } else { return tokFindBegin(src, i); } } function copyPos(pos) { return {i: pos.i, ln: pos.ln, ch: pos.ch}; } function advancePos(pos, src, steps) { for(let i = 0; i < steps; ++ i) { ++ pos.ch; if(src[pos.i + i] === '\n') { ++ pos.ln; pos.ch = 0; } } pos.i += steps; } class TokenState { constructor(src) { this.src = src; this.block = null; this.token = null; this.pos = {i: 0, ln: 0, ch: 0}; this.reset(); } isOver() { return this.pos.i > this.src.length; } reset() { this.token = {s: '', v: '', q: false, b: null, e: null}; this.block = null; } beginToken(advance) { this.block = advance.newBlock; Object.assign(this.token, this.block.baseToken); this.token.b = copyPos(this.pos); } endToken() { let token = null; if(!this.block.omit) { this.token.e = copyPos(this.pos); token = this.token; } this.reset(); return token; } advance() { const advance = tokAdvance(this.src, this.pos.i, this.block); if(advance.newBlock) { this.beginToken(advance); } this.token.s += advance.appendSpace; this.token.v += advance.appendValue; advancePos(this.pos, this.src, advance.skip); if(advance.end) { return this.endToken(); } else { return null; } } } function posStr(pos) { return 'line ' + (pos.ln + 1) + ', character ' + pos.ch; } return class Tokeniser { tokenise(src) { const tokens = []; const state = new TokenState(src); while(!state.isOver()) { const token = state.advance(); if(token) { tokens.push(token); } } if(state.block) { throw new Error( 'Unterminated literal (began at ' + posStr(state.token.b) + ')' ); } return tokens; } getCodeMirrorMode(arrows) { return new CMMode(TOKENS, arrows); } splitLines(tokens) { const lines = []; let line = []; tokens.forEach((token) => { if(!token.q && token.v === '\n') { if(line.length > 0) { lines.push(line); line = []; } } else { line.push(token); } }); if(line.length > 0) { lines.push(line); } return lines; } }; }); define('sequence/MarkdownParser',[],() => { 'use strict'; const STYLES = [ { begin: /[\s_~`]\*(?=\S)/g, end: /\S\*(?=[\s_~`])/g, attrs: {'font-style': 'italic'}, }, { begin: /[\s*~`]_(?=\S)/g, end: /\S_(?=[\s*~`])/g, attrs: {'font-style': 'italic'}, }, { begin: /[\s_~`]\*\*(?=\S)/g, end: /\S\*\*(?=[\s_~`])/g, attrs: {'font-weight': 'bolder'}, }, { begin: /[\s*~`]__(?=\S)/g, end: /\S__(?=[\s*~`])/g, attrs: {'font-weight': 'bolder'}, }, { begin: /[\s_*`]~(?=\S)/g, end: /\S~(?=[\s_*`])/g, attrs: {'text-decoration': 'line-through'}, }, { begin: /[\s_*~.]`(?=\S)/g, end: /\S`(?=[\s_*~.])/g, attrs: {'font-family': 'monospace'}, }, ]; function findNext(line, p, active) { const virtLine = ' ' + line + ' '; let styleIndex = -1; let bestStart = virtLine.length; let bestEnd = 0; STYLES.forEach(({begin, end, attrs}, ind) => { const search = active[ind] ? end : begin; search.lastIndex = p; const m = search.exec(virtLine); if(m && ( m.index < bestStart || (m.index === bestStart && search.lastIndex > bestEnd) )) { styleIndex = ind; bestStart = m.index; bestEnd = search.lastIndex; } }); return {styleIndex, start: bestStart, end: bestEnd - 1}; } function combineAttrs(activeCount, active) { if(!activeCount) { return null; } const attrs = {}; active.forEach((on, ind) => { if(on) { Object.assign(attrs, STYLES[ind].attrs); } }); return attrs; } function parseMarkdown(text) { if(!text) { return []; } const active = STYLES.map(() => false); let activeCount = 0; let attrs = null; const lines = text.split('\n'); const result = []; lines.forEach((line) => { const parts = []; let p = 0; while(true) { const {styleIndex, start, end} = findNext(line, p, active); if(styleIndex === -1) { break; } if(active[styleIndex]) { active[styleIndex] = false; -- activeCount; } else { active[styleIndex] = true; ++ activeCount; } if(start > p) { parts.push({text: line.substring(p, start), attrs}); } attrs = combineAttrs(activeCount, active); p = end; } if(p < line.length) { parts.push({text: line.substr(p), attrs}); } result.push(parts); }); return result; } return parseMarkdown; }); define('sequence/LabelPatternParser',[],() => { 'use strict'; const LABEL_PATTERN = /(.*?)<([^<>]*)>/g; const DP_PATTERN = /\.([0-9]*)/; function countDP(value) { const match = DP_PATTERN.exec(value); if(!match || !match[1]) { return 0; } return match[1].length; } function parseCounter(args) { let start = 1; let inc = 1; let dp = 0; if(args[0]) { start = Number(args[0]); dp = Math.max(dp, countDP(args[0])); } if(args[1]) { inc = Number(args[1]); dp = Math.max(dp, countDP(args[1])); } return {start, inc, dp}; } function parseToken(token) { if(token === 'label') { return {token: 'label'}; } const p = token.indexOf(' '); let type = null; let args = null; if(p === -1) { type = token; args = []; } else { type = token.substr(0, p); args = token.substr(p + 1).split(','); } if(type === 'inc') { return parseCounter(args); } return '<' + token + '>'; } function parsePattern(raw) { const pattern = []; let match = null; let end = 0; LABEL_PATTERN.lastIndex = 0; while((match = LABEL_PATTERN.exec(raw))) { if(match[1]) { pattern.push(match[1]); } if(match[2]) { pattern.push(parseToken(match[2])); } end = LABEL_PATTERN.lastIndex; } const remainder = raw.substr(end); if(remainder) { pattern.push(remainder); } return pattern; } return parsePattern; }); define('sequence/Parser',[ 'core/ArrayUtilities', './Tokeniser', './MarkdownParser', './LabelPatternParser', ], ( array, Tokeniser, markdownParser, labelPatternParser ) => { 'use strict'; const BLOCK_TYPES = { 'if': { type: 'block begin', blockType: 'if', tag: 'if', skip: [], }, 'else': { type: 'block split', blockType: 'else', tag: 'else', skip: ['if'], }, 'repeat': { type: 'block begin', blockType: 'repeat', tag: 'repeat', skip: [], }, }; const CONNECT_TYPES = ((() => { const lTypes = [ {tok: '', type: 0}, {tok: '<', type: 1}, {tok: '<<', type: 2}, ]; const mTypes = [ {tok: '-', type: 'solid'}, {tok: '--', type: 'dash'}, {tok: '~', type: 'wave'}, ]; const rTypes = [ {tok: '', type: 0}, {tok: '>', type: 1}, {tok: '>>', type: 2}, {tok: 'x', type: 3}, ]; const arrows = (array.combine([lTypes, mTypes, rTypes]) .filter((arrow) => (arrow[0].type !== 0 || arrow[2].type !== 0)) ); const types = new Map(); arrows.forEach((arrow) => { types.set(arrow.map((part) => part.tok).join(''), { line: arrow[1].type, left: arrow[0].type, right: arrow[2].type, }); }); return types; })()); const CONNECT_AGENT_FLAGS = { '*': {flag: 'begin', allowBlankName: true, blankNameFlag: 'source'}, '+': {flag: 'start'}, '-': {flag: 'stop'}, '!': {flag: 'end'}, }; const TERMINATOR_TYPES = [ 'none', 'box', 'cross', 'fade', 'bar', ]; const NOTE_TYPES = { 'text': { mode: 'text', types: { 'left': {type: 'note left', skip: ['of'], min: 0, max: null}, 'right': {type: 'note right', skip: ['of'], min: 0, max: null}, }, }, 'note': { mode: 'note', types: { 'over': {type: 'note over', skip: [], min: 0, max: null}, 'left': {type: 'note left', skip: ['of'], min: 0, max: null}, 'right': {type: 'note right', skip: ['of'], min: 0, max: null}, 'between': {type: 'note between', skip: [], min: 2, max: null}, }, }, 'state': { mode: 'state', types: { 'over': {type: 'note over', skip: [], min: 1, max: 1}, }, }, }; const AGENT_MANIPULATION_TYPES = { 'define': {type: 'agent define'}, 'begin': {type: 'agent begin', mode: 'box'}, 'end': {type: 'agent end', mode: 'cross'}, }; function makeError(message, token = null) { let suffix = ''; if(token) { suffix = ( ' at line ' + (token.b.ln + 1) + ', character ' + token.b.ch ); } return new Error(message + suffix); } function errToken(line, pos) { if(pos < line.length) { return line[pos]; } const last = array.last(line); if(!last) { return null; } return {b: last.e}; } function joinLabel(line, begin = 0, end = null) { if(end === null) { end = line.length; } if(end <= begin) { return ''; } let result = line[begin].v; for(let i = begin + 1; i < end; ++ i) { result += line[i].s + line[i].v; } return result; } function tokenKeyword(token) { if(!token || token.q) { return null; } return token.v; } function skipOver(line, start, skip, error = null) { for(let i = 0; i < skip.length; ++ i) { const expected = skip[i]; const token = line[start + i]; if(tokenKeyword(token) !== expected) { if(error) { throw makeError( error + '; expected "' + expected + '"', token ); } else { return start; } } } return start + skip.length; } function findToken(line, token, start = 0) { for(let i = start; i < line.length; ++ i) { if(tokenKeyword(line[i]) === token) { return i; } } return -1; } function readAgentAlias(line, start, end, {enableAlias, allowBlankName}) { let aliasSep = -1; if(enableAlias) { aliasSep = findToken(line, 'as', start); } if(aliasSep === -1 || aliasSep >= end) { aliasSep = end; } if(start >= aliasSep && !allowBlankName) { throw makeError('Missing agent name', errToken(line, start)); } return { name: joinLabel(line, start, aliasSep), alias: joinLabel(line, aliasSep + 1, end), }; } function readAgent(line, start, end, { flagTypes = {}, aliases = false, } = {}) { const flags = []; const blankNameFlags = []; let p = start; let allowBlankName = false; for(; p < end; ++ p) { const token = line[p]; const rawFlag = tokenKeyword(token); const flag = flagTypes[rawFlag]; if(!flag) { break; } if(flags.includes(flag.flag)) { throw makeError('Duplicate agent flag: ' + rawFlag, token); } allowBlankName = allowBlankName || Boolean(flag.allowBlankName); flags.push(flag.flag); blankNameFlags.push(flag.blankNameFlag); } const {name, alias} = readAgentAlias(line, p, end, { enableAlias: aliases, allowBlankName, }); return { name, alias, flags: name ? flags : blankNameFlags, }; } function readAgentList(line, start, end, readAgentOpts) { const list = []; let currentStart = -1; for(let i = start; i < end; ++ i) { const token = line[i]; if(tokenKeyword(token) === ',') { if(currentStart !== -1) { list.push(readAgent(line, currentStart, i, readAgentOpts)); currentStart = -1; } } else if(currentStart === -1) { currentStart = i; } } if(currentStart !== -1) { list.push(readAgent(line, currentStart, end, readAgentOpts)); } return list; } const PARSERS = [ (line, meta) => { // title if(tokenKeyword(line[0]) !== 'title') { return null; } meta.title = joinLabel(line, 1); return true; }, (line, meta) => { // theme if(tokenKeyword(line[0]) !== 'theme') { return null; } meta.theme = joinLabel(line, 1); return true; }, (line, meta) => { // terminators if(tokenKeyword(line[0]) !== 'terminators') { return null; } const type = tokenKeyword(line[1]); if(!type) { throw makeError('Unspecified termination', line[0]); } if(TERMINATOR_TYPES.indexOf(type) === -1) { throw makeError('Unknown termination "' + type + '"', line[1]); } meta.terminators = type; return true; }, (line, meta) => { // headers if(tokenKeyword(line[0]) !== 'headers') { return null; } const type = tokenKeyword(line[1]); if(!type) { throw makeError('Unspecified header', line[0]); } if(TERMINATOR_TYPES.indexOf(type) === -1) { throw makeError('Unknown header "' + type + '"', line[1]); } meta.headers = type; return true; }, (line) => { // autolabel if(tokenKeyword(line[0]) !== 'autolabel') { return null; } let raw = null; if(tokenKeyword(line[1]) === 'off') { raw = '