1/** js sequence diagrams 2.0.1
2 *  https://bramp.github.io/js-sequence-diagrams/
3 *  (c) 2012-2017 Andrew Brampton (bramp.net)
4 *  @license Simplified BSD license.
5 */
6(function() {
7'use strict';
8/*global Diagram */
9
10// The following are included by preprocessor */
11/** js sequence diagrams
12 *  https://bramp.github.io/js-sequence-diagrams/
13 *  (c) 2012-2017 Andrew Brampton (bramp.net)
14 *  Simplified BSD license.
15 */
16/*global grammar _ */
17
18function Diagram() {
19  this.title   = undefined;
20  this.actors  = [];
21  this.signals = [];
22}
23/*
24 * Return an existing actor with this alias, or creates a new one with alias and name.
25 */
26Diagram.prototype.getActor = function(alias, name) {
27  alias = alias.trim();
28
29  var i;
30  var actors = this.actors;
31  for (i in actors) {
32    if (actors[i].alias == alias) {
33      return actors[i];
34    }
35  }
36  i = actors.push(new Diagram.Actor(alias, (name || alias), actors.length));
37  return actors[ i - 1 ];
38};
39
40/*
41 * Parses the input as either a alias, or a "name as alias", and returns the corresponding actor.
42 */
43Diagram.prototype.getActorWithAlias = function(input) {
44  input = input.trim();
45
46  // We are lazy and do some of the parsing in javascript :(. TODO move into the .jison file.
47  var s = /([\s\S]+) as (\S+)$/im.exec(input);
48  var alias;
49  var name;
50  if (s) {
51    name  = s[1].trim();
52    alias = s[2].trim();
53  } else {
54    name = alias = input;
55  }
56  return this.getActor(alias, name);
57};
58
59Diagram.prototype.setTitle = function(title) {
60  this.title = title;
61};
62
63Diagram.prototype.addSignal = function(signal) {
64  this.signals.push(signal);
65};
66
67Diagram.Actor = function(alias, name, index) {
68  this.alias = alias;
69  this.name  = name;
70  this.index = index;
71};
72
73Diagram.Signal = function(actorA, signaltype, actorB, message) {
74  this.type       = 'Signal';
75  this.actorA     = actorA;
76  this.actorB     = actorB;
77  this.linetype   = signaltype & 3;
78  this.arrowtype  = (signaltype >> 2) & 3;
79  this.message    = message;
80};
81
82Diagram.Signal.prototype.isSelf = function() {
83  return this.actorA.index == this.actorB.index;
84};
85
86Diagram.Note = function(actor, placement, message) {
87  this.type      = 'Note';
88  this.actor     = actor;
89  this.placement = placement;
90  this.message   = message;
91
92  if (this.hasManyActors() && actor[0] == actor[1]) {
93    throw new Error('Note should be over two different actors');
94  }
95};
96
97Diagram.Note.prototype.hasManyActors = function() {
98  return _.isArray(this.actor);
99};
100
101Diagram.unescape = function(s) {
102  // Turn "\\n" into "\n"
103  return s.trim().replace(/^"(.*)"$/m, '$1').replace(/\\n/gm, '\n');
104};
105
106Diagram.LINETYPE = {
107  SOLID: 0,
108  DOTTED: 1
109};
110
111Diagram.ARROWTYPE = {
112  FILLED: 0,
113  OPEN: 1
114};
115
116Diagram.PLACEMENT = {
117  LEFTOF: 0,
118  RIGHTOF: 1,
119  OVER: 2
120};
121
122// Some older browsers don't have getPrototypeOf, thus we polyfill it
123// https://github.com/bramp/js-sequence-diagrams/issues/57
124// https://github.com/zaach/jison/issues/194
125// Taken from http://ejohn.org/blog/objectgetprototypeof/
126if (typeof Object.getPrototypeOf !== 'function') {
127  /* jshint -W103 */
128  if (typeof 'test'.__proto__ === 'object') {
129    Object.getPrototypeOf = function(object) {
130      return object.__proto__;
131    };
132  } else {
133    Object.getPrototypeOf = function(object) {
134      // May break if the constructor has been tampered with
135      return object.constructor.prototype;
136    };
137  }
138  /* jshint +W103 */
139}
140
141/** The following is included by preprocessor */
142/* parser generated by jison 0.4.15 */
143/*
144  Returns a Parser object of the following structure:
145
146  Parser: {
147    yy: {}
148  }
149
150  Parser.prototype: {
151    yy: {},
152    trace: function(),
153    symbols_: {associative list: name ==> number},
154    terminals_: {associative list: number ==> name},
155    productions_: [...],
156    performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
157    table: [...],
158    defaultActions: {...},
159    parseError: function(str, hash),
160    parse: function(input),
161
162    lexer: {
163        EOF: 1,
164        parseError: function(str, hash),
165        setInput: function(input),
166        input: function(),
167        unput: function(str),
168        more: function(),
169        less: function(n),
170        pastInput: function(),
171        upcomingInput: function(),
172        showPosition: function(),
173        test_match: function(regex_match_array, rule_index),
174        next: function(),
175        lex: function(),
176        begin: function(condition),
177        popState: function(),
178        _currentRules: function(),
179        topState: function(),
180        pushState: function(condition),
181
182        options: {
183            ranges: boolean           (optional: true ==> token location info will include a .range[] member)
184            flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
185            backtrack_lexer: boolean  (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
186        },
187
188        performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
189        rules: [...],
190        conditions: {associative list: name ==> set},
191    }
192  }
193
194
195  token location info (@$, _$, etc.): {
196    first_line: n,
197    last_line: n,
198    first_column: n,
199    last_column: n,
200    range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
201  }
202
203
204  the parseError function receives a 'hash' object with these members for lexer and parser errors: {
205    text:        (matched text)
206    token:       (the produced terminal token, if any)
207    line:        (yylineno)
208  }
209  while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
210    loc:         (yylloc)
211    expected:    (string describing the set of expected tokens)
212    recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
213  }
214*/
215var parser = function() {
216    function Parser() {
217        this.yy = {};
218    }
219    var o = function(k, v, o, l) {
220        for (o = o || {}, l = k.length; l--; o[k[l]] = v) ;
221        return o;
222    }, $V0 = [ 5, 8, 9, 13, 15, 24 ], $V1 = [ 1, 13 ], $V2 = [ 1, 17 ], $V3 = [ 24, 29, 30 ], parser = {
223        trace: function() {},
224        yy: {},
225        symbols_: {
226            error: 2,
227            start: 3,
228            document: 4,
229            EOF: 5,
230            line: 6,
231            statement: 7,
232            NL: 8,
233            participant: 9,
234            actor_alias: 10,
235            signal: 11,
236            note_statement: 12,
237            title: 13,
238            message: 14,
239            note: 15,
240            placement: 16,
241            actor: 17,
242            over: 18,
243            actor_pair: 19,
244            ",": 20,
245            left_of: 21,
246            right_of: 22,
247            signaltype: 23,
248            ACTOR: 24,
249            linetype: 25,
250            arrowtype: 26,
251            LINE: 27,
252            DOTLINE: 28,
253            ARROW: 29,
254            OPENARROW: 30,
255            MESSAGE: 31,
256            $accept: 0,
257            $end: 1
258        },
259        terminals_: {
260            2: "error",
261            5: "EOF",
262            8: "NL",
263            9: "participant",
264            13: "title",
265            15: "note",
266            18: "over",
267            20: ",",
268            21: "left_of",
269            22: "right_of",
270            24: "ACTOR",
271            27: "LINE",
272            28: "DOTLINE",
273            29: "ARROW",
274            30: "OPENARROW",
275            31: "MESSAGE"
276        },
277        productions_: [ 0, [ 3, 2 ], [ 4, 0 ], [ 4, 2 ], [ 6, 1 ], [ 6, 1 ], [ 7, 2 ], [ 7, 1 ], [ 7, 1 ], [ 7, 2 ], [ 12, 4 ], [ 12, 4 ], [ 19, 1 ], [ 19, 3 ], [ 16, 1 ], [ 16, 1 ], [ 11, 4 ], [ 17, 1 ], [ 10, 1 ], [ 23, 2 ], [ 23, 1 ], [ 25, 1 ], [ 25, 1 ], [ 26, 1 ], [ 26, 1 ], [ 14, 1 ] ],
278        performAction: function(yytext, yyleng, yylineno, yy, yystate, $$, _$) {
279            /* this == yyval */
280            var $0 = $$.length - 1;
281            switch (yystate) {
282              case 1:
283                return yy.parser.yy;
284
285              case 4:
286                break;
287
288              case 6:
289                $$[$0];
290                break;
291
292              case 7:
293              case 8:
294                yy.parser.yy.addSignal($$[$0]);
295                break;
296
297              case 9:
298                yy.parser.yy.setTitle($$[$0]);
299                break;
300
301              case 10:
302                this.$ = new Diagram.Note($$[$0 - 1], $$[$0 - 2], $$[$0]);
303                break;
304
305              case 11:
306                this.$ = new Diagram.Note($$[$0 - 1], Diagram.PLACEMENT.OVER, $$[$0]);
307                break;
308
309              case 12:
310              case 20:
311                this.$ = $$[$0];
312                break;
313
314              case 13:
315                this.$ = [ $$[$0 - 2], $$[$0] ];
316                break;
317
318              case 14:
319                this.$ = Diagram.PLACEMENT.LEFTOF;
320                break;
321
322              case 15:
323                this.$ = Diagram.PLACEMENT.RIGHTOF;
324                break;
325
326              case 16:
327                this.$ = new Diagram.Signal($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0]);
328                break;
329
330              case 17:
331                this.$ = yy.parser.yy.getActor(Diagram.unescape($$[$0]));
332                break;
333
334              case 18:
335                this.$ = yy.parser.yy.getActorWithAlias(Diagram.unescape($$[$0]));
336                break;
337
338              case 19:
339                this.$ = $$[$0 - 1] | $$[$0] << 2;
340                break;
341
342              case 21:
343                this.$ = Diagram.LINETYPE.SOLID;
344                break;
345
346              case 22:
347                this.$ = Diagram.LINETYPE.DOTTED;
348                break;
349
350              case 23:
351                this.$ = Diagram.ARROWTYPE.FILLED;
352                break;
353
354              case 24:
355                this.$ = Diagram.ARROWTYPE.OPEN;
356                break;
357
358              case 25:
359                this.$ = Diagram.unescape($$[$0].substring(1));
360            }
361        },
362        table: [ o($V0, [ 2, 2 ], {
363            3: 1,
364            4: 2
365        }), {
366            1: [ 3 ]
367        }, {
368            5: [ 1, 3 ],
369            6: 4,
370            7: 5,
371            8: [ 1, 6 ],
372            9: [ 1, 7 ],
373            11: 8,
374            12: 9,
375            13: [ 1, 10 ],
376            15: [ 1, 12 ],
377            17: 11,
378            24: $V1
379        }, {
380            1: [ 2, 1 ]
381        }, o($V0, [ 2, 3 ]), o($V0, [ 2, 4 ]), o($V0, [ 2, 5 ]), {
382            10: 14,
383            24: [ 1, 15 ]
384        }, o($V0, [ 2, 7 ]), o($V0, [ 2, 8 ]), {
385            14: 16,
386            31: $V2
387        }, {
388            23: 18,
389            25: 19,
390            27: [ 1, 20 ],
391            28: [ 1, 21 ]
392        }, {
393            16: 22,
394            18: [ 1, 23 ],
395            21: [ 1, 24 ],
396            22: [ 1, 25 ]
397        }, o([ 20, 27, 28, 31 ], [ 2, 17 ]), o($V0, [ 2, 6 ]), o($V0, [ 2, 18 ]), o($V0, [ 2, 9 ]), o($V0, [ 2, 25 ]), {
398            17: 26,
399            24: $V1
400        }, {
401            24: [ 2, 20 ],
402            26: 27,
403            29: [ 1, 28 ],
404            30: [ 1, 29 ]
405        }, o($V3, [ 2, 21 ]), o($V3, [ 2, 22 ]), {
406            17: 30,
407            24: $V1
408        }, {
409            17: 32,
410            19: 31,
411            24: $V1
412        }, {
413            24: [ 2, 14 ]
414        }, {
415            24: [ 2, 15 ]
416        }, {
417            14: 33,
418            31: $V2
419        }, {
420            24: [ 2, 19 ]
421        }, {
422            24: [ 2, 23 ]
423        }, {
424            24: [ 2, 24 ]
425        }, {
426            14: 34,
427            31: $V2
428        }, {
429            14: 35,
430            31: $V2
431        }, {
432            20: [ 1, 36 ],
433            31: [ 2, 12 ]
434        }, o($V0, [ 2, 16 ]), o($V0, [ 2, 10 ]), o($V0, [ 2, 11 ]), {
435            17: 37,
436            24: $V1
437        }, {
438            31: [ 2, 13 ]
439        } ],
440        defaultActions: {
441            3: [ 2, 1 ],
442            24: [ 2, 14 ],
443            25: [ 2, 15 ],
444            27: [ 2, 19 ],
445            28: [ 2, 23 ],
446            29: [ 2, 24 ],
447            37: [ 2, 13 ]
448        },
449        parseError: function(str, hash) {
450            if (!hash.recoverable) throw new Error(str);
451            this.trace(str);
452        },
453        parse: function(input) {
454            function lex() {
455                var token;
456                return token = lexer.lex() || EOF, "number" != typeof token && (token = self.symbols_[token] || token),
457                token;
458            }
459            var self = this, stack = [ 0 ], vstack = [ null ], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1, args = lstack.slice.call(arguments, 1), lexer = Object.create(this.lexer), sharedState = {
460                yy: {}
461            };
462            for (var k in this.yy) Object.prototype.hasOwnProperty.call(this.yy, k) && (sharedState.yy[k] = this.yy[k]);
463            lexer.setInput(input, sharedState.yy), sharedState.yy.lexer = lexer, sharedState.yy.parser = this,
464            "undefined" == typeof lexer.yylloc && (lexer.yylloc = {});
465            var yyloc = lexer.yylloc;
466            lstack.push(yyloc);
467            var ranges = lexer.options && lexer.options.ranges;
468            "function" == typeof sharedState.yy.parseError ? this.parseError = sharedState.yy.parseError : this.parseError = Object.getPrototypeOf(this).parseError;
469            for (var symbol, preErrorSymbol, state, action, r, p, len, newState, expected, yyval = {}; ;) {
470                if (state = stack[stack.length - 1], this.defaultActions[state] ? action = this.defaultActions[state] : (null !== symbol && "undefined" != typeof symbol || (symbol = lex()),
471                action = table[state] && table[state][symbol]), "undefined" == typeof action || !action.length || !action[0]) {
472                    var errStr = "";
473                    expected = [];
474                    for (p in table[state]) this.terminals_[p] && p > TERROR && expected.push("'" + this.terminals_[p] + "'");
475                    errStr = lexer.showPosition ? "Parse error on line " + (yylineno + 1) + ":\n" + lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'" : "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == EOF ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"),
476                    this.parseError(errStr, {
477                        text: lexer.match,
478                        token: this.terminals_[symbol] || symbol,
479                        line: lexer.yylineno,
480                        loc: yyloc,
481                        expected: expected
482                    });
483                }
484                if (action[0] instanceof Array && action.length > 1) throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
485                switch (action[0]) {
486                  case 1:
487                    stack.push(symbol), vstack.push(lexer.yytext), lstack.push(lexer.yylloc), stack.push(action[1]),
488                    symbol = null, preErrorSymbol ? (symbol = preErrorSymbol, preErrorSymbol = null) : (yyleng = lexer.yyleng,
489                    yytext = lexer.yytext, yylineno = lexer.yylineno, yyloc = lexer.yylloc, recovering > 0 && recovering--);
490                    break;
491
492                  case 2:
493                    if (len = this.productions_[action[1]][1], yyval.$ = vstack[vstack.length - len],
494                    yyval._$ = {
495                        first_line: lstack[lstack.length - (len || 1)].first_line,
496                        last_line: lstack[lstack.length - 1].last_line,
497                        first_column: lstack[lstack.length - (len || 1)].first_column,
498                        last_column: lstack[lstack.length - 1].last_column
499                    }, ranges && (yyval._$.range = [ lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1] ]),
500                    r = this.performAction.apply(yyval, [ yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack ].concat(args)),
501                    "undefined" != typeof r) return r;
502                    len && (stack = stack.slice(0, -1 * len * 2), vstack = vstack.slice(0, -1 * len),
503                    lstack = lstack.slice(0, -1 * len)), stack.push(this.productions_[action[1]][0]),
504                    vstack.push(yyval.$), lstack.push(yyval._$), newState = table[stack[stack.length - 2]][stack[stack.length - 1]],
505                    stack.push(newState);
506                    break;
507
508                  case 3:
509                    return !0;
510                }
511            }
512            return !0;
513        }
514    }, lexer = function() {
515        var lexer = {
516            EOF: 1,
517            parseError: function(str, hash) {
518                if (!this.yy.parser) throw new Error(str);
519                this.yy.parser.parseError(str, hash);
520            },
521            // resets the lexer, sets new input
522            setInput: function(input, yy) {
523                return this.yy = yy || this.yy || {}, this._input = input, this._more = this._backtrack = this.done = !1,
524                this.yylineno = this.yyleng = 0, this.yytext = this.matched = this.match = "", this.conditionStack = [ "INITIAL" ],
525                this.yylloc = {
526                    first_line: 1,
527                    first_column: 0,
528                    last_line: 1,
529                    last_column: 0
530                }, this.options.ranges && (this.yylloc.range = [ 0, 0 ]), this.offset = 0, this;
531            },
532            // consumes and returns one char from the input
533            input: function() {
534                var ch = this._input[0];
535                this.yytext += ch, this.yyleng++, this.offset++, this.match += ch, this.matched += ch;
536                var lines = ch.match(/(?:\r\n?|\n).*/g);
537                return lines ? (this.yylineno++, this.yylloc.last_line++) : this.yylloc.last_column++,
538                this.options.ranges && this.yylloc.range[1]++, this._input = this._input.slice(1),
539                ch;
540            },
541            // unshifts one char (or a string) into the input
542            unput: function(ch) {
543                var len = ch.length, lines = ch.split(/(?:\r\n?|\n)/g);
544                this._input = ch + this._input, this.yytext = this.yytext.substr(0, this.yytext.length - len),
545                //this.yyleng -= len;
546                this.offset -= len;
547                var oldLines = this.match.split(/(?:\r\n?|\n)/g);
548                this.match = this.match.substr(0, this.match.length - 1), this.matched = this.matched.substr(0, this.matched.length - 1),
549                lines.length - 1 && (this.yylineno -= lines.length - 1);
550                var r = this.yylloc.range;
551                return this.yylloc = {
552                    first_line: this.yylloc.first_line,
553                    last_line: this.yylineno + 1,
554                    first_column: this.yylloc.first_column,
555                    last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len
556                }, this.options.ranges && (this.yylloc.range = [ r[0], r[0] + this.yyleng - len ]),
557                this.yyleng = this.yytext.length, this;
558            },
559            // When called from action, caches matched text and appends it on next action
560            more: function() {
561                return this._more = !0, this;
562            },
563            // When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
564            reject: function() {
565                return this.options.backtrack_lexer ? (this._backtrack = !0, this) : this.parseError("Lexical error on line " + (this.yylineno + 1) + ". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n" + this.showPosition(), {
566                    text: "",
567                    token: null,
568                    line: this.yylineno
569                });
570            },
571            // retain first n characters of the match
572            less: function(n) {
573                this.unput(this.match.slice(n));
574            },
575            // displays already matched input, i.e. for error messages
576            pastInput: function() {
577                var past = this.matched.substr(0, this.matched.length - this.match.length);
578                return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
579            },
580            // displays upcoming input, i.e. for error messages
581            upcomingInput: function() {
582                var next = this.match;
583                return next.length < 20 && (next += this._input.substr(0, 20 - next.length)), (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
584            },
585            // displays the character position where the lexing error occurred, i.e. for error messages
586            showPosition: function() {
587                var pre = this.pastInput(), c = new Array(pre.length + 1).join("-");
588                return pre + this.upcomingInput() + "\n" + c + "^";
589            },
590            // test the lexed token: return FALSE when not a match, otherwise return token
591            test_match: function(match, indexed_rule) {
592                var token, lines, backup;
593                if (this.options.backtrack_lexer && (// save context
594                backup = {
595                    yylineno: this.yylineno,
596                    yylloc: {
597                        first_line: this.yylloc.first_line,
598                        last_line: this.last_line,
599                        first_column: this.yylloc.first_column,
600                        last_column: this.yylloc.last_column
601                    },
602                    yytext: this.yytext,
603                    match: this.match,
604                    matches: this.matches,
605                    matched: this.matched,
606                    yyleng: this.yyleng,
607                    offset: this.offset,
608                    _more: this._more,
609                    _input: this._input,
610                    yy: this.yy,
611                    conditionStack: this.conditionStack.slice(0),
612                    done: this.done
613                }, this.options.ranges && (backup.yylloc.range = this.yylloc.range.slice(0))), lines = match[0].match(/(?:\r\n?|\n).*/g),
614                lines && (this.yylineno += lines.length), this.yylloc = {
615                    first_line: this.yylloc.last_line,
616                    last_line: this.yylineno + 1,
617                    first_column: this.yylloc.last_column,
618                    last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length
619                }, this.yytext += match[0], this.match += match[0], this.matches = match, this.yyleng = this.yytext.length,
620                this.options.ranges && (this.yylloc.range = [ this.offset, this.offset += this.yyleng ]),
621                this._more = !1, this._backtrack = !1, this._input = this._input.slice(match[0].length),
622                this.matched += match[0], token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]),
623                this.done && this._input && (this.done = !1), token) return token;
624                if (this._backtrack) {
625                    // recover context
626                    for (var k in backup) this[k] = backup[k];
627                    return !1;
628                }
629                return !1;
630            },
631            // return next match in input
632            next: function() {
633                if (this.done) return this.EOF;
634                this._input || (this.done = !0);
635                var token, match, tempMatch, index;
636                this._more || (this.yytext = "", this.match = "");
637                for (var rules = this._currentRules(), i = 0; i < rules.length; i++) if (tempMatch = this._input.match(this.rules[rules[i]]),
638                tempMatch && (!match || tempMatch[0].length > match[0].length)) {
639                    if (match = tempMatch, index = i, this.options.backtrack_lexer) {
640                        if (token = this.test_match(tempMatch, rules[i]), token !== !1) return token;
641                        if (this._backtrack) {
642                            match = !1;
643                            continue;
644                        }
645                        // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
646                        return !1;
647                    }
648                    if (!this.options.flex) break;
649                }
650                return match ? (token = this.test_match(match, rules[index]), token !== !1 && token) : "" === this._input ? this.EOF : this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), {
651                    text: "",
652                    token: null,
653                    line: this.yylineno
654                });
655            },
656            // return next match that has a token
657            lex: function() {
658                var r = this.next();
659                return r ? r : this.lex();
660            },
661            // activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
662            begin: function(condition) {
663                this.conditionStack.push(condition);
664            },
665            // pop the previously active lexer condition state off the condition stack
666            popState: function() {
667                var n = this.conditionStack.length - 1;
668                return n > 0 ? this.conditionStack.pop() : this.conditionStack[0];
669            },
670            // produce the lexer rule set which is active for the currently active lexer condition state
671            _currentRules: function() {
672                return this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1] ? this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules : this.conditions.INITIAL.rules;
673            },
674            // return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
675            topState: function(n) {
676                return n = this.conditionStack.length - 1 - Math.abs(n || 0), n >= 0 ? this.conditionStack[n] : "INITIAL";
677            },
678            // alias for begin(condition)
679            pushState: function(condition) {
680                this.begin(condition);
681            },
682            // return the number of states currently on the stack
683            stateStackSize: function() {
684                return this.conditionStack.length;
685            },
686            options: {
687                "case-insensitive": !0
688            },
689            performAction: function(yy, yy_, $avoiding_name_collisions, YY_START) {
690                switch ($avoiding_name_collisions) {
691                  case 0:
692                    return 8;
693
694                  case 1:
695                    /* skip whitespace */
696                    break;
697
698                  case 2:
699                    /* skip comments */
700                    break;
701
702                  case 3:
703                    return 9;
704
705                  case 4:
706                    return 21;
707
708                  case 5:
709                    return 22;
710
711                  case 6:
712                    return 18;
713
714                  case 7:
715                    return 15;
716
717                  case 8:
718                    return 13;
719
720                  case 9:
721                    return 20;
722
723                  case 10:
724                    return 24;
725
726                  case 11:
727                    return 24;
728
729                  case 12:
730                    return 28;
731
732                  case 13:
733                    return 27;
734
735                  case 14:
736                    return 30;
737
738                  case 15:
739                    return 29;
740
741                  case 16:
742                    return 31;
743
744                  case 17:
745                    return 5;
746
747                  case 18:
748                    return "INVALID";
749                }
750            },
751            rules: [ /^(?:[\r\n]+)/i, /^(?:\s+)/i, /^(?:#[^\r\n]*)/i, /^(?:participant\b)/i, /^(?:left of\b)/i, /^(?:right of\b)/i, /^(?:over\b)/i, /^(?:note\b)/i, /^(?:title\b)/i, /^(?:,)/i, /^(?:[^\->:,\r\n"]+)/i, /^(?:"[^"]+")/i, /^(?:--)/i, /^(?:-)/i, /^(?:>>)/i, /^(?:>)/i, /^(?:[^\r\n]+)/i, /^(?:$)/i, /^(?:.)/i ],
752            conditions: {
753                INITIAL: {
754                    rules: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 ],
755                    inclusive: !0
756                }
757            }
758        };
759        return lexer;
760    }();
761    return parser.lexer = lexer, Parser.prototype = parser, parser.Parser = Parser,
762    new Parser();
763}();
764
765"undefined" != typeof require && "undefined" != typeof exports && (exports.parser = parser,
766exports.Parser = parser.Parser, exports.parse = function() {
767    return parser.parse.apply(parser, arguments);
768}, exports.main = function(args) {
769    args[1] || (console.log("Usage: " + args[0] + " FILE"), process.exit(1));
770    var source = require("fs").readFileSync(require("path").normalize(args[1]), "utf8");
771    return exports.parser.parse(source);
772}, "undefined" != typeof module && require.main === module && exports.main(process.argv.slice(1)));
773/**
774 * jison doesn't have a good exception, so we make one.
775 * This is brittle as it depends on jison internals
776 */
777function ParseError(message, hash) {
778  _.extend(this, hash);
779
780  this.name = 'ParseError';
781  this.message = (message || '');
782}
783ParseError.prototype = new Error();
784Diagram.ParseError = ParseError;
785
786Diagram.parse = function(input) {
787  // TODO jison v0.4.17 changed their API slightly, so parser is no longer defined:
788
789  // Create the object to track state and deal with errors
790  parser.yy = new Diagram();
791  parser.yy.parseError = function(message, hash) {
792    throw new ParseError(message, hash);
793  };
794
795  // Parse
796  var diagram = parser.parse(input);
797
798  // Then clean up the parseError key that a user won't care about
799  delete diagram.parseError;
800  return diagram;
801};
802
803
804/** js sequence diagrams
805 *  https://bramp.github.io/js-sequence-diagrams/
806 *  (c) 2012-2017 Andrew Brampton (bramp.net)
807 *  Simplified BSD license.
808 */
809/*global Diagram, _ */
810
811// Following the CSS convention
812// Margin is the gap outside the box
813// Padding is the gap inside the box
814// Each object has x/y/width/height properties
815// The x/y should be top left corner
816// width/height is with both margin and padding
817
818// TODO
819// Image width is wrong, when there is a note in the right hand col
820// Title box could look better
821// Note box could look better
822
823var DIAGRAM_MARGIN = 10;
824
825var ACTOR_MARGIN   = 10; // Margin around a actor
826var ACTOR_PADDING  = 10; // Padding inside a actor
827
828var SIGNAL_MARGIN  = 5; // Margin around a signal
829var SIGNAL_PADDING = 5; // Padding inside a signal
830
831var NOTE_MARGIN   = 10; // Margin around a note
832var NOTE_PADDING  = 5; // Padding inside a note
833var NOTE_OVERLAP  = 15; // Overlap when using a "note over A,B"
834
835var TITLE_MARGIN   = 0;
836var TITLE_PADDING  = 5;
837
838var SELF_SIGNAL_WIDTH = 20; // How far out a self signal goes
839
840var PLACEMENT = Diagram.PLACEMENT;
841var LINETYPE  = Diagram.LINETYPE;
842var ARROWTYPE = Diagram.ARROWTYPE;
843
844var ALIGN_LEFT   = 0;
845var ALIGN_CENTER = 1;
846
847function AssertException(message) { this.message = message; }
848AssertException.prototype.toString = function() {
849  return 'AssertException: ' + this.message;
850};
851
852function assert(exp, message) {
853  if (!exp) {
854    throw new AssertException(message);
855  }
856}
857
858if (!String.prototype.trim) {
859  String.prototype.trim = function() {
860    return this.replace(/^\s+|\s+$/g, '');
861  };
862}
863
864Diagram.themes = {};
865function registerTheme(name, theme) {
866  Diagram.themes[name] = theme;
867}
868
869/******************
870 * Drawing extras
871 ******************/
872
873function getCenterX(box) {
874  return box.x + box.width / 2;
875}
876
877function getCenterY(box) {
878  return box.y + box.height / 2;
879}
880
881/******************
882 * SVG Path extras
883 ******************/
884
885function clamp(x, min, max) {
886  if (x < min) {
887    return min;
888  }
889  if (x > max) {
890    return max;
891  }
892  return x;
893}
894
895function wobble(x1, y1, x2, y2) {
896  assert(_.all([x1,x2,y1,y2], _.isFinite), 'x1,x2,y1,y2 must be numeric');
897
898  // Wobble no more than 1/25 of the line length
899  var factor = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / 25;
900
901  // Distance along line where the control points are
902  // Clamp between 20% and 80% so any arrow heads aren't angled too much
903  var r1 = clamp(Math.random(), 0.2, 0.8);
904  var r2 = clamp(Math.random(), 0.2, 0.8);
905
906  var xfactor = Math.random() > 0.5 ? factor : -factor;
907  var yfactor = Math.random() > 0.5 ? factor : -factor;
908
909  var p1 = {
910    x: (x2 - x1) * r1 + x1 + xfactor,
911    y: (y2 - y1) * r1 + y1 + yfactor
912  };
913
914  var p2 = {
915    x: (x2 - x1) * r2 + x1 - xfactor,
916    y: (y2 - y1) * r2 + y1 - yfactor
917  };
918
919  return 'C' + p1.x.toFixed(1) + ',' + p1.y.toFixed(1) + // start control point
920         ' ' + p2.x.toFixed(1) + ',' + p2.y.toFixed(1) + // end control point
921         ' ' + x2.toFixed(1) + ',' + y2.toFixed(1);      // end point
922}
923
924/**
925 * Draws a wobbly (hand drawn) rect
926 */
927function handRect(x, y, w, h) {
928  assert(_.all([x, y, w, h], _.isFinite), 'x, y, w, h must be numeric');
929  return 'M' + x + ',' + y +
930   wobble(x, y, x + w, y) +
931   wobble(x + w, y, x + w, y + h) +
932   wobble(x + w, y + h, x, y + h) +
933   wobble(x, y + h, x, y);
934}
935
936/**
937 * Draws a wobbly (hand drawn) line
938 */
939function handLine(x1, y1, x2, y2) {
940  assert(_.all([x1,x2,y1,y2], _.isFinite), 'x1,x2,y1,y2 must be numeric');
941  return 'M' + x1.toFixed(1) + ',' + y1.toFixed(1) + wobble(x1, y1, x2, y2);
942}
943
944/******************
945 * BaseTheme
946 ******************/
947
948var BaseTheme = function(diagram, options) {
949  this.init(diagram, options);
950};
951
952_.extend(BaseTheme.prototype, {
953
954  // Init called while creating the Theme
955  init: function(diagram, options) {
956    this.diagram = diagram;
957
958    this.actorsHeight_  = 0;
959    this.signalsHeight_ = 0;
960    this.title_ = undefined; // hack - This should be somewhere better
961  },
962
963  setupPaper: function(container) {},
964
965  draw: function(container) {
966    this.setupPaper(container);
967
968    this.layout();
969
970    var titleHeight = this.title_ ? this.title_.height : 0;
971    var y = DIAGRAM_MARGIN + titleHeight;
972
973    this.drawTitle();
974    this.drawActors(y);
975    this.drawSignals(y + this.actorsHeight_);
976  },
977
978  layout: function() {
979    // Local copies
980    var diagram = this.diagram;
981    var font    = this.font_;
982    var actors  = diagram.actors;
983    var signals = diagram.signals;
984
985    diagram.width  = 0; // min width
986    diagram.height = 0; // min height
987
988    // Setup some layout stuff
989    if (diagram.title) {
990      var title = this.title_ = {};
991      var bb = this.textBBox(diagram.title, font);
992      title.textBB = bb;
993      title.message = diagram.title;
994
995      title.width  = bb.width  + (TITLE_PADDING + TITLE_MARGIN) * 2;
996      title.height = bb.height + (TITLE_PADDING + TITLE_MARGIN) * 2;
997      title.x = DIAGRAM_MARGIN;
998      title.y = DIAGRAM_MARGIN;
999
1000      diagram.width  += title.width;
1001      diagram.height += title.height;
1002    }
1003
1004    _.each(actors, function(a) {
1005      var bb = this.textBBox(a.name, font);
1006      a.textBB = bb;
1007
1008      a.x = 0; a.y = 0;
1009      a.width  = bb.width  + (ACTOR_PADDING + ACTOR_MARGIN) * 2;
1010      a.height = bb.height + (ACTOR_PADDING + ACTOR_MARGIN) * 2;
1011
1012      a.distances = [];
1013      a.paddingRight = 0;
1014      this.actorsHeight_ = Math.max(a.height, this.actorsHeight_);
1015    }, this);
1016
1017    function actorEnsureDistance(a, b, d) {
1018      assert(a < b, 'a must be less than or equal to b');
1019
1020      if (a < 0) {
1021        // Ensure b has left margin
1022        b = actors[b];
1023        b.x = Math.max(d - b.width / 2, b.x);
1024      } else if (b >= actors.length) {
1025        // Ensure a has right margin
1026        a = actors[a];
1027        a.paddingRight = Math.max(d, a.paddingRight);
1028      } else {
1029        a = actors[a];
1030        a.distances[b] = Math.max(d, a.distances[b] ? a.distances[b] : 0);
1031      }
1032    }
1033
1034    _.each(signals, function(s) {
1035      // Indexes of the left and right actors involved
1036      var a;
1037      var b;
1038
1039      var bb = this.textBBox(s.message, font);
1040
1041      //var bb = t.attr("text", s.message).getBBox();
1042      s.textBB = bb;
1043      s.width   = bb.width;
1044      s.height  = bb.height;
1045
1046      var extraWidth = 0;
1047
1048      if (s.type == 'Signal') {
1049
1050        s.width  += (SIGNAL_MARGIN + SIGNAL_PADDING) * 2;
1051        s.height += (SIGNAL_MARGIN + SIGNAL_PADDING) * 2;
1052
1053        if (s.isSelf()) {
1054          // TODO Self signals need a min height
1055          a = s.actorA.index;
1056          b = a + 1;
1057          s.width += SELF_SIGNAL_WIDTH;
1058        } else {
1059          a = Math.min(s.actorA.index, s.actorB.index);
1060          b = Math.max(s.actorA.index, s.actorB.index);
1061        }
1062
1063      } else if (s.type == 'Note') {
1064        s.width  += (NOTE_MARGIN + NOTE_PADDING) * 2;
1065        s.height += (NOTE_MARGIN + NOTE_PADDING) * 2;
1066
1067        // HACK lets include the actor's padding
1068        extraWidth = 2 * ACTOR_MARGIN;
1069
1070        if (s.placement == PLACEMENT.LEFTOF) {
1071          b = s.actor.index;
1072          a = b - 1;
1073        } else if (s.placement == PLACEMENT.RIGHTOF) {
1074          a = s.actor.index;
1075          b = a + 1;
1076        } else if (s.placement == PLACEMENT.OVER && s.hasManyActors()) {
1077          // Over multiple actors
1078          a = Math.min(s.actor[0].index, s.actor[1].index);
1079          b = Math.max(s.actor[0].index, s.actor[1].index);
1080
1081          // We don't need our padding, and we want to overlap
1082          extraWidth = -(NOTE_PADDING * 2 + NOTE_OVERLAP * 2);
1083
1084        } else if (s.placement == PLACEMENT.OVER) {
1085          // Over single actor
1086          a = s.actor.index;
1087          actorEnsureDistance(a - 1, a, s.width / 2);
1088          actorEnsureDistance(a, a + 1, s.width / 2);
1089          this.signalsHeight_ += s.height;
1090
1091          return; // Bail out early
1092        }
1093      } else {
1094        throw new Error('Unhandled signal type:' + s.type);
1095      }
1096
1097      actorEnsureDistance(a, b, s.width + extraWidth);
1098      this.signalsHeight_ += s.height;
1099    }, this);
1100
1101    // Re-jig the positions
1102    var actorsX = 0;
1103    _.each(actors, function(a) {
1104      a.x = Math.max(actorsX, a.x);
1105
1106      // TODO This only works if we loop in sequence, 0, 1, 2, etc
1107      _.each(a.distances, function(distance, b) {
1108        // lodash (and possibly others) do not like sparse arrays
1109        // so sometimes they return undefined
1110        if (typeof distance == 'undefined') {
1111          return;
1112        }
1113
1114        b = actors[b];
1115        distance = Math.max(distance, a.width / 2, b.width / 2);
1116        b.x = Math.max(b.x, a.x + a.width / 2 + distance - b.width / 2);
1117      });
1118
1119      actorsX = a.x + a.width + a.paddingRight;
1120    }, this);
1121
1122    diagram.width = Math.max(actorsX, diagram.width);
1123
1124    // TODO Refactor a little
1125    diagram.width  += 2 * DIAGRAM_MARGIN;
1126    diagram.height += 2 * DIAGRAM_MARGIN + 2 * this.actorsHeight_ + this.signalsHeight_;
1127
1128    return this;
1129  },
1130
1131  // TODO Instead of one textBBox function, create a function for each element type, e.g
1132  //      layout_title, layout_actor, etc that returns it's bounding box
1133  textBBox: function(text, font) {},
1134
1135  drawTitle: function() {
1136    var title = this.title_;
1137    if (title) {
1138      this.drawTextBox(title, title.message, TITLE_MARGIN, TITLE_PADDING, this.font_, ALIGN_LEFT);
1139    }
1140  },
1141
1142  drawActors: function(offsetY) {
1143    var y = offsetY;
1144    _.each(this.diagram.actors, function(a) {
1145      // Top box
1146      this.drawActor(a, y, this.actorsHeight_);
1147
1148      // Bottom box
1149      this.drawActor(a, y + this.actorsHeight_ + this.signalsHeight_, this.actorsHeight_);
1150
1151      // Veritical line
1152      var aX = getCenterX(a);
1153      this.drawLine(
1154       aX, y + this.actorsHeight_ - ACTOR_MARGIN,
1155       aX, y + this.actorsHeight_ + ACTOR_MARGIN + this.signalsHeight_);
1156    }, this);
1157  },
1158
1159  drawActor: function(actor, offsetY, height) {
1160    actor.y      = offsetY;
1161    actor.height = height;
1162    this.drawTextBox(actor, actor.name, ACTOR_MARGIN, ACTOR_PADDING, this.font_, ALIGN_CENTER);
1163  },
1164
1165  drawSignals: function(offsetY) {
1166    var y = offsetY;
1167    _.each(this.diagram.signals, function(s) {
1168      // TODO Add debug mode, that draws padding/margin box
1169      if (s.type == 'Signal') {
1170        if (s.isSelf()) {
1171          this.drawSelfSignal(s, y);
1172        } else {
1173          this.drawSignal(s, y);
1174        }
1175
1176      } else if (s.type == 'Note') {
1177        this.drawNote(s, y);
1178      }
1179
1180      y += s.height;
1181    }, this);
1182  },
1183
1184  drawSelfSignal: function(signal, offsetY) {
1185      assert(signal.isSelf(), 'signal must be a self signal');
1186
1187      var textBB = signal.textBB;
1188      var aX = getCenterX(signal.actorA);
1189
1190      var x = aX + SELF_SIGNAL_WIDTH + SIGNAL_PADDING;
1191      var y = offsetY + SIGNAL_PADDING + signal.height / 2 + textBB.y;
1192
1193      this.drawText(x, y, signal.message, this.font_, ALIGN_LEFT);
1194
1195      var y1 = offsetY + SIGNAL_MARGIN + SIGNAL_PADDING;
1196      var y2 = y1 + signal.height - 2 * SIGNAL_MARGIN - SIGNAL_PADDING;
1197
1198      // Draw three lines, the last one with a arrow
1199      this.drawLine(aX, y1, aX + SELF_SIGNAL_WIDTH, y1, signal.linetype);
1200      this.drawLine(aX + SELF_SIGNAL_WIDTH, y1, aX + SELF_SIGNAL_WIDTH, y2, signal.linetype);
1201      this.drawLine(aX + SELF_SIGNAL_WIDTH, y2, aX, y2, signal.linetype, signal.arrowtype);
1202    },
1203
1204  drawSignal: function(signal, offsetY) {
1205    var aX = getCenterX(signal.actorA);
1206    var bX = getCenterX(signal.actorB);
1207
1208    // Mid point between actors
1209    var x = (bX - aX) / 2 + aX;
1210    var y = offsetY + SIGNAL_MARGIN + 2 * SIGNAL_PADDING;
1211
1212    // Draw the text in the middle of the signal
1213    this.drawText(x, y, signal.message, this.font_, ALIGN_CENTER);
1214
1215    // Draw the line along the bottom of the signal
1216    y = offsetY + signal.height - SIGNAL_MARGIN - SIGNAL_PADDING;
1217    this.drawLine(aX, y, bX, y, signal.linetype, signal.arrowtype);
1218  },
1219
1220  drawNote: function(note, offsetY) {
1221    note.y = offsetY;
1222    var actorA = note.hasManyActors() ? note.actor[0] : note.actor;
1223    var aX = getCenterX(actorA);
1224    switch (note.placement) {
1225    case PLACEMENT.RIGHTOF:
1226      note.x = aX + ACTOR_MARGIN;
1227    break;
1228    case PLACEMENT.LEFTOF:
1229      note.x = aX - ACTOR_MARGIN - note.width;
1230    break;
1231    case PLACEMENT.OVER:
1232      if (note.hasManyActors()) {
1233        var bX = getCenterX(note.actor[1]);
1234        var overlap = NOTE_OVERLAP + NOTE_PADDING;
1235        note.x = Math.min(aX, bX) - overlap;
1236        note.width = (Math.max(aX, bX) + overlap) - note.x;
1237      } else {
1238        note.x = aX - note.width / 2;
1239      }
1240    break;
1241    default:
1242      throw new Error('Unhandled note placement: ' + note.placement);
1243  }
1244    return this.drawTextBox(note, note.message, NOTE_MARGIN, NOTE_PADDING, this.font_, ALIGN_LEFT);
1245  },
1246
1247  /**
1248   * Draw text surrounded by a box
1249   */
1250  drawTextBox: function(box, text, margin, padding, font, align) {
1251    var x = box.x + margin;
1252    var y = box.y + margin;
1253    var w = box.width  - 2 * margin;
1254    var h = box.height - 2 * margin;
1255
1256    // Draw inner box
1257    this.drawRect(x, y, w, h);
1258
1259    // Draw text (in the center)
1260    if (align == ALIGN_CENTER) {
1261      x = getCenterX(box);
1262      y = getCenterY(box);
1263    } else {
1264      x += padding;
1265      y += padding;
1266    }
1267
1268    return this.drawText(x, y, text, font, align);
1269  }
1270});
1271
1272/** js sequence diagrams
1273 *  https://bramp.github.io/js-sequence-diagrams/
1274 *  (c) 2012-2017 Andrew Brampton (bramp.net)
1275 *  Simplified BSD license.
1276 */
1277/*global Diagram, Snap, WebFont _ */
1278// TODO Move defintion of font onto the <svg>, so it can easily be override at each level
1279if (typeof Snap != 'undefined') {
1280
1281  var xmlns = 'http://www.w3.org/2000/svg';
1282
1283  var LINE = {
1284    'stroke': '#000000',
1285    'stroke-width': 2, // BUG TODO This gets set as a style, not as a attribute. Look at  eve.on("snap.util.attr"...
1286    'fill': 'none'
1287  };
1288
1289  var RECT = {
1290        'stroke': '#000000',
1291        'stroke-width': 2,
1292        'fill': '#fff'
1293      };
1294
1295  var LOADED_FONTS = {};
1296
1297  /******************
1298   * SnapTheme
1299   ******************/
1300
1301  var SnapTheme = function(diagram, options, resume) {
1302        _.defaults(options, {
1303            'css-class': 'simple',
1304            'font-size': 16,
1305            'font-family': 'Andale Mono, monospace'
1306          });
1307
1308        this.init(diagram, options, resume);
1309      };
1310
1311  _.extend(SnapTheme.prototype, BaseTheme.prototype, {
1312
1313    init: function(diagram, options, resume) {
1314            BaseTheme.prototype.init.call(this, diagram);
1315
1316            this.paper_  = undefined;
1317            this.cssClass_ = options['css-class'] || undefined;
1318            this.font_ = {
1319                'font-size': options['font-size'],
1320                'font-family': options['font-family']
1321              };
1322
1323            var a = this.arrowTypes_ = {};
1324            a[ARROWTYPE.FILLED] = 'Block';
1325            a[ARROWTYPE.OPEN]   = 'Open';
1326
1327            var l = this.lineTypes_ = {};
1328            l[LINETYPE.SOLID]  = '';
1329            l[LINETYPE.DOTTED] = '6,2';
1330
1331            var that = this;
1332            this.waitForFont(function() {
1333              resume(that);
1334            });
1335          },
1336
1337    // Wait for loading of the font
1338    waitForFont: function(callback) {
1339      var fontFamily = this.font_['font-family'];
1340
1341      if (typeof WebFont == 'undefined') {
1342        throw new Error('WebFont is required (https://github.com/typekit/webfontloader).');
1343      }
1344
1345      if (LOADED_FONTS[fontFamily]) {
1346        // If already loaded, just return instantly.
1347        callback();
1348        return;
1349      }
1350
1351      WebFont.load({
1352          custom: {
1353              families: [fontFamily] // TODO replace this with something that reads the css
1354            },
1355          classes: false, // No need to place classes on the DOM, just use JS Events
1356          active: function() {
1357              LOADED_FONTS[fontFamily] = true;
1358              callback();
1359            },
1360          inactive: function() {
1361              // If we fail to fetch the font, still continue.
1362              LOADED_FONTS[fontFamily] = true;
1363              callback();
1364            }
1365        });
1366    },
1367
1368    addDescription: function(svg, description) {
1369          var desc = document.createElementNS(xmlns, 'desc');
1370          desc.appendChild(document.createTextNode(description));
1371          svg.appendChild(desc);
1372        },
1373
1374    setupPaper: function(container) {
1375      // Container must be a SVG element. We assume it's a div, so lets create a SVG and insert
1376      var svg = document.createElementNS(xmlns, 'svg');
1377      container.appendChild(svg);
1378
1379      this.addDescription(svg, this.diagram.title || '');
1380
1381      this.paper_ = Snap(svg);
1382      this.paper_.addClass('sequence');
1383
1384      if (this.cssClass_) {
1385        this.paper_.addClass(this.cssClass_);
1386      }
1387
1388      this.beginGroup();
1389
1390      // TODO Perhaps only include the markers if we actually use them.
1391      var a = this.arrowMarkers_ = {};
1392      var arrow = this.paper_.path('M 0 0 L 5 2.5 L 0 5 z');
1393      a[ARROWTYPE.FILLED] = arrow.marker(0, 0, 5, 5, 5, 2.5)
1394       .attr({id: 'markerArrowBlock'});
1395
1396      arrow = this.paper_.path('M 9.6,8 1.92,16 0,13.7 5.76,8 0,2.286 1.92,0 9.6,8 z');
1397      a[ARROWTYPE.OPEN] = arrow.marker(0, 0, 9.6, 16, 9.6, 8)
1398       .attr({markerWidth: '4', id: 'markerArrowOpen'});
1399    },
1400
1401    layout: function() {
1402      BaseTheme.prototype.layout.call(this);
1403      this.paper_.attr({
1404        width:  this.diagram.width + 'px',
1405        height: this.diagram.height + 'px'
1406      });
1407    },
1408
1409    textBBox: function(text, font) {
1410      // TODO getBBox will return the bounds with any whitespace/kerning. This makes some of our aligments screwed up
1411      var t = this.createText(text, font);
1412      var bb = t.getBBox();
1413      t.remove();
1414      return bb;
1415    },
1416
1417    // For each drawn element, push onto the stack, so it can be wrapped in a single outer element
1418    pushToStack: function(element) {
1419      this._stack.push(element);
1420      return element;
1421    },
1422
1423    // Begin a group of elements
1424    beginGroup: function() {
1425      this._stack = [];
1426    },
1427
1428    // Finishes the group, and returns the <group> element
1429    finishGroup: function() {
1430      var g = this.paper_.group.apply(this.paper_, this._stack);
1431      this.beginGroup(); // Reset the group
1432      return g;
1433    },
1434
1435    createText: function(text, font) {
1436      text = _.invoke(text.split('\n'), 'trim');
1437      var t = this.paper_.text(0, 0, text);
1438      t.attr(font || {});
1439      if (text.length > 1) {
1440        // Every row after the first, set tspan to be 1.2em below the previous line
1441        t.selectAll('tspan:nth-child(n+2)').attr({
1442          dy: '1.2em',
1443          x: 0
1444        });
1445      }
1446
1447      return t;
1448    },
1449
1450    drawLine: function(x1, y1, x2, y2, linetype, arrowhead) {
1451      var line = this.paper_.line(x1, y1, x2, y2).attr(LINE);
1452      if (linetype !== undefined) {
1453        line.attr('strokeDasharray', this.lineTypes_[linetype]);
1454      }
1455      if (arrowhead !== undefined) {
1456        line.attr('markerEnd', this.arrowMarkers_[arrowhead]);
1457      }
1458      return this.pushToStack(line);
1459    },
1460
1461    drawRect: function(x, y, w, h) {
1462      var rect = this.paper_.rect(x, y, w, h).attr(RECT);
1463      return this.pushToStack(rect);
1464    },
1465
1466    /**
1467     * Draws text with a optional white background
1468     * x,y (int) x,y top left point of the text, or the center of the text (depending on align param)
1469     * text (string) text to print
1470     * font (Object)
1471     * align (string) ALIGN_LEFT or ALIGN_CENTER
1472     */
1473    drawText: function(x, y, text, font, align) {
1474      var t = this.createText(text, font);
1475      var bb = t.getBBox();
1476
1477      if (align == ALIGN_CENTER) {
1478        x = x - bb.width / 2;
1479        y = y - bb.height / 2;
1480      }
1481
1482      // Now move the text into place
1483      // `y - bb.y` because text(..) is positioned from the baseline, so this moves it down.
1484      t.attr({x: x - bb.x, y: y - bb.y});
1485      t.selectAll('tspan').attr({x: x});
1486
1487      this.pushToStack(t);
1488      return t;
1489    },
1490
1491    drawTitle: function() {
1492      this.beginGroup();
1493      BaseTheme.prototype.drawTitle.call(this);
1494      return this.finishGroup().addClass('title');
1495    },
1496
1497    drawActor: function(actor, offsetY, height) {
1498      this.beginGroup();
1499      BaseTheme.prototype.drawActor.call(this, actor, offsetY, height);
1500      return this.finishGroup().addClass('actor');
1501    },
1502
1503    drawSignal: function(signal, offsetY) {
1504      this.beginGroup();
1505      BaseTheme.prototype.drawSignal.call(this, signal, offsetY);
1506      return this.finishGroup().addClass('signal');
1507    },
1508
1509    drawSelfSignal: function(signal, offsetY) {
1510      this.beginGroup();
1511      BaseTheme.prototype.drawSelfSignal.call(this, signal, offsetY);
1512      return this.finishGroup().addClass('signal');
1513    },
1514
1515    drawNote: function(note, offsetY) {
1516      this.beginGroup();
1517      BaseTheme.prototype.drawNote.call(this, note, offsetY);
1518      return this.finishGroup().addClass('note');
1519    },
1520  });
1521
1522  /******************
1523   * SnapHandTheme
1524   ******************/
1525
1526  var SnapHandTheme = function(diagram, options, resume) {
1527        _.defaults(options, {
1528            'css-class': 'hand',
1529            'font-size': 16,
1530            'font-family': 'danielbd'
1531          });
1532
1533        this.init(diagram, options, resume);
1534      };
1535
1536  // Take the standard SnapTheme and make all the lines wobbly
1537  _.extend(SnapHandTheme.prototype, SnapTheme.prototype, {
1538    drawLine: function(x1, y1, x2, y2, linetype, arrowhead) {
1539      var line = this.paper_.path(handLine(x1, y1, x2, y2)).attr(LINE);
1540      if (linetype !== undefined) {
1541        line.attr('strokeDasharray', this.lineTypes_[linetype]);
1542      }
1543      if (arrowhead !== undefined) {
1544        line.attr('markerEnd', this.arrowMarkers_[arrowhead]);
1545      }
1546      return this.pushToStack(line);
1547    },
1548
1549    drawRect: function(x, y, w, h) {
1550      var rect = this.paper_.path(handRect(x, y, w, h)).attr(RECT);
1551      return this.pushToStack(rect);
1552    }
1553  });
1554
1555  registerTheme('snapSimple', SnapTheme);
1556  registerTheme('snapHand',   SnapHandTheme);
1557}
1558
1559
1560/** js sequence diagrams
1561 *  https://bramp.github.io/js-sequence-diagrams/
1562 *  (c) 2012-2017 Andrew Brampton (bramp.net)
1563 *  Simplified BSD license.
1564 */
1565/*global Diagram, _ */
1566
1567if (typeof Raphael == 'undefined' && typeof Snap == 'undefined') {
1568  throw new Error('Raphael or Snap.svg is required to be included.');
1569}
1570
1571if (_.isEmpty(Diagram.themes)) {
1572  // If you are using stock js-sequence-diagrams you should never see this. This only
1573  // happens if you have removed the built in themes.
1574  throw new Error('No themes were registered. Please call registerTheme(...).');
1575}
1576
1577// Set the default hand/simple based on which theme is available.
1578Diagram.themes.hand = Diagram.themes.snapHand || Diagram.themes.raphaelHand;
1579Diagram.themes.simple = Diagram.themes.snapSimple || Diagram.themes.raphaelSimple;
1580
1581/* Draws the diagram. Creates a SVG inside the container
1582* container (HTMLElement|string) DOM element or its ID to draw on
1583* options (Object)
1584*/
1585Diagram.prototype.drawSVG = function(container, options) {
1586  var defaultOptions = {
1587    theme: 'hand'
1588  };
1589
1590  options = _.defaults(options || {}, defaultOptions);
1591
1592  if (!(options.theme in Diagram.themes)) {
1593    throw new Error('Unsupported theme: ' + options.theme);
1594  }
1595
1596  // TODO Write tests for this check
1597  var div = _.isString(container) ? document.getElementById(container) : container;
1598  if (div === null || !div.tagName) {
1599    throw new Error('Invalid container: ' + container);
1600  }
1601
1602  var Theme = Diagram.themes[options.theme];
1603  new Theme(this, options, function(drawing) {
1604      drawing.draw(div);
1605    });
1606}; // end of drawSVG
1607/** js sequence diagrams
1608 *  https://bramp.github.io/js-sequence-diagrams/
1609 *  (c) 2012-2017 Andrew Brampton (bramp.net)
1610 *  Simplified BSD license.
1611 */
1612/*global jQuery */
1613if (typeof jQuery != 'undefined') {
1614  (function($) {
1615    $.fn.sequenceDiagram = function(options) {
1616      return this.each(function() {
1617        var $this = $(this);
1618        var diagram = Diagram.parse($this.text());
1619        $this.html('');
1620        diagram.drawSVG(this, options);
1621      });
1622    };
1623  })(jQuery);
1624}
1625
1626// Taken from underscore.js:
1627// Establish the root object, `window` (`self`) in the browser, or `global` on the server.
1628// We use `self` instead of `window` for `WebWorker` support.
1629var root = (typeof self == 'object' && self.self == self && self) ||
1630 (typeof global == 'object' && global.global == global && global);
1631
1632// Export the Diagram object for **Node.js**, with
1633// backwards-compatibility for their old module API. If we're in
1634// the browser, add `Diagram` as a global object.
1635if (typeof exports !== 'undefined') {
1636  if (typeof module !== 'undefined' && module.exports) {
1637    exports = module.exports = Diagram;
1638  }
1639  exports.Diagram = Diagram;
1640} else {
1641  root.Diagram = Diagram;
1642}
1643}());
1644
1645