text: var __extends = (this && this.__extends) || (function () {
      var extendStatics = Object.setPrototypeOf ||
          ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
          function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  (function (factory) {
      if (typeof module === "object" && typeof module.exports === "object") {
          var v = factory(require, exports);
          if (v !== undefined) module.exports = v;
      }
      else if (typeof define === "function" && define.amd) {
          define(["require", "exports", "../release/go", "./Figures", "./BPMNClasses", "./DrawCommandHandlerTool"], factory);
      }
  })(function (require, exports) {
      "use strict";
      Object.defineProperty(exports, "__esModule", { value: true });
      /*
      *  Copyright (C) 1998-2017 by Northwoods Software Corporation. All Rights Reserved.
      */
      var go = require("../release/go");
      require("./Figures");
      //import * as jQuery from "jquery";
      var BPMNClasses_1 = require("./BPMNClasses");
      var DrawCommandHandlerTool_1 = require("./DrawCommandHandlerTool");
      // This file holds all of the JavaScript code specific to the BPMN.html page.
      var myDiagram;
      // Setup all of the Diagrams and what they need.
      // This is called after the page is loaded.
      function init() {
          var $ = go.GraphObject.make; // for more concise visual tree definitions
          function checkLocalStorage() {
              try {
                  window.localStorage.setItem('item', 'item');
                  window.localStorage.removeItem('item');
                  return true;
              }
              catch (e) {
                  return false;
              }
          }
          if (!checkLocalStorage()) {
              var currentFile = document.getElementById("currentFile");
              currentFile.textContent = "Sorry! No web storage support. If you're using Internet Explorer / Microsoft Edge, you must load the page from a server for local storage to work.";
          }
          // setup the menubar
          jQuery("#menuui").menu();
          jQuery(function () {
              jQuery("#menuui").menu({ position: { my: "left top", at: "left top+30" } });
          });
          jQuery("#menuui").menu({
              icons: { submenu: "ui-icon-triangle-1-s" }
          });
          // hides open HTML Element
          var openDocument = document.getElementById("openDocument");
          openDocument.style.visibility = "hidden";
          // hides remove HTML Element
          var removeDocument = document.getElementById("removeDocument");
          removeDocument.style.visibility = "hidden";
          // constants for design choices
          var GradientYellow = $(go.Brush, "Linear", { 0: "LightGoldenRodYellow", 1: "#FFFF66" });
          var GradientLightGreen = $(go.Brush, "Linear", { 0: "#E0FEE0", 1: "PaleGreen" });
          var GradientLightGray = $(go.Brush, "Linear", { 0: "White", 1: "#DADADA" });
          var ActivityNodeFill = $(go.Brush, "Linear", { 0: "OldLace", 1: "PapayaWhip" });
          var ActivityNodeStroke = "#CDAA7D";
          var ActivityMarkerStrokeWidth = 1.5;
          var ActivityNodeWidth = 120;
          var ActivityNodeHeight = 80;
          var ActivityNodeStrokeWidth = 1;
          var ActivityNodeStrokeWidthIsCall = 4;
          var SubprocessNodeFill = ActivityNodeFill;
          var SubprocessNodeStroke = ActivityNodeStroke;
          var EventNodeSize = 42;
          var EventNodeInnerSize = EventNodeSize - 6;
          var EventNodeSymbolSize = EventNodeInnerSize - 14;
          var EventEndOuterFillColor = "pink";
          var EventBackgroundColor = GradientLightGreen;
          var EventSymbolLightFill = "white";
          var EventSymbolDarkFill = "dimgray";
          var EventDimensionStrokeColor = "green";
          var EventDimensionStrokeEndColor = "red";
          var EventNodeStrokeWidthIsEnd = 4;
          var GatewayNodeSize = 80;
          var GatewayNodeSymbolSize = 45;
          var GatewayNodeFill = GradientYellow;
          var GatewayNodeStroke = "darkgoldenrod";
          var GatewayNodeSymbolStroke = "darkgoldenrod";
          var GatewayNodeSymbolFill = GradientYellow;
          var GatewayNodeSymbolStrokeWidth = 3;
          var DataFill = GradientLightGray;
          // custom figures for Shapes
          go.Shape.defineFigureGenerator("Empty", function (shape, w, h) {
              return new go.Geometry();
          });
          var annotationStr = "M 150,0L 0,0L 0,600L 150,600 M 800,0";
          var annotationGeo = go.Geometry.parse(annotationStr);
          annotationGeo.normalize();
          go.Shape.defineFigureGenerator("Annotation", function (shape, w, h) {
              var geo = annotationGeo.copy();
              // calculate how much to scale the Geometry so that it fits in w x h
              var bounds = geo.bounds;
              var scale = Math.min(w / bounds.width, h / bounds.height);
              geo.scale(scale, scale);
              return geo;
          });
          var gearStr = "F M 391,5L 419,14L 444.5,30.5L 451,120.5L 485.5,126L 522,141L 595,83L 618.5,92L 644,106.5" +
              "L 660.5,132L 670,158L 616,220L 640.5,265.5L 658.122,317.809L 753.122,322.809L 770.122,348.309L 774.622,374.309" +
              "L 769.5,402L 756.622,420.309L 659.122,428.809L 640.5,475L 616.5,519.5L 670,573.5L 663,600L 646,626.5" +
              "L 622,639L 595,645.5L 531.5,597.5L 493.192,613.462L 450,627.5L 444.5,718.5L 421.5,733L 393,740.5L 361.5,733.5" +
              "L 336.5,719L 330,627.5L 277.5,611.5L 227.5,584.167L 156.5,646L 124.5,641L 102,626.5L 82,602.5L 78.5,572.5" +
              "L 148.167,500.833L 133.5,466.833L 122,432.5L 26.5,421L 11,400.5L 5,373.5L 12,347.5L 26.5,324L 123.5,317.5" +
              "L 136.833,274.167L 154,241L 75.5,152.5L 85.5,128.5L 103,105.5L 128.5,88.5001L 154.872,82.4758L 237,155" +
              "L 280.5,132L 330,121L 336,30L 361,15L 391,5 Z M 398.201,232L 510.201,275L 556.201,385L 505.201,491L 399.201,537" +
              "L 284.201,489L 242.201,385L 282.201,273L 398.201,232 Z";
          var gearGeo = go.Geometry.parse(gearStr);
          gearGeo.normalize();
          go.Shape.defineFigureGenerator("BpmnTaskService", function (shape, w, h) {
              var geo = gearGeo.copy();
              // calculate how much to scale the Geometry so that it fits in w x h
              var bounds = geo.bounds;
              var scale = Math.min(w / bounds.width, h / bounds.height);
              geo.scale(scale, scale);
              // text should go in the hand
              geo.spot1 = new go.Spot(0, 0.6, 10, 0);
              geo.spot2 = new go.Spot(1, 1);
              return geo;
          });
          var handGeo = go.Geometry.parse("F1M18.13,10.06 C18.18,10.07 18.22,10.07 18.26,10.08 18.91," +
              "10.20 21.20,10.12 21.28,12.93 21.36,15.75 21.42,32.40 21.42,32.40 21.42," +
              "32.40 21.12,34.10 23.08,33.06 23.08,33.06 22.89,24.76 23.80,24.17 24.72," +
              "23.59 26.69,23.81 27.19,24.40 27.69,24.98 28.03,24.97 28.03,33.34 28.03," +
              "33.34 29.32,34.54 29.93,33.12 30.47,31.84 29.71,27.11 30.86,26.56 31.80," +
              "26.12 34.53,26.12 34.72,28.29 34.94,30.82 34.22,36.12 35.64,35.79 35.64," +
              "35.79 36.64,36.08 36.72,34.54 36.80,33.00 37.17,30.15 38.42,29.90 39.67," +
              "29.65 41.22,30.20 41.30,32.29 41.39,34.37 42.30,46.69 38.86,55.40 35.75," +
              "63.29 36.42,62.62 33.47,63.12 30.76,63.58 26.69,63.12 26.69,63.12 26.69," +
              "63.12 17.72,64.45 15.64,57.62 13.55,50.79 10.80,40.95 7.30,38.95 3.80," +
              "36.95 4.24,36.37 4.28,35.35 4.32,34.33 7.60,31.25 12.97,35.75 12.97," +
              "35.75 16.10,39.79 16.10,42.00 16.10,42.00 15.69,14.30 15.80,12.79 15.96," +
              "10.75 17.42,10.04 18.13,10.06z ");
          handGeo.rotate(90, 0, 0);
          handGeo.normalize();
          go.Shape.defineFigureGenerator("BpmnTaskManual", function (shape, w, h) {
              var geo = handGeo.copy();
              // calculate how much to scale the Geometry so that it fits in w x h
              var bounds = geo.bounds;
              var scale = Math.min(w / bounds.width, h / bounds.height);
              geo.scale(scale, scale);
              // guess where text should go (in the hand)
              geo.spot1 = new go.Spot(0, 0.6, 10, 0);
              geo.spot2 = new go.Spot(1, 1);
              return geo;
          });
          // define the appearance of tooltips, shared by various templates
          var tooltiptemplate = $(go.Adornment, go.Panel.Auto, $(go.Shape, "RoundedRectangle", { fill: "whitesmoke", stroke: "gray" }), $(go.TextBlock, { margin: 3, editable: true }, new go.Binding("text", "", function (data) {
              if (data.item !== undefined)
                  return data.item;
              return "(unnamed item)";
          })));
          // conversion functions used by data Bindings
          function nodeActivityTaskTypeConverter(s) {
              var tasks = ["Empty",
                  "BpmnTaskMessage",
                  "BpmnTaskUser",
                  "BpmnTaskManual",
                  "BpmnTaskScript",
                  "BpmnTaskMessage",
                  "BpmnTaskService",
                  "InternalStorage"];
              if (s < tasks.length)
                  return tasks[s];
              return "NotAllowed"; // error
          }
          // location of event on boundary of Activity is based on the index of the event in the boundaryEventArray
          function nodeActivityBESpotConverter(s) {
              var x = 10 + (EventNodeSize / 2);
              if (s === 0)
                  return new go.Spot(0, 1, x, 0); // bottom left
              if (s === 1)
                  return new go.Spot(1, 1, -x, 0); // bottom right
              if (s === 2)
                  return new go.Spot(1, 0, -x, 0); // top right
              return new go.Spot(1, 0, -x - (s - 2) * EventNodeSize, 0); // top ... right-to-left-ish spread
          }
          function nodeActivityTaskTypeColorConverter(s) {
              return (s == 5) ? "dimgray" : "white";
          }
          function nodeEventTypeConverter(s) {
              var tasks = ["NotAllowed",
                  "Empty",
                  "BpmnTaskMessage",
                  "BpmnEventTimer",
                  "BpmnEventEscalation",
                  "BpmnEventConditional",
                  "Arrow",
                  "BpmnEventError",
                  "ThinX",
                  "BpmnActivityCompensation",
                  "Triangle",
                  "Pentagon",
                  "ThickCross",
                  "Circle"];
              if (s < tasks.length)
                  return tasks[s];
              return "NotAllowed"; // error
          }
          function nodeEventDimensionStrokeColorConverter(s) {
              if (s === 8)
                  return EventDimensionStrokeEndColor;
              return EventDimensionStrokeColor;
          }
          function nodeEventDimensionSymbolFillConverter(s) {
              if (s <= 6)
                  return EventSymbolLightFill;
              return EventSymbolDarkFill;
          }
          //------------------------------------------  Activity Node Boundary Events   ----------------------------------------------
          var boundaryEventMenu = $(go.Adornment, "Vertical", $("ContextMenuButton", $(go.TextBlock, "Remove event"), 
          // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
          { click: function (e, obj) { removeActivityNodeBoundaryEvent(obj.part.adornedObject); } }));
          // removing a boundary event doesn't not reposition other BE circles on the node
          // just reassigning alignmentIndex in remaining BE would do that.
          function removeActivityNodeBoundaryEvent(obj) {
              myDiagram.startTransaction("removeBoundaryEvent");
              var pid = obj.portId;
              var arr = obj.panel.itemArray;
              for (var i = 0; i < arr.length; i++) {
                  if (arr[i].portId === pid) {
                      myDiagram.model.removeArrayItem(arr, i);
                      break;
                  }
              }
              myDiagram.commitTransaction("removeBoundaryEvent");
          }
          var boundaryEventItemTemplate = $(go.Panel, "Spot", {
              contextMenu: boundaryEventMenu,
              alignmentFocus: go.Spot.Center,
              fromLinkable: true, toLinkable: false, cursor: "pointer", fromSpot: go.Spot.Bottom,
              fromMaxLinks: 1, toMaxLinks: 0
          }, new go.Binding("portId", "portId"), new go.Binding("alignment", "alignmentIndex", nodeActivityBESpotConverter), $(go.Shape, "Circle", { desiredSize: new go.Size(EventNodeSize, EventNodeSize) }, new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; }), new go.Binding("fromSpot", "alignmentIndex", function (s) {
              //  nodeActivityBEFromSpotConverter, 0 & 1 go on bottom, all others on top of activity
              if (s < 2)
                  return go.Spot.Bottom;
              return go.Spot.Top;
          }), new go.Binding("fill", "color")), $(go.Shape, "Circle", {
              alignment: go.Spot.Center,
              desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize), fill: null
          }, new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; })), $(go.Shape, "NotAllowed", {
              alignment: go.Spot.Center,
              desiredSize: new go.Size(EventNodeSymbolSize, EventNodeSymbolSize), fill: "white"
          }, new go.Binding("figure", "eventType", nodeEventTypeConverter)));
          //------------------------------------------  Activity Node contextMenu   ----------------------------------------------
          var activityNodeMenu = $(go.Adornment, "Vertical", $("ContextMenuButton", $(go.TextBlock, "Add Email Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(2, 5); } }), $("ContextMenuButton", $(go.TextBlock, "Add Timer Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(3, 5); } }), $("ContextMenuButton", $(go.TextBlock, "Add Escalation Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(4, 5); } }), $("ContextMenuButton", $(go.TextBlock, "Add Error Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(7, 5); } }), $("ContextMenuButton", $(go.TextBlock, "Add Signal Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(10, 5); } }), $("ContextMenuButton", $(go.TextBlock, "Add N-I Escalation Event", { margin: 3 }), { click: function (e, obj) { addActivityNodeBoundaryEvent(4, 6); } }), $("ContextMenuButton", $(go.TextBlock, "Rename", { margin: 3 }), { click: function (e, obj) { rename(obj); } }));
          // sub-process,  loop, parallel, sequential, ad doc and compensation markers in horizontal array
          function makeSubButton(sub) {
              if (sub)
                  return [$("SubGraphExpanderButton"),
                      { margin: 2, visible: false },
                      new go.Binding("visible", "isSubProcess")];
              return [];
          }
          // sub-process,  loop, parallel, sequential, ad doc and compensation markers in horizontal array
          function makeMarkerPanel(sub, scale) {
              return $(go.Panel, "Horizontal", { alignment: go.Spot.MiddleBottom, alignmentFocus: go.Spot.MiddleBottom }, $(go.Shape, "BpmnActivityLoop", { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth }, new go.Binding("visible", "isLoop")), $(go.Shape, "BpmnActivityParallel", { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth }, new go.Binding("visible", "isParallel")), $(go.Shape, "BpmnActivitySequential", { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth }, new go.Binding("visible", "isSequential")), $(go.Shape, "BpmnActivityAdHoc", { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth }, new go.Binding("visible", "isAdHoc")), $(go.Shape, "BpmnActivityCompensation", { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth, fill: null }, new go.Binding("visible", "isCompensation")), makeSubButton(sub)); // end activity markers horizontal panel
          }
          var activityNodeTemplate = $(go.Node, "Spot", {
              locationObjectName: "SHAPE", locationSpot: go.Spot.Center,
              resizable: true, resizeObjectName: "PANEL",
              toolTip: tooltiptemplate,
              selectionAdorned: false,
              contextMenu: activityNodeMenu,
              itemTemplate: boundaryEventItemTemplate
          }, new go.Binding("itemArray", "boundaryEventArray"), new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), 
          // move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
          new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(), $(go.Panel, "Auto", {
              name: "PANEL",
              minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
              desiredSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight)
          }, new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify), $(go.Panel, "Spot", $(go.Shape, "RoundedRectangle", // the outside rounded rectangle
          {
              name: "SHAPE",
              fill: ActivityNodeFill, stroke: ActivityNodeStroke,
              parameter1: 10,
              portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
          }, new go.Binding("fill", "color"), new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })), 
          //        $(go.Shape, "RoundedRectangle",  // the inner "Transaction" rounded rectangle
          //          { margin: 3,
          //            stretch: go.GraphObject.Fill,
          //            stroke: ActivityNodeStroke,
          //            parameter1: 8, fill: null, visible: false
          //          },
          //          new go.Binding("visible", "isTransaction")
          //         ),
          // task icon
          $(go.Shape, "BpmnTaskScript", // will be None, Script, Manual, Service, etc via converter
          {
              alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
              width: 22, height: 22
          }, new go.Binding("fill", "taskType", nodeActivityTaskTypeColorConverter), new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)), // end Task Icon
          makeMarkerPanel(false, 1) // sub-process,  loop, parallel, sequential, ad doc and compensation markers
          ), // end main body rectangles spot panel
          $(go.TextBlock, // the center text
          {
              alignment: go.Spot.Center, textAlign: "center", margin: 12,
              editable: true
          }, new go.Binding("text").makeTwoWay())) // end Auto Panel
          ); // end go.Node, which is a Spot Panel with bound itemArray
          // ------------------------------- template for Activity / Task node in Palette  -------------------------------
          var palscale = 2;
          var activityNodeTemplateForPalette = $(go.Node, "Vertical", {
              locationObjectName: "SHAPE",
              locationSpot: go.Spot.Center,
              selectionAdorned: false
          }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Panel, "Spot", {
              name: "PANEL",
              desiredSize: new go.Size(ActivityNodeWidth / palscale, ActivityNodeHeight / palscale)
          }, $(go.Shape, "RoundedRectangle", // the outside rounded rectangle
          {
              name: "SHAPE",
              fill: ActivityNodeFill, stroke: ActivityNodeStroke,
              parameter1: 10 / palscale // corner size (default 10)
          }, new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })), $(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
          {
              margin: 3,
              stretch: go.GraphObject.Fill,
              stroke: ActivityNodeStroke,
              parameter1: 8 / palscale, fill: null, visible: false
          }, new go.Binding("visible", "isTransaction")), 
          // task icon
          $(go.Shape, "BpmnTaskScript", // will be None, Script, Manual, Service, etc via converter
          {
              alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
              width: 22 / palscale, height: 22 / palscale
          }, new go.Binding("fill", "taskType", nodeActivityTaskTypeColorConverter), new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)), makeMarkerPanel(false, palscale) // sub-process,  loop, parallel, sequential, ad doc and compensation markers
          ), // End Spot panel
          $(go.TextBlock, // the center text
          { alignment: go.Spot.Center, textAlign: "center", margin: 2 }, new go.Binding("text"))); // End Node
          var subProcessGroupTemplateForPalette = $(go.Group, "Vertical", {
              locationObjectName: "SHAPE",
              locationSpot: go.Spot.Center,
              isSubGraphExpanded: false,
              selectionAdorned: false
          }, $(go.Panel, "Spot", {
              name: "PANEL",
              desiredSize: new go.Size(ActivityNodeWidth / palscale, ActivityNodeHeight / palscale)
          }, $(go.Shape, "RoundedRectangle", // the outside rounded rectangle
          {
              name: "SHAPE",
              fill: ActivityNodeFill, stroke: ActivityNodeStroke,
              parameter1: 10 / palscale // corner size (default 10)
          }, new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })), $(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
          {
              margin: 3,
              stretch: go.GraphObject.Fill,
              stroke: ActivityNodeStroke,
              parameter1: 8 / palscale, fill: null, visible: false
          }, new go.Binding("visible", "isTransaction")), makeMarkerPanel(true, palscale) // sub-process,  loop, parallel, sequential, ad doc and compensation markers
          ), // end main body rectangles spot panel
          $(go.TextBlock, // the center text
          { alignment: go.Spot.Center, textAlign: "center", margin: 2 }, new go.Binding("text"))); // end go.Group
          //------------------------------------------  Event Node Template  ----------------------------------------------
          var eventNodeTemplate = $(go.Node, "Vertical", {
              locationObjectName: "SHAPE",
              locationSpot: go.Spot.Center,
              toolTip: tooltiptemplate
          }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), 
          // move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
          new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(), 
          // can be resided according to the user's desires
          { resizable: false, resizeObjectName: "SHAPE" }, $(go.Panel, "Spot", $(go.Shape, "Circle", // Outer circle
          {
              strokeWidth: 1,
              name: "SHAPE",
              desiredSize: new go.Size(EventNodeSize, EventNodeSize),
              portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
          }, 
          // allows the color to be determined by the node data
          new go.Binding("fill", "eventDimension", function (s) { return (s === 8) ? EventEndOuterFillColor : EventBackgroundColor; }), new go.Binding("strokeWidth", "eventDimension", function (s) { return s === 8 ? EventNodeStrokeWidthIsEnd : 1; }), new go.Binding("stroke", "eventDimension", nodeEventDimensionStrokeColorConverter), new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 3 || s === 6) ? [4, 2] : null; }), new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)), // end main shape
          $(go.Shape, "Circle", // Inner circle
          { alignment: go.Spot.Center, desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize), fill: null }, new go.Binding("stroke", "eventDimension", nodeEventDimensionStrokeColorConverter), new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 3 || s === 6) ? [4, 2] : null; }), // dashes for non-interrupting
          new go.Binding("visible", "eventDimension", function (s) { return s > 3 && s <= 7; }) // inner  only visible for 4 thru 7
          ), $(go.Shape, "NotAllowed", { alignment: go.Spot.Center, desiredSize: new go.Size(EventNodeSymbolSize, EventNodeSymbolSize), stroke: "black" }, new go.Binding("figure", "eventType", nodeEventTypeConverter), new go.Binding("fill", "eventDimension", nodeEventDimensionSymbolFillConverter))), // end Auto Panel
          $(go.TextBlock, { alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: true }, new go.Binding("text").makeTwoWay())); // end go.Node Vertical
          //------------------------------------------  Gateway Node Template   ----------------------------------------------
          function nodeGatewaySymbolTypeConverter(s) {
              var tasks = ["NotAllowed",
                  "ThinCross",
                  "Circle",
                  "AsteriskLine",
                  "ThinX",
                  "Pentagon",
                  "Pentagon",
                  "ThickCross"]; // 7 - parallel event gateway to start a process (single circle)
              if (s < tasks.length)
                  return tasks[s];
              return "NotAllowed"; // error
          }
          // tweak the size of some of the gateway icons
          function nodeGatewaySymbolSizeConverter(s) {
              var size = new go.Size(GatewayNodeSymbolSize, GatewayNodeSymbolSize);
              if (s === 4) {
                  size.width = size.width / 4 * 3;
                  size.height = size.height / 4 * 3;
              }
              else if (s > 4) {
                  size.width = size.width / 1.6;
                  size.height = size.height / 1.6;
              }
              return size;
          }
          function nodePalGatewaySymbolSizeConverter(s) {
              var size = nodeGatewaySymbolSizeConverter(s);
              size.width = size.width / 2;
              size.height = size.height / 2;
              return size;
          }
          var gatewayNodeTemplate = $(go.Node, "Vertical", {
              locationObjectName: "SHAPE",
              locationSpot: go.Spot.Center,
              toolTip: tooltiptemplate
          }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), 
          // move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
          new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(), 
          // can be resided according to the user's desires
          { resizable: false, resizeObjectName: "SHAPE" }, $(go.Panel, "Spot", $(go.Shape, "Diamond", {
              strokeWidth: 1, fill: GatewayNodeFill, stroke: GatewayNodeStroke,
              name: "SHAPE",
              desiredSize: new go.Size(GatewayNodeSize, GatewayNodeSize),
              portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fromSpot: go.Spot.NotLeftSide, toSpot: go.Spot.MiddleLeft
          }, new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)), // end main shape
          $(go.Shape, "NotAllowed", { alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke, fill: GatewayNodeSymbolFill }, new go.Binding("figure", "gatewayType", nodeGatewaySymbolTypeConverter), 
          //new go.Binding("visible", "gatewayType", function(s) { return s !== 4; }),   // comment out if you want exclusive gateway to be X instead of blank.
          new go.Binding("strokeWidth", "gatewayType", function (s) { return (s <= 4) ? GatewayNodeSymbolStrokeWidth : 1; }), new go.Binding("desiredSize", "gatewayType", nodeGatewaySymbolSizeConverter)), 
          // the next 2 circles only show up for event gateway
          $(go.Shape, "Circle", // Outer circle
          {
              strokeWidth: 1, stroke: GatewayNodeSymbolStroke, fill: null, desiredSize: new go.Size(EventNodeSize, EventNodeSize)
          }, new go.Binding("visible", "gatewayType", function (s) { return s >= 5; }) // only visible for > 5
          ), // end main shape
          $(go.Shape, "Circle", // Inner circle
          {
              alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke,
              desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize),
              fill: null
          }, new go.Binding("visible", "gatewayType", function (s) { return s === 5; }) // inner  only visible for == 5
          )), $(go.TextBlock, { alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: true }, new go.Binding("text").makeTwoWay())); // end go.Node Vertical
          //--------------------------------------------------------------------------------------------------------------
          var gatewayNodeTemplateForPalette = $(go.Node, "Vertical", {
              toolTip: tooltiptemplate,
              resizable: false,
              locationObjectName: "SHAPE",
              locationSpot: go.Spot.Center,
              resizeObjectName: "SHAPE"
          }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Panel, "Spot", $(go.Shape, "Diamond", {
              strokeWidth: 1, fill: GatewayNodeFill, stroke: GatewayNodeStroke, name: "SHAPE",
              desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 2)
          }), $(go.Shape, "NotAllowed", { alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke, strokeWidth: GatewayNodeSymbolStrokeWidth, fill: GatewayNodeSymbolFill }, new go.Binding("figure", "gatewayType", nodeGatewaySymbolTypeConverter), 
          //new go.Binding("visible", "gatewayType", function(s) { return s !== 4; }),   // comment out if you want exclusive gateway to be X instead of blank.
          new go.Binding("strokeWidth", "gatewayType", function (s) { return (s <= 4) ? GatewayNodeSymbolStrokeWidth : 1; }), new go.Binding("desiredSize", "gatewayType", nodePalGatewaySymbolSizeConverter)), 
          // the next 2 circles only show up for event gateway
          $(go.Shape, "Circle", // Outer circle
          {
              strokeWidth: 1, stroke: GatewayNodeSymbolStroke, fill: null, desiredSize: new go.Size(EventNodeSize / 2, EventNodeSize / 2)
          }, 
          //new go.Binding("desiredSize", "gatewayType", new go.Size(EventNodeSize/2, EventNodeSize/2)),
          new go.Binding("visible", "gatewayType", function (s) { return s >= 5; }) // only visible for > 5
          ), // end main shape
          $(go.Shape, "Circle", // Inner circle
          {
              alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke,
              desiredSize: new go.Size(EventNodeInnerSize / 2, EventNodeInnerSize / 2),
              fill: null
          }, new go.Binding("visible", "gatewayType", function (s) { return s === 5; }) // inner  only visible for == 5
          )), $(go.TextBlock, { alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: false }, new go.Binding("text")));
          //--------------------------------------------------------------------------------------------------------------
          var annotationNodeTemplate = $(go.Node, "Auto", { background: GradientLightGray, locationSpot: go.Spot.Center }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, "Annotation", // A left bracket shape
          { portId: "", fromLinkable: true, cursor: "pointer", fromSpot: go.Spot.Left, strokeWidth: 2, stroke: "gray" }), $(go.TextBlock, { margin: 5, editable: true }, new go.Binding("text").makeTwoWay()));
          var dataObjectNodeTemplate = $(go.Node, "Vertical", { locationObjectName: "SHAPE", locationSpot: go.Spot.Center }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, "File", {
              name: "SHAPE", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fill: DataFill, desiredSize: new go.Size(EventNodeSize * 0.8, EventNodeSize)
          }), $(go.TextBlock, {
              margin: 5,
              editable: true
          }, new go.Binding("text").makeTwoWay()));
          var dataStoreNodeTemplate = $(go.Node, "Vertical", { locationObjectName: "SHAPE", locationSpot: go.Spot.Center }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, "Database", {
              name: "SHAPE", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fill: DataFill, desiredSize: new go.Size(EventNodeSize, EventNodeSize)
          }), $(go.TextBlock, { margin: 5, editable: true }, new go.Binding("text").makeTwoWay()));
          //------------------------------------------  private process Node Template Map   ----------------------------------------------
          var privateProcessNodeTemplate = $(go.Node, "Auto", { layerName: "Background", resizable: true, resizeObjectName: "LANE" }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, "Rectangle", { fill: null }), $(go.Panel, "Table", // table with 2 cells to hold header and lane
          {
              desiredSize: new go.Size(ActivityNodeWidth * 6, ActivityNodeHeight),
              background: DataFill, name: "LANE", minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight * 0.667)
          }, new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify), $(go.TextBlock, {
              row: 0, column: 0,
              angle: 270, margin: 5,
              editable: true, textAlign: "center"
          }, new go.Binding("text").makeTwoWay()), $(go.RowColumnDefinition, { column: 1, separatorStrokeWidth: 1, separatorStroke: "black" }), $(go.Shape, "Rectangle", {
              row: 0, column: 1,
              stroke: null, fill: "transparent",
              portId: "", fromLinkable: true, toLinkable: true,
              fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides,
              cursor: "pointer", stretch: go.GraphObject.Fill
          })));
          var privateProcessNodeTemplateForPalette = $(go.Node, "Vertical", { locationSpot: go.Spot.Center }, $(go.Shape, "Process", { fill: DataFill, desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }), $(go.TextBlock, { margin: 5, editable: true }, new go.Binding("text")));
          var poolTemplateForPalette = $(go.Group, "Vertical", {
              locationSpot: go.Spot.Center,
              computesBoundsIncludingLinks: false,
              isSubGraphExpanded: false
          }, $(go.Shape, "Process", { fill: "white", desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }), $(go.Shape, "Process", { fill: "white", desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }), $(go.TextBlock, { margin: 5, editable: true }, new go.Binding("text")));
          var swimLanesGroupTemplateForPalette = $(go.Group, "Vertical"); // empty in the palette
          var subProcessGroupTemplate = $(go.Group, "Spot", {
              locationSpot: go.Spot.Center,
              locationObjectName: "PH",
              //locationSpot: go.Spot.Center,
              isSubGraphExpanded: false,
              memberValidation: function (group, part) {
                  return !(part instanceof go.Group) ||
                      (part.category !== "Pool" && part.category !== "Lane");
              },
              mouseDrop: function (e, grp) {
                  var ok = grp.addMembers(grp.diagram.selection, true);
                  if (!ok)
                      grp.diagram.currentTool.doCancel();
              },
              contextMenu: activityNodeMenu,
              itemTemplate: boundaryEventItemTemplate
          }, new go.Binding("itemArray", "boundaryEventArray"), new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), 
          // move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
          // new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
          $(go.Panel, "Auto", $(go.Shape, "RoundedRectangle", {
              name: "PH", fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
              minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
              portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
              fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
          }, new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })), $(go.Panel, "Vertical", { defaultAlignment: go.Spot.Left }, $(go.TextBlock, // label
          { margin: 3, editable: true }, new go.Binding("text", "text").makeTwoWay(), new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })), 
          // create a placeholder to represent the area where the contents of the group are
          $(go.Placeholder, { padding: new go.Margin(5, 5) }), makeMarkerPanel(true, 1) // sub-process,  loop, parallel, sequential, ad doc and compensation markers
          ) // end Vertical Panel
          )); // end Group
          //** need this in the subprocess group template above.
          //        $(go.Shape, "RoundedRectangle",  // the inner "Transaction" rounded rectangle
          //          { margin: 3,
          //            stretch: go.GraphObject.Fill,
          //            stroke: ActivityNodeStroke,
          //            parameter1: 8, fill: null, visible: false
          //          },
          //          new go.Binding("visible", "isTransaction")
          //         ),
          function groupStyle() {
              return [
                  {
                      layerName: "Background",
                      background: "transparent",
                      movable: true,
                      copyable: false,
                      avoidable: false // don't impede AvoidsNodes routed Links
                  },
                  new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify)
              ];
          }
          // hide links between lanes when either lane is collapsed
          function updateCrossLaneLinks(group) {
              group.findExternalLinksConnected().each(function (l) {
                  l.visible = (l.fromNode.isVisible() && l.toNode.isVisible());
              });
          }
          var laneEventMenu = $(go.Adornment, "Vertical", $("ContextMenuButton", $(go.TextBlock, "Add Lane"), 
          // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
          { click: function (e, obj) { addLaneEvent(obj.part.adornedObject); } }));
          // Add a lane to pool (lane parameter is lane above new lane)
          function addLaneEvent(lane) {
              myDiagram.startTransaction("addLane");
              if (lane != null && lane.data.category === "Lane") {
                  // create a new lane data object
                  var shape = lane.findObject("SHAPE");
                  var size = new go.Size(shape.width, MINBREADTH);
                  //size.height = MINBREADTH;
                  var newlanedata = {
                      category: "Lane",
                      text: "New Lane",
                      color: "white",
                      isGroup: true,
                      loc: go.Point.stringify(new go.Point(lane.location.x, lane.location.y + 1)),
                      size: go.Size.stringify(size),
                      group: lane.data.group
                  };
                  // and add it to the model
                  myDiagram.model.addNodeData(newlanedata);
              }
              myDiagram.commitTransaction("addLane");
          }
          var swimLanesGroupTemplate = $(go.Group, "Spot", groupStyle(), {
              name: "Lane",
              contextMenu: laneEventMenu,
              minLocation: new go.Point(NaN, -Infinity),
              maxLocation: new go.Point(NaN, Infinity),
              selectionObjectName: "SHAPE",
              resizable: true, resizeObjectName: "SHAPE",
              layout: $(go.LayeredDigraphLayout, // automatically lay out the lane's subgraph
              {
                  isInitial: false,
                  isOngoing: false,
                  direction: 0,
                  columnSpacing: 10,
                  layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
              }),
              computesBoundsAfterDrag: true,
              computesBoundsIncludingLinks: false,
              computesBoundsIncludingLocation: true,
              handlesDragDropForMembers: true,
              mouseDrop: function (e, grp) {
                  // don't allow drag-and-dropping a mix of regular Nodes and Groups
                  if (!e.diagram.selection.any(function (n) { return (n instanceof go.Group && n.category !== "subprocess") || n.category === "privateProcess"; })) {
                      var ok = grp.addMembers(grp.diagram.selection, true);
                      if (ok) {
                          updateCrossLaneLinks(grp);
                          relayoutDiagram();
                      }
                      else {
                          grp.diagram.currentTool.doCancel();
                      }
                  }
              },
              subGraphExpandedChanged: function (grp) {
                  var shp = grp.resizeObject;
                  if (grp.diagram.undoManager.isUndoingRedoing)
                      return;
                  if (grp.isSubGraphExpanded) {
                      shp.height = grp["_savedBreadth"];
                  }
                  else {
                      grp["_savedBreadth"] = shp.height;
                      shp.height = NaN;
                  }
                  updateCrossLaneLinks(grp);
              }
          }, 
          //new go.Binding("isSubGraphExpanded", "expanded").makeTwoWay(),
          $(go.Shape, "Rectangle", // this is the resized object
          { name: "SHAPE", fill: "white", stroke: null }, // need stroke null here or you gray out some of pool border.
          new go.Binding("fill", "color"), new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)), 
          // the lane header consisting of a Shape and a TextBlock
          $(go.Panel, "Horizontal", {
              name: "HEADER",
              angle: 270,
              alignment: go.Spot.LeftCenter, alignmentFocus: go.Spot.LeftCenter
          }, $(go.TextBlock, // the lane label
          { editable: true, margin: new go.Margin(2, 0, 0, 8) }, new go.Binding("visible", "isSubGraphExpanded").ofObject(), new go.Binding("text", "text").makeTwoWay()), $("SubGraphExpanderButton", { margin: 4, angle: -270 }) // but this remains always visible!
          ), // end Horizontal Panel
          $(go.Placeholder, { padding: 12, alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft }), $(go.Panel, "Horizontal", { alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft }, $(go.TextBlock, // this TextBlock is only seen when the swimlane is collapsed
          {
              name: "LABEL",
              editable: true, visible: false,
              angle: 0, margin: new go.Margin(6, 0, 0, 20)
          }, new go.Binding("visible", "isSubGraphExpanded", function (e) { return !e; }).ofObject(), new go.Binding("text", "text").makeTwoWay()))); // end swimLanesGroupTemplate
          // define a custom resize adornment that has two resize handles if the group is expanded
          //myDiagram.groupTemplate.resizeAdornmentTemplate =
          swimLanesGroupTemplate.resizeAdornmentTemplate =
              $(go.Adornment, "Spot", $(go.Placeholder), $(go.Shape, // for changing the length of a lane
              {
                  alignment: go.Spot.Right,
                  desiredSize: new go.Size(7, 50),
                  fill: "lightblue", stroke: "dodgerblue",
                  cursor: "col-resize"
              }, new go.Binding("visible", "", function (ad) {
                  if (ad.adornedPart === null)
                      return false;
                  return ad.adornedPart.isSubGraphExpanded;
              }).ofObject()), $(go.Shape, // for changing the breadth of a lane
              {
                  alignment: go.Spot.Bottom,
                  desiredSize: new go.Size(50, 7),
                  fill: "lightblue", stroke: "dodgerblue",
                  cursor: "row-resize"
              }, new go.Binding("visible", "", function (ad) {
                  if (ad.adornedPart === null)
                      return false;
                  return ad.adornedPart.isSubGraphExpanded;
              }).ofObject()));
          var poolGroupTemplate = $(go.Group, "Auto", groupStyle(), {
              computesBoundsIncludingLinks: false,
              // use a simple layout that ignores links to stack the "lane" Groups on top of each other
              layout: $(PoolLayout, { spacing: new go.Size(0, 0) }) // no space between lanes
          }, new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), $(go.Shape, { fill: "white" }, new go.Binding("fill", "color")), $(go.Panel, "Table", { defaultColumnSeparatorStroke: "black" }, $(go.Panel, "Horizontal", { column: 0, angle: 270 }, $(go.TextBlock, { editable: true, margin: new go.Margin(5, 0, 5, 0) }, // margin matches private process (black box pool)
          new go.Binding("text").makeTwoWay())), $(go.Placeholder, { background: "darkgray", column: 1 }))); // end poolGroupTemplate
          //------------------------------------------  Template Maps  ----------------------------------------------
          // create the nodeTemplateMap, holding main view node templates:
          var nodeTemplateMap = new go.Map("string", go.Node);
          // for each of the node categories, specify which template to use
          nodeTemplateMap.add("activity", activityNodeTemplate);
          nodeTemplateMap.add("event", eventNodeTemplate);
          nodeTemplateMap.add("gateway", gatewayNodeTemplate);
          nodeTemplateMap.add("annotation", annotationNodeTemplate);
          nodeTemplateMap.add("dataobject", dataObjectNodeTemplate);
          nodeTemplateMap.add("datastore", dataStoreNodeTemplate);
          nodeTemplateMap.add("privateProcess", privateProcessNodeTemplate);
          // for the default category, "", use the same template that Diagrams use by default
          // this just shows the key value as a simple TextBlock
          var groupTemplateMap = new go.Map("string", go.Group);
          groupTemplateMap.add("subprocess", subProcessGroupTemplate);
          groupTemplateMap.add("Lane", swimLanesGroupTemplate);
          groupTemplateMap.add("Pool", poolGroupTemplate);
          // create the nodeTemplateMap, holding special palette "mini" node templates:
          var palNodeTemplateMap = new go.Map("string", go.Node);
          palNodeTemplateMap.add("activity", activityNodeTemplateForPalette);
          palNodeTemplateMap.add("event", eventNodeTemplate);
          palNodeTemplateMap.add("gateway", gatewayNodeTemplateForPalette);
          palNodeTemplateMap.add("annotation", annotationNodeTemplate);
          palNodeTemplateMap.add("dataobject", dataObjectNodeTemplate);
          palNodeTemplateMap.add("datastore", dataStoreNodeTemplate);
          palNodeTemplateMap.add("privateProcess", privateProcessNodeTemplateForPalette);
          var palGroupTemplateMap = new go.Map("string", go.Group);
          palGroupTemplateMap.add("subprocess", subProcessGroupTemplateForPalette);
          palGroupTemplateMap.add("Pool", poolTemplateForPalette);
          palGroupTemplateMap.add("Lane", swimLanesGroupTemplateForPalette);
          //------------------------------------------  Link Templates   ----------------------------------------------
          var sequenceLinkTemplate = $(go.Link, {
              contextMenu: $(go.Adornment, "Vertical", $("ContextMenuButton", $(go.TextBlock, "Default Flow"), 
              // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
              { click: function (e, obj) { setSequenceLinkDefaultFlow(obj.part.adornedObject); } }), $("ContextMenuButton", $(go.TextBlock, "Conditional Flow"), 
              // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
              { click: function (e, obj) { setSequenceLinkConditionalFlow(obj.part.adornedObject); } })),
              routing: go.Link.AvoidsNodes, curve: go.Link.JumpGap, corner: 10,
              //fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide,
              reshapable: true, relinkableFrom: true, relinkableTo: true, toEndSegmentLength: 20
          }, new go.Binding("points").makeTwoWay(), $(go.Shape, { stroke: "black", strokeWidth: 1 }), $(go.Shape, { toArrow: "Triangle", scale: 1.2, fill: "black", stroke: null }), $(go.Shape, { fromArrow: "", scale: 1.5, stroke: "black", fill: "white" }, new go.Binding("fromArrow", "isDefault", function (s) {
              if (s === null)
                  return "";
              return s ? "BackSlash" : "StretchedDiamond";
          }), new go.Binding("segmentOffset", "isDefault", function (s) {
              return s ? new go.Point(5, 0) : new go.Point(0, 0);
          })), $(go.TextBlock, {
              name: "Label", editable: true, text: "label", segmentOffset: new go.Point(-10, -10), visible: false
          }, new go.Binding("text", "text").makeTwoWay(), new go.Binding("visible", "visible").makeTwoWay()));
          // set Default Sequence Flow (backslash From Arrow)
          function setSequenceLinkDefaultFlow(obj) {
              myDiagram.startTransaction("setSequenceLinkDefaultFlow");
              var model = myDiagram.model;
              model.setDataProperty(obj.data, "isDefault", true);
              // Set all other links from the fromNode to be isDefault=null
              obj.fromNode.findLinksOutOf().each(function (link) {
                  if (link !== obj && link.data.isDefault) {
                      model.setDataProperty(link.data, "isDefault", null);
                  }
              });
              myDiagram.commitTransaction("setSequenceLinkDefaultFlow");
          }
          // set Conditional Sequence Flow (diamond From Arrow)
          function setSequenceLinkConditionalFlow(obj) {
              myDiagram.startTransaction("setSequenceLinkConditionalFlow");
              var model = myDiagram.model;
              model.setDataProperty(obj.data, "isDefault", false);
              myDiagram.commitTransaction("setSequenceLinkConditionalFlow");
          }
          var messageFlowLinkTemplate = $(BPMNClasses_1.PoolLink, // defined in BPMNClasses.js
          {
              routing: go.Link.Orthogonal, curve: go.Link.JumpGap, corner: 10,
              fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides,
              reshapable: true, relinkableTo: true, toEndSegmentLength: 20
          }, new go.Binding("points").makeTwoWay(), $(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [6, 2] }), $(go.Shape, { toArrow: "Triangle", scale: 1, fill: "white", stroke: "black" }), $(go.Shape, { fromArrow: "Circle", scale: 1, visible: true, stroke: "black", fill: "white" }), $(go.TextBlock, {
              editable: true, text: "label"
          }, // Link label
          new go.Binding("text", "text").makeTwoWay()));
          var dataAssociationLinkTemplate = $(go.Link, {
              routing: go.Link.AvoidsNodes, curve: go.Link.JumpGap, corner: 10,
              fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides,
              reshapable: true, relinkableFrom: true, relinkableTo: true
          }, new go.Binding("points").makeTwoWay(), $(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [1, 3] }), $(go.Shape, { toArrow: "OpenTriangle", scale: 1, fill: null, stroke: "blue" }));
          var annotationAssociationLinkTemplate = $(go.Link, {
              reshapable: true, relinkableFrom: true, relinkableTo: true,
              toSpot: go.Spot.AllSides,
              toEndSegmentLength: 20, fromEndSegmentLength: 40
          }, new go.Binding("points").makeTwoWay(), $(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [1, 3] }), $(go.Shape, { toArrow: "OpenTriangle", scale: 1, stroke: "black" }));
          var linkTemplateMap = new go.Map("string", go.Link);
          linkTemplateMap.add("msg", messageFlowLinkTemplate);
          linkTemplateMap.add("annotation", annotationAssociationLinkTemplate);
          linkTemplateMap.add("data", dataAssociationLinkTemplate);
          linkTemplateMap.add("", sequenceLinkTemplate); // default
          //------------------------------------------the main Diagram----------------------------------------------
          myDiagram =
              $(go.Diagram, "myDiagramDiv", {
                  nodeTemplateMap: nodeTemplateMap,
                  linkTemplateMap: linkTemplateMap,
                  groupTemplateMap: groupTemplateMap,
                  allowDrop: true,
                  commandHandler: new DrawCommandHandlerTool_1.DrawCommandHandlerTool(),
                  // default to having arrow keys move selected nodes
                  "commandHandler.arrowKeyBehavior": "move",
                  mouseDrop: function (e) {
                      // when the selection is dropped in the diagram's background,
                      // make sure the selected Parts no longer belong to any Group
                      var ok = myDiagram.commandHandler.addTopLevelParts(myDiagram.selection, true);
                      if (!ok)
                          myDiagram.currentTool.doCancel();
                  },
                  linkingTool: new BPMNClasses_1.BPMNLinkingTool(),
                  "SelectionMoved": relayoutDiagram,
                  "SelectionCopied": relayoutDiagram
              });
          myDiagram.toolManager.mouseDownTools.insertAt(0, new LaneResizingTool());
          myDiagram.addDiagramListener("LinkDrawn", function (e) {
              if (e.subject.fromNode.category === "annotation") {
                  e.subject.category = "annotation"; // annotation association
              }
              else if (e.subject.fromNode.category === "dataobject" || e.subject.toNode.category === "dataobject") {
                  e.subject.category = "data"; // data association
              }
              else if (e.subject.fromNode.category === "datastore" || e.subject.toNode.category === "datastore") {
                  e.subject.category = "data"; // data association
              }
          });
          //  uncomment this if you want a subprocess to expand on drop.  We decided we didn't like this behavior
          //  myDiagram.addDiagramListener("ExternalObjectsDropped", function(e) {
          //    // e.subject is the collection that was just dropped
          //    e.subject.each(function(part) {
          //        if (part instanceof go.Node && part.data.item === "end") {
          //          part.move(new go.Point(part.location.x  + 350, part.location.y))
          //        }
          //      });
          //    myDiagram.commandHandler.expandSubGraph();
          //  });
          // change the title to indicate that the diagram has been modified
          myDiagram.addDiagramListener("Modified", function (e) {
              var currentFile = document.getElementById("currentFile");
              var idx = currentFile.textContent.indexOf("*");
              if (myDiagram.isModified) {
                  if (idx < 0)
                      currentFile.textContent = currentFile.textContent + "*";
              }
              else {
                  if (idx >= 0)
                      currentFile.textContent = currentFile.textContent.substr(0, idx);
              }
          });
          //------------------------------------------  Palette   ----------------------------------------------
          // Make sure the pipes are ordered by their key in the palette inventory
          function keyCompare(a, b) {
              var at = a.data.key;
              var bt = b.data.key;
              if (at < bt)
                  return -1;
              if (at > bt)
                  return 1;
              return 0;
          }
          // initialize the first Palette, BPMN Spec Level 1
          var myPaletteLevel1 = $(go.Palette, "myPaletteLevel1", {
              nodeTemplateMap: palNodeTemplateMap,
              groupTemplateMap: palGroupTemplateMap,
              layout: $(go.GridLayout, {
                  cellSize: new go.Size(1, 1),
                  spacing: new go.Size(5, 5),
                  comparer: keyCompare
              })
          });
          // initialize the second Palette, BPMN Spec Level 2
          var myPaletteLevel2 = $(go.Palette, "myPaletteLevel2", {
              nodeTemplateMap: palNodeTemplateMap,
              groupTemplateMap: palGroupTemplateMap,
              layout: $(go.GridLayout, {
                  cellSize: new go.Size(1, 1),
                  spacing: new go.Size(5, 5),
                  comparer: keyCompare
              })
          });
          // initialize the third Palette, random other stuff
          var myPaletteLevel3 = $(go.Palette, "myPaletteLevel3", {
              nodeTemplateMap: palNodeTemplateMap,
              groupTemplateMap: palGroupTemplateMap,
              layout: $(go.GridLayout, {
                  cellSize: new go.Size(1, 1),
                  spacing: new go.Size(5, 5),
                  comparer: keyCompare
              })
          });
          jQuery("#accordion").accordion({
              activate: function (event, ui) {
                  myPaletteLevel1.requestUpdate();
                  myPaletteLevel2.requestUpdate();
              }
          });
          myPaletteLevel1.model = $(go.GraphLinksModel, {
              copiesArrays: true,
              copiesArrayObjects: true,
              nodeDataArray: [
                  // -------------------------- Event Nodes
                  { key: 101, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start" },
                  { key: 102, category: "event", text: "Message", eventType: 2, eventDimension: 2, item: "Message" },
                  { key: 103, category: "event", text: "Timer", eventType: 3, eventDimension: 3, item: "Timer" },
                  { key: 104, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "End" },
                  { key: 107, category: "event", text: "Message", eventType: 2, eventDimension: 8, item: "Message" },
                  { key: 108, category: "event", text: "Terminate", eventType: 13, eventDimension: 8, item: "Terminate" },
                  // -------------------------- Task/Activity Nodes
                  { key: 131, category: "activity", text: "Task", item: "generic task", taskType: 0 },
                  { key: 132, category: "activity", text: "User Task", item: "User task", taskType: 2 },
                  { key: 133, category: "activity", text: "Service\nTask", item: "service task", taskType: 6 },
                  // subprocess and start and end
                  { key: 134, category: "subprocess", loc: "0 0", text: "Subprocess", isGroup: true, isSubProcess: true, taskType: 0 },
                  { key: -802, category: "event", loc: "0 0", group: 134, text: "Start", eventType: 1, eventDimension: 1, item: "start" },
                  { key: -803, category: "event", loc: "350 0", group: 134, text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end" },
                  // -------------------------- Gateway Nodes, Data, Pool and Annotation
                  { key: 201, category: "gateway", text: "Parallel", gatewayType: 1 },
                  { key: 204, category: "gateway", text: "Exclusive", gatewayType: 4 },
                  { key: 301, category: "dataobject", text: "Data\nObject" },
                  { key: 302, category: "datastore", text: "Data\nStorage" },
                  { key: 401, category: "privateProcess", text: "Black Box" },
                  { key: "501", "text": "Pool 1", "isGroup": "true", "category": "Pool" },
                  { key: "Lane5", "text": "Lane 1", "isGroup": "true", "group": "501", "color": "lightyellow", "category": "Lane" },
                  { key: "Lane6", "text": "Lane 2", "isGroup": "true", "group": "501", "color": "lightgreen", "category": "Lane" },
                  { key: 701, category: "annotation", text: "note" }
              ] // end nodeDataArray
          }); // end model
          // an activity with a boundary event:
          //        {
          //          key: 1,
          //          category: "activity",
          //          text: "Message",
          //          taskType: 1,
          //          item: "Message Task",
          //          boundaryEventArray: [{ "portId": "be0", alignmentIndex: 0, eventType: 2, color: "white" }]   // portId # and alignmentIndex should match
          //        },
          myPaletteLevel2.model = $(go.GraphLinksModel, {
              copiesArrays: true,
              copiesArrayObjects: true,
              nodeDataArray: [
                  { key: 1, category: "activity", taskType: 1, text: "Receive Task", item: "Receive Task" },
                  { key: 2, category: "activity", taskType: 5, text: "Send Task", item: "Send Task" },
                  { key: 3, category: "activity", taskType: 7, text: "Business\nRule Task", item: "Business Rule Task" },
                  { key: 4, category: "activity", taskType: 2, text: "User Task", item: "User Task", isCall: true },
                  { key: 101, text: "Adhoc\nSubprocess", isGroup: true, isSubProcess: true, category: "subprocess", isAdHoc: true, taskType: 0, loc: "0 0" },
                  { key: -812, group: 101, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start", loc: "0 0" },
                  { key: -813, group: 101, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end" },
                  { key: 102, text: "Transactional\nSubprocess", isGroup: true, isSubProcess: true, category: "subprocess", isTransaction: true, taskType: 0, loc: "0 0" },
                  { key: -822, group: 102, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start", loc: "0 0" },
                  { key: -823, group: 102, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end", loc: "350 0" },
                  { key: 103, text: "Looping\nActivity", isGroup: true, isLoop: true, isSubProcess: true, category: "subprocess", taskType: 0, loc: "0 0" },
                  { key: -831, group: 103, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start", loc: "0 0" },
                  { key: -832, group: 103, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end", loc: "350 0" },
                  { key: 104, text: "Multi-Instance\nActivity", isGroup: true, isSubProcess: true, isParallel: true, category: "subprocess", taskType: 0, loc: "0 0" },
                  { key: -841, group: 104, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start", loc: "0 0" },
                  { key: -842, group: 104, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end", loc: "350 0" },
                  { key: 105, text: "Call\nSubprocess", isGroup: true, isSubProcess: true, category: "subprocess", isCall: true, taskType: 0, loc: "0 0" },
                  { key: -861, group: 105, category: "event", text: "Start", eventType: 1, eventDimension: 1, item: "start", loc: "0 0" },
                  { key: -862, group: 105, category: "event", text: "End", eventType: 1, eventDimension: 8, item: "end", name: "end", loc: "350 0" },
                  // gateway nodes
                  { key: 301, category: "gateway", gatewayType: 2, text: "Inclusive" },
                  { key: 302, category: "gateway", gatewayType: 5, text: "Event\nGateway" },
                  // events
                  { key: 401, category: "event", eventType: 5, eventDimension: 1, text: "Conditional\nStart", item: "BpmnEventConditional" },
                  { key: 402, category: "event", eventType: 10, eventDimension: 1, text: "Signal\nStart", item: "BpmnEventSignal" },
                  { key: 403, category: "event", eventType: 10, eventDimension: 8, text: "Signal\nEnd", item: "end signal" },
                  { key: 404, category: "event", eventType: 7, eventDimension: 8, text: "Error", item: "BpmnEventError" },
                  { key: 405, category: "event", eventType: 4, eventDimension: 8, text: "Escalation", item: "BpmnEventEscalation" },
                  // throwing / catching intermedicate events
                  { key: 502, category: "event", eventType: 6, eventDimension: 4, text: "Catch\nLink", item: "BpmnEventOffPage" },
                  { key: 503, category: "event", eventType: 6, eventDimension: 7, text: "Throw\nLink", item: "BpmnEventOffPage" },
                  { key: 504, category: "event", eventType: 2, eventDimension: 4, text: "Catch\nMessage", item: "Message" },
                  { key: 505, category: "event", eventType: 2, eventDimension: 7, text: "Throw\nMessage", item: "Message" },
                  { key: 506, category: "event", eventType: 5, eventDimension: 4, text: "Catch\nConditional", item: "" },
                  { key: 507, category: "event", eventType: 3, eventDimension: 4, text: "Catch\nTimer", item: "" },
                  { key: 508, category: "event", eventType: 4, eventDimension: 7, text: "Throw\nEscalation", item: "Escalation" },
                  { key: 509, category: "event", eventType: 10, eventDimension: 4, text: "Catch\nSignal", item: "" },
                  { key: 510, category: "event", eventType: 10, eventDimension: 7, text: "Throw\nSignal", item: "" }
              ] // end nodeDataArray
          }); // end model
          myPaletteLevel3.model = $(go.GraphLinksModel, {
              copiesArrays: true,
              copiesArrayObjects: true,
              nodeDataArray: [
                  { key: 108, category: "event", eventType: 8, eventDimension: 5, text: "Cancel", item: "BpmnEventCancel" },
                  { key: 109, category: "event", eventType: 9, eventDimension: 5, text: "Compensation", item: "BpmnEventCompensation" },
                  { key: 111, category: "event", eventType: 11, eventDimension: 1, text: "Multiple", item: "Multiple" },
                  { key: 112, category: "event", eventType: 12, eventDimension: 1, text: "Parallel", item: "Parallel" },
                  // activity nodes
                  { key: 203, category: "activity", taskType: 3, isAdHoc: true, text: "Manual", item: "Manual Task" },
                  { key: 204, category: "activity", taskType: 4, isSequential: true, text: "Script", item: "Script Task" },
                  { key: 205, category: "activity", taskType: 5, isParallel: true, text: "Send Msg", item: "Send Msg Task" },
                  { key: 206, category: "activity", taskType: 6, isLoop: true, isSubProcess: true, isTransaction: true, text: "Service", item: "service task" },
                  // gateway nodes not in Level 1 or Level 2
                  { key: 603, category: "gateway", text: "Complex", gatewayType: 3 },
                  { key: 606, category: "gateway", text: "Exclusive Start", gatewayType: 6 },
                  { key: 607, category: "gateway", text: "Parallel Start", gatewayType: 7 },
                  {
                      key: 4, category: "activity", taskType: 2, text: "User Task", item: "User Task",
                      isCall: true, isLoop: true, isParallel: true, isSequential: true
                  }
              ] // end nodeDataArray
          }); // end model
          //------------------------------------------  Overview   ----------------------------------------------
          var myOverview = $(go.Overview, "myOverviewDiv", { observed: myDiagram, maxScale: 0.5, contentAlignment: go.Spot.Center });
          // change color of viewport border in Overview
          myOverview.box.elt(0).stroke = "dodgerblue";
          // start with a simple preset model:
          loadJSON("BPMNdata/OMG BPMN by Example Figure 5.1.json");
      } // end init
      exports.init = init;
      //------------------------------------------  pools / lanes   ----------------------------------------------
      // swimlanes
      var MINLENGTH = 400; // this controls the minimum length of any swimlane
      var MINBREADTH = 20; // this controls the minimum breadth of any non-collapsed swimlane
      // some shared functions
      // this is called after nodes have been moved or lanes resized, to layout all of the Pool Groups again
      function relayoutDiagram() {
          myDiagram.layout.invalidateLayout();
          myDiagram.findTopLevelGroups().each(function (g) { if (g.category === "Pool")
              g.layout.invalidateLayout(); });
          myDiagram.layoutDiagram();
      }
      // compute the minimum size of a Pool Group needed to hold all of the Lane Groups
      function computeMinPoolSize(pool) {
          // assert(pool instanceof go.Group && pool.category === "Pool");
          var len = MINLENGTH;
          pool.memberParts.each(function (lane) {
              // pools ought to only contain lanes, not plain Nodes
              if (!(lane instanceof go.Group))
                  return;
              var holder = lane.placeholder;
              if (holder !== null) {
                  var sz = holder.actualBounds;
                  len = Math.max(len, sz.width);
              }
          });
          return new go.Size(len, NaN);
      }
      // compute the minimum size for a particular Lane Group
      function computeLaneSize(lane) {
          // assert(lane instanceof go.Group && lane.category !== "Pool");
          var sz = computeMinLaneSize(lane);
          if (lane.isSubGraphExpanded) {
              var holder = lane.placeholder;
              if (holder !== null) {
                  var hsz = holder.actualBounds;
                  sz.height = Math.max(sz.height, hsz.height);
              }
          }
          // minimum breadth needs to be big enough to hold the header
          var hdr = lane.findObject("HEADER");
          if (hdr !== null)
              sz.height = Math.max(sz.height, hdr.actualBounds.height);
          return sz;
      }
      // determine the minimum size of a Lane Group, even if collapsed
      function computeMinLaneSize(lane) {
          if (!lane.isSubGraphExpanded)
              return new go.Size(MINLENGTH, 1);
          return new go.Size(MINLENGTH, MINBREADTH);
      }
      // define a custom ResizingTool to limit how far one can shrink a lane Group
      var LaneResizingTool = (function (_super) {
          __extends(LaneResizingTool, _super);
          function LaneResizingTool() {
              return _super !== null && _super.apply(this, arguments) || this;
          }
          LaneResizingTool.prototype.isLengthening = function () {
              return (this.handle.alignment === go.Spot.Right);
          };
          ;
          /** @override */
          LaneResizingTool.prototype.computeMinSize = function () {
              var lane = this.adornedObject.part;
              // assert(lane instanceof go.Group && lane.category !== "Pool");
              var msz = computeMinLaneSize(lane); // get the absolute minimum size
              if (this.isLengthening()) {
                  var sz = computeMinPoolSize(lane.containingGroup);
                  msz.width = Math.max(msz.width, sz.width);
              }
              else {
                  var sz = computeLaneSize(lane);
                  msz.width = Math.max(msz.width, sz.width);
                  msz.height = Math.max(msz.height, sz.height);
              }
              return msz;
          };
          ;
          /** @override */
          LaneResizingTool.prototype.canStart = function () {
              if (!go.ResizingTool.prototype.canStart.call(this))
                  return false;
              // if this is a resize handle for a "Lane", we can start.
              var diagram = this.diagram;
              if (diagram === null)
                  return;
              var handl = this.findToolHandleAt(diagram.firstInput.documentPoint, this.name);
              if (handl === null || handl.part === null || handl.part.adornedObject === null || handl.part.adornedObject.part === null)
                  return false;
              return (handl.part.adornedObject.part.category === "Lane");
          };
          /** @override */
          LaneResizingTool.prototype.resize = function (newr) {
              var lane = this.adornedObject.part;
              if (this.isLengthening()) {
                  lane.containingGroup.memberParts.each(function (lane) {
                      if (!(lane instanceof go.Group))
                          return;
                      var shape = lane.resizeObject;
                      if (shape !== null) {
                          shape.width = newr.width;
                      }
                  });
              }
              else {
                  _super.prototype.resize.call(this, newr);
              }
              relayoutDiagram(); // now that the lane has changed size, layout the pool again
          };
          ;
          return LaneResizingTool;
      }(go.ResizingTool));
      // end LaneResizingTool class
      // define a custom grid layout that makes sure the length of each lane is the same
      // and that each lane is broad enough to hold its subgraph
      var PoolLayout = (function (_super) {
          __extends(PoolLayout, _super);
          function PoolLayout() {
              var _this = _super !== null && _super.apply(this, arguments) || this;
              _this.cellSize = new go.Size(1, 1);
              _this.wrappingColumn = 1;
              _this.wrappingWidth = Infinity;
              _this.isRealtime = false; // don't continuously layout while dragging
              _this.alignment = go.GridLayout.Position;
              // This sorts based on the location of each Group.
              // This is useful when Groups can be moved up and down in order to change their order.
              _this.comparer = function (a, b) {
                  var ay = a.location.y;
                  var by = b.location.y;
                  if (isNaN(ay) || isNaN(by))
                      return 0;
                  if (ay < by)
                      return -1;
                  if (ay > by)
                      return 1;
                  return 0;
              };
              return _this;
          }
          /** @override */
          PoolLayout.prototype.doLayout = function (coll) {
              var diagram = this.diagram;
              if (diagram === null)
                  return;
              diagram.startTransaction("PoolLayout");
              var pool = this.group;
              if (pool !== null && pool.category === "Pool") {
                  // make sure all of the Group Shapes are big enough
                  var minsize = computeMinPoolSize(pool);
                  pool.memberParts.each(function (lane) {
                      if (!(lane instanceof go.Group))
                          return;
                      if (lane.category !== "Pool") {
                          var shape = lane.resizeObject;
                          if (shape !== null) {
                              var sz = computeLaneSize(lane);
                              shape.width = (isNaN(shape.width) ? minsize.width : Math.max(shape.width, minsize.width));
                              shape.height = (!isNaN(shape.height)) ? Math.max(shape.height, sz.height) : sz.height;
                              var cell = lane.resizeCellSize;
                              if (!isNaN(shape.width) && !isNaN(cell.width) && cell.width > 0)
                                  shape.width = Math.ceil(shape.width / cell.width) * cell.width;
                              if (!isNaN(shape.height) && !isNaN(cell.height) && cell.height > 0)
                                  shape.height = Math.ceil(shape.height / cell.height) * cell.height;
                          }
                      }
                  });
              }
              // now do all of the usual stuff, according to whatever properties have been set on this GridLayout
              _super.prototype.doLayout.call(this, coll);
              diagram.commitTransaction("PoolLayout");
          };
          ;
          return PoolLayout;
      }(go.GridLayout));
      // end PoolLayout class
      //------------------------------------------  Commands for this application  ----------------------------------------------
      // Add a port to the specified side of the selected nodes.   name is beN  (be0, be1)
      // evDim is 5 for Interrupting, 6 for non-Interrupting
      function addActivityNodeBoundaryEvent(evType, evDim) {
          myDiagram.startTransaction("addBoundaryEvent");
          myDiagram.selection.each(function (node) {
              // skip any selected Links
              if (!(node instanceof go.Node))
                  return;
              if (node.data && (node.data.category === "activity" || node.data.category === "subprocess")) {
                  // compute the next available index number for the side
                  var i = 0;
                  var defaultPort = node.findPort("");
                  while (node.findPort("be" + i.toString()) !== defaultPort)
                      i++; // now this new port name is unique within the whole Node because of the side prefix
                  var name = "be" + i.toString();
                  if (!node.data.boundaryEventArray) {
                      myDiagram.model.setDataProperty(node.data, "boundaryEventArray", []);
                  } // initialize the Array of port data if necessary
                  // create a new port data object
                  var newportdata = {
                      portId: name,
                      eventType: evType,
                      eventDimension: evDim,
                      color: "white",
                      alignmentIndex: i
                      // if you add port data properties here, you should copy them in copyPortData above  ** BUG...  we don't do that.
                  };
                  // and add it to the Array of port data
                  myDiagram.model.insertArrayItem(node.data.boundaryEventArray, -1, newportdata);
              }
          });
          myDiagram.commitTransaction("addBoundaryEvent");
      }
      exports.addActivityNodeBoundaryEvent = addActivityNodeBoundaryEvent;
      // changes the item of the object
      function rename(obj) {
          myDiagram.startTransaction("rename");
          var newName = prompt("Rename " + obj.part.data.item + " to:");
          myDiagram.model.setDataProperty(obj.part.data, "item", newName);
          myDiagram.commitTransaction("rename");
      }
      exports.rename = rename;
      // shows/hides gridlines
      // to be implemented onclick of a button
      function updateGridOption() {
          myDiagram.startTransaction("grid");
          var grid = document.getElementById("grid");
          myDiagram.grid.visible = grid.checked;
          myDiagram.commitTransaction("grid");
      }
      exports.updateGridOption = updateGridOption;
      // enables/disables snapping tools, to be implemented by buttons
      function updateSnapOption() {
          // no transaction needed, because we are modifying tools for future use
          var snap = document.getElementById("snap");
          if (snap.checked) {
              myDiagram.toolManager.draggingTool.isGridSnapEnabled = true;
              myDiagram.toolManager.resizingTool.isGridSnapEnabled = true;
          }
          else {
              myDiagram.toolManager.draggingTool.isGridSnapEnabled = false;
              myDiagram.toolManager.resizingTool.isGridSnapEnabled = false;
          }
      }
      exports.updateSnapOption = updateSnapOption;
      // user specifies the amount of space between nodes when making rows and column
      function askSpace() {
          var space = parseFloat(prompt("Desired space between nodes (in pixels):", "0"));
          return space;
      }
      exports.askSpace = askSpace;
      var UnsavedFileName = "(Unsaved File)";
      function getCurrentFileName() {
          var currentFile = document.getElementById("currentFile");
          var name = currentFile.textContent;
          if (name[name.length - 1] === "*")
              return name.substr(0, name.length - 1);
          return name;
      }
      exports.getCurrentFileName = getCurrentFileName;
      function setCurrentFileName(name) {
          var currentFile = document.getElementById("currentFile");
          if (myDiagram.isModified) {
              name += "*";
          }
          currentFile.textContent = name;
      }
      exports.setCurrentFileName = setCurrentFileName;
      function newDocument() {
          // checks to see if all changes have been saved
          if (myDiagram.isModified) {
              var save = confirm("Would you like to save changes to " + getCurrentFileName() + "?");
              if (save) {
                  saveDocument();
              }
          }
          setCurrentFileName(UnsavedFileName);
          // loads an empty diagram
          myDiagram.model = new go.GraphLinksModel();
          resetModel();
      }
      exports.newDocument = newDocument;
      function resetModel() {
          myDiagram.model.undoManager.isEnabled = true;
          myDiagram.model.linkFromPortIdProperty = "fromPort";
          myDiagram.model.linkToPortIdProperty = "toPort";
          myDiagram.model.copiesArrays = true;
          myDiagram.model.copiesArrayObjects = true;
          myDiagram.isModified = false;
      }
      exports.resetModel = resetModel;
      function checkLocalStorage() {
          return (typeof (Storage) !== "undefined") && (window.localStorage !== undefined);
      }
      exports.checkLocalStorage = checkLocalStorage;
      // saves the current floor plan to local storage
      function saveDocument() {
          if (checkLocalStorage()) {
              var saveName = getCurrentFileName();
              if (saveName === UnsavedFileName) {
                  saveDocumentAs();
              }
              else {
                  saveDiagramProperties();
                  window.localStorage.setItem(saveName, myDiagram.model.toJson());
                  myDiagram.isModified = false;
              }
          }
      }
      exports.saveDocument = saveDocument;
      // saves floor plan to local storage with a new name
      function saveDocumentAs() {
          if (checkLocalStorage()) {
              var saveName = prompt("Save file as...", getCurrentFileName());
              if (saveName && saveName !== UnsavedFileName) {
                  setCurrentFileName(saveName);
                  saveDiagramProperties();
                  window.localStorage.setItem(saveName, myDiagram.model.toJson());
                  myDiagram.isModified = false;
              }
          }
      }
      exports.saveDocumentAs = saveDocumentAs;
      // checks to see if all changes have been saved -> shows the open HTML element
      function openDocument() {
          if (checkLocalStorage()) {
              if (myDiagram.isModified) {
                  var save = confirm("Would you like to save changes to " + getCurrentFileName() + "?");
                  if (save) {
                      saveDocument();
                  }
              }
              openElement("openDocument", "mySavedFiles");
          }
      }
      exports.openDocument = openDocument;
      // shows the remove HTML element
      function removeDocument() {
          if (checkLocalStorage()) {
              openElement("removeDocument", "mySavedFiles2");
          }
      }
      exports.removeDocument = removeDocument;
      // these functions are called when panel buttons are clicked
      function loadFile() {
          var listbox = document.getElementById("mySavedFiles");
          // get selected filename
          var fileName = undefined;
          for (var i = 0; i < listbox.options.length; i++) {
              if (listbox.options[i].selected)
                  fileName = listbox.options[i].text; // selected file
          }
          if (fileName !== undefined) {
              // changes the text of "currentFile" to be the same as the floor plan now loaded
              setCurrentFileName(fileName);
              // actually load the model from the JSON format string
              var savedFile = window.localStorage.getItem(fileName);
              myDiagram.model = go.Model.fromJson(savedFile);
              loadDiagramProperties();
              myDiagram.model.undoManager.isEnabled = true;
              myDiagram.isModified = false;
              // eventually loadDiagramProperties will be called to finish
              // restoring shared saved model/diagram properties
          }
          closeElement("openDocument");
      }
      exports.loadFile = loadFile;
      function loadJSON(file) {
          jQuery.getJSON(file, function (jsondata) {
              // set these kinds of Diagram properties after initialization, not now
              myDiagram.addDiagramListener("InitialLayoutCompleted", loadDiagramProperties); // defined below
              // create the model from the data in the JavaScript object parsed from JSON text
              //myDiagram.model = new go.GraphLinksModel(jsondata["nodes"], jsondata["links"]);
              myDiagram.model = go.Model.fromJson(jsondata);
              loadDiagramProperties();
              myDiagram.model.undoManager.isEnabled = true;
              myDiagram.isModified = false;
          });
      }
      exports.loadJSON = loadJSON;
      // Store shared model state in the Model.modelData property
      // (will be loaded by loadDiagramProperties)
      function saveDiagramProperties() {
          myDiagram.model.modelData.position = go.Point.stringify(myDiagram.position);
      }
      exports.saveDiagramProperties = saveDiagramProperties;
      // Called by loadFile and loadJSON.
      function loadDiagramProperties(e) {
          // set Diagram.initialPosition, not Diagram.position, to handle initialization side-effects
          var pos = myDiagram.model.modelData.position;
          if (pos)
              myDiagram.initialPosition = go.Point.parse(pos);
      }
      exports.loadDiagramProperties = loadDiagramProperties;
      // deletes the selected file from local storage
      function removeFile() {
          var listbox = document.getElementById("mySavedFiles2");
          // get selected filename
          var fileName = undefined;
          for (var i = 0; i < listbox.options.length; i++) {
              if (listbox.options[i].selected)
                  fileName = listbox.options[i].text; // selected file
          }
          if (fileName !== undefined) {
              // removes file from local storage
              window.localStorage.removeItem(fileName);
              // the current document remains open, even if its storage was deleted
          }
          closeElement("removeDocument");
      }
      exports.removeFile = removeFile;
      function updateFileList(id) {
          // displays cached floor plan files in the listboxes
          var listbox = document.getElementById(id);
          // remove any old listing of files
          var last;
          while (last = listbox.lastChild)
              listbox.removeChild(last);
          // now add all saved files to the listbox
          for (var key in window.localStorage) {
              var storedFile = window.localStorage.getItem(key);
              if (!storedFile)
                  continue;
              var option = document.createElement("option");
              option.value = key;
              option.text = key;
              listbox.add(option, null);
          }
      }
      exports.updateFileList = updateFileList;
      function openElement(id, listid) {
          var panel = document.getElementById(id);
          if (panel.style.visibility === "hidden") {
              updateFileList(listid);
              panel.style.visibility = "visible";
          }
      }
      exports.openElement = openElement;
      // hides the open/remove elements when the "cancel" button is pressed
      function closeElement(id) {
          var panel = document.getElementById(id);
          if (panel.style.visibility === "visible") {
              panel.style.visibility = "hidden";
          }
      }
      exports.closeElement = closeElement;
      function undo() { myDiagram.commandHandler.undo(); }
      exports.undo = undo;
      function redo() { myDiagram.commandHandler.redo(); }
      exports.redo = redo;
      function cutSelection() { myDiagram.commandHandler.cutSelection(); }
      exports.cutSelection = cutSelection;
      function copySelection() { myDiagram.commandHandler.copySelection(); }
      exports.copySelection = copySelection;
      function pasteSelection() { myDiagram.commandHandler.pasteSelection(); }
      exports.pasteSelection = pasteSelection;
      function deleteSelection() { myDiagram.commandHandler.deleteSelection(); }
      exports.deleteSelection = deleteSelection;
      function selectAll() { myDiagram.commandHandler.selectAll(); }
      exports.selectAll = selectAll;
      function alignLeft() { myDiagram.commandHandler.alignLeft(); }
      exports.alignLeft = alignLeft;
      function alignRight() { myDiagram.commandHandler.alignRight(); }
      exports.alignRight = alignRight;
      function alignTop() { myDiagram.commandHandler.alignTop(); }
      exports.alignTop = alignTop;
      function alignBottom() { myDiagram.commandHandler.alignBottom(); }
      exports.alignBottom = alignBottom;
      function alignCemterX() { myDiagram.commandHandler.alignCenterX(); }
      exports.alignCemterX = alignCemterX;
      function alignCenterY() { myDiagram.commandHandler.alignCenterY(); }
      exports.alignCenterY = alignCenterY;
      function alignRows() { myDiagram.commandHandler.alignRow(askSpace()); }
      exports.alignRows = alignRows;
      function alignColumns() { myDiagram.commandHandler.alignColumn(askSpace()); }
      exports.alignColumns = alignColumns;
      function basicOrderProcess() { loadJSON("BPMNdata/BasicOrderProcess.json"); }
      exports.basicOrderProcess = basicOrderProcess;
      function BPMNdata51() { loadJSON("BPMNdata/OMG BPMN by Example Figure 5.1.json"); }
      exports.BPMNdata51 = BPMNdata51;
      function BPMNdata52() { loadJSON("BPMNdata/OMG BPMN by Example Figure 5.2.json"); }
      exports.BPMNdata52 = BPMNdata52;
      function BPMNdata53() { loadJSON("BPMNdata/OMG BPMN by Example Figure 5.3.json"); }
      exports.BPMNdata53 = BPMNdata53;
      function cancel1() { closeElement('openDocument'); }
      exports.cancel1 = cancel1;
      function cancel2() { closeElement('removeDocument'); }
      exports.cancel2 = cancel2;
  });
  