1/*!
2 * bpmn-js - bpmn-modeler v8.8.2
3 *
4 * Copyright (c) 2014-present, camunda Services GmbH
5 *
6 * Released under the bpmn.io license
7 * http://bpmn.io/license
8 *
9 * Source Code: https://github.com/bpmn-io/bpmn-js
10 *
11 * Date: 2021-10-20
12 */
13(function (global, factory) {
14	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
15	typeof define === 'function' && define.amd ? define(factory) :
16	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BpmnJS = factory());
17}(this, (function () { 'use strict';
18
19	var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
20
21	var inherits_browser = {exports: {}};
22
23	if (typeof Object.create === 'function') {
24	  // implementation from standard node.js 'util' module
25	  inherits_browser.exports = function inherits(ctor, superCtor) {
26	    if (superCtor) {
27	      ctor.super_ = superCtor;
28	      ctor.prototype = Object.create(superCtor.prototype, {
29	        constructor: {
30	          value: ctor,
31	          enumerable: false,
32	          writable: true,
33	          configurable: true
34	        }
35	      });
36	    }
37	  };
38	} else {
39	  // old school shim for old browsers
40	  inherits_browser.exports = function inherits(ctor, superCtor) {
41	    if (superCtor) {
42	      ctor.super_ = superCtor;
43	      var TempCtor = function () {};
44	      TempCtor.prototype = superCtor.prototype;
45	      ctor.prototype = new TempCtor();
46	      ctor.prototype.constructor = ctor;
47	    }
48	  };
49	}
50
51	var inherits$1 = inherits_browser.exports;
52
53	function createCommonjsModule(fn, module) {
54		return module = { exports: {} }, fn(module, module.exports), module.exports;
55	}
56
57	var hat_1 = createCommonjsModule(function (module) {
58	var hat = module.exports = function (bits, base) {
59	    if (!base) base = 16;
60	    if (bits === undefined) bits = 128;
61	    if (bits <= 0) return '0';
62
63	    var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
64	    for (var i = 2; digits === Infinity; i *= 2) {
65	        digits = Math.log(Math.pow(2, bits / i)) / Math.log(base) * i;
66	    }
67
68	    var rem = digits - Math.floor(digits);
69
70	    var res = '';
71
72	    for (var i = 0; i < Math.floor(digits); i++) {
73	        var x = Math.floor(Math.random() * base).toString(base);
74	        res = x + res;
75	    }
76
77	    if (rem) {
78	        var b = Math.pow(base, rem);
79	        var x = Math.floor(Math.random() * b).toString(base);
80	        res = x + res;
81	    }
82
83	    var parsed = parseInt(res, base);
84	    if (parsed !== Infinity && parsed >= Math.pow(2, bits)) {
85	        return hat(bits, base)
86	    }
87	    else return res;
88	};
89
90	hat.rack = function (bits, base, expandBy) {
91	    var fn = function (data) {
92	        var iters = 0;
93	        do {
94	            if (iters ++ > 10) {
95	                if (expandBy) bits += expandBy;
96	                else throw new Error('too many ID collisions, use more bits')
97	            }
98
99	            var id = hat(bits, base);
100	        } while (Object.hasOwnProperty.call(hats, id));
101
102	        hats[id] = data;
103	        return id;
104	    };
105	    var hats = fn.hats = {};
106
107	    fn.get = function (id) {
108	        return fn.hats[id];
109	    };
110
111	    fn.set = function (id, value) {
112	        fn.hats[id] = value;
113	        return fn;
114	    };
115
116	    fn.bits = bits || 128;
117	    fn.base = base || 16;
118	    return fn;
119	};
120	});
121
122	/**
123	 * Create a new id generator / cache instance.
124	 *
125	 * You may optionally provide a seed that is used internally.
126	 *
127	 * @param {Seed} seed
128	 */
129
130	function Ids(seed) {
131	  if (!(this instanceof Ids)) {
132	    return new Ids(seed);
133	  }
134
135	  seed = seed || [128, 36, 1];
136	  this._seed = seed.length ? hat_1.rack(seed[0], seed[1], seed[2]) : seed;
137	}
138	/**
139	 * Generate a next id.
140	 *
141	 * @param {Object} [element] element to bind the id to
142	 *
143	 * @return {String} id
144	 */
145
146	Ids.prototype.next = function (element) {
147	  return this._seed(element || true);
148	};
149	/**
150	 * Generate a next id with a given prefix.
151	 *
152	 * @param {Object} [element] element to bind the id to
153	 *
154	 * @return {String} id
155	 */
156
157
158	Ids.prototype.nextPrefixed = function (prefix, element) {
159	  var id;
160
161	  do {
162	    id = prefix + this.next(true);
163	  } while (this.assigned(id)); // claim {prefix}{random}
164
165
166	  this.claim(id, element); // return
167
168	  return id;
169	};
170	/**
171	 * Manually claim an existing id.
172	 *
173	 * @param {String} id
174	 * @param {String} [element] element the id is claimed by
175	 */
176
177
178	Ids.prototype.claim = function (id, element) {
179	  this._seed.set(id, element || true);
180	};
181	/**
182	 * Returns true if the given id has already been assigned.
183	 *
184	 * @param  {String} id
185	 * @return {Boolean}
186	 */
187
188
189	Ids.prototype.assigned = function (id) {
190	  return this._seed.get(id) || false;
191	};
192	/**
193	 * Unclaim an id.
194	 *
195	 * @param  {String} id the id to unclaim
196	 */
197
198
199	Ids.prototype.unclaim = function (id) {
200	  delete this._seed.hats[id];
201	};
202	/**
203	 * Clear all claimed ids.
204	 */
205
206
207	Ids.prototype.clear = function () {
208	  var hats = this._seed.hats,
209	      id;
210
211	  for (id in hats) {
212	    this.unclaim(id);
213	  }
214	};
215
216	/**
217	 * Flatten array, one level deep.
218	 *
219	 * @param {Array<?>} arr
220	 *
221	 * @return {Array<?>}
222	 */
223	function flatten(arr) {
224	  return Array.prototype.concat.apply([], arr);
225	}
226
227	var nativeToString = Object.prototype.toString;
228	var nativeHasOwnProperty = Object.prototype.hasOwnProperty;
229	function isUndefined$1(obj) {
230	  return obj === undefined;
231	}
232	function isDefined(obj) {
233	  return obj !== undefined;
234	}
235	function isNil(obj) {
236	  return obj == null;
237	}
238	function isArray$2(obj) {
239	  return nativeToString.call(obj) === '[object Array]';
240	}
241	function isObject(obj) {
242	  return nativeToString.call(obj) === '[object Object]';
243	}
244	function isNumber(obj) {
245	  return nativeToString.call(obj) === '[object Number]';
246	}
247	function isFunction(obj) {
248	  var tag = nativeToString.call(obj);
249	  return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
250	}
251	function isString(obj) {
252	  return nativeToString.call(obj) === '[object String]';
253	}
254	/**
255	 * Ensure collection is an array.
256	 *
257	 * @param {Object} obj
258	 */
259
260	function ensureArray(obj) {
261	  if (isArray$2(obj)) {
262	    return;
263	  }
264
265	  throw new Error('must supply array');
266	}
267	/**
268	 * Return true, if target owns a property with the given key.
269	 *
270	 * @param {Object} target
271	 * @param {String} key
272	 *
273	 * @return {Boolean}
274	 */
275
276	function has(target, key) {
277	  return nativeHasOwnProperty.call(target, key);
278	}
279
280	/**
281	 * Find element in collection.
282	 *
283	 * @param  {Array|Object} collection
284	 * @param  {Function|Object} matcher
285	 *
286	 * @return {Object}
287	 */
288
289	function find(collection, matcher) {
290	  matcher = toMatcher(matcher);
291	  var match;
292	  forEach(collection, function (val, key) {
293	    if (matcher(val, key)) {
294	      match = val;
295	      return false;
296	    }
297	  });
298	  return match;
299	}
300	/**
301	 * Find element index in collection.
302	 *
303	 * @param  {Array|Object} collection
304	 * @param  {Function} matcher
305	 *
306	 * @return {Object}
307	 */
308
309	function findIndex(collection, matcher) {
310	  matcher = toMatcher(matcher);
311	  var idx = isArray$2(collection) ? -1 : undefined;
312	  forEach(collection, function (val, key) {
313	    if (matcher(val, key)) {
314	      idx = key;
315	      return false;
316	    }
317	  });
318	  return idx;
319	}
320	/**
321	 * Find element in collection.
322	 *
323	 * @param  {Array|Object} collection
324	 * @param  {Function} matcher
325	 *
326	 * @return {Array} result
327	 */
328
329	function filter(collection, matcher) {
330	  var result = [];
331	  forEach(collection, function (val, key) {
332	    if (matcher(val, key)) {
333	      result.push(val);
334	    }
335	  });
336	  return result;
337	}
338	/**
339	 * Iterate over collection; returning something
340	 * (non-undefined) will stop iteration.
341	 *
342	 * @param  {Array|Object} collection
343	 * @param  {Function} iterator
344	 *
345	 * @return {Object} return result that stopped the iteration
346	 */
347
348	function forEach(collection, iterator) {
349	  var val, result;
350
351	  if (isUndefined$1(collection)) {
352	    return;
353	  }
354
355	  var convertKey = isArray$2(collection) ? toNum : identity;
356
357	  for (var key in collection) {
358	    if (has(collection, key)) {
359	      val = collection[key];
360	      result = iterator(val, convertKey(key));
361
362	      if (result === false) {
363	        return val;
364	      }
365	    }
366	  }
367	}
368	/**
369	 * Return collection without element.
370	 *
371	 * @param  {Array} arr
372	 * @param  {Function} matcher
373	 *
374	 * @return {Array}
375	 */
376
377	function without(arr, matcher) {
378	  if (isUndefined$1(arr)) {
379	    return [];
380	  }
381
382	  ensureArray(arr);
383	  matcher = toMatcher(matcher);
384	  return arr.filter(function (el, idx) {
385	    return !matcher(el, idx);
386	  });
387	}
388	/**
389	 * Reduce collection, returning a single result.
390	 *
391	 * @param  {Object|Array} collection
392	 * @param  {Function} iterator
393	 * @param  {Any} result
394	 *
395	 * @return {Any} result returned from last iterator
396	 */
397
398	function reduce(collection, iterator, result) {
399	  forEach(collection, function (value, idx) {
400	    result = iterator(result, value, idx);
401	  });
402	  return result;
403	}
404	/**
405	 * Return true if every element in the collection
406	 * matches the criteria.
407	 *
408	 * @param  {Object|Array} collection
409	 * @param  {Function} matcher
410	 *
411	 * @return {Boolean}
412	 */
413
414	function every(collection, matcher) {
415	  return !!reduce(collection, function (matches, val, key) {
416	    return matches && matcher(val, key);
417	  }, true);
418	}
419	/**
420	 * Return true if some elements in the collection
421	 * match the criteria.
422	 *
423	 * @param  {Object|Array} collection
424	 * @param  {Function} matcher
425	 *
426	 * @return {Boolean}
427	 */
428
429	function some(collection, matcher) {
430	  return !!find(collection, matcher);
431	}
432	/**
433	 * Transform a collection into another collection
434	 * by piping each member through the given fn.
435	 *
436	 * @param  {Object|Array}   collection
437	 * @param  {Function} fn
438	 *
439	 * @return {Array} transformed collection
440	 */
441
442	function map$1(collection, fn) {
443	  var result = [];
444	  forEach(collection, function (val, key) {
445	    result.push(fn(val, key));
446	  });
447	  return result;
448	}
449	/**
450	 * Get the collections keys.
451	 *
452	 * @param  {Object|Array} collection
453	 *
454	 * @return {Array}
455	 */
456
457	function keys(collection) {
458	  return collection && Object.keys(collection) || [];
459	}
460	/**
461	 * Shorthand for `keys(o).length`.
462	 *
463	 * @param  {Object|Array} collection
464	 *
465	 * @return {Number}
466	 */
467
468	function size(collection) {
469	  return keys(collection).length;
470	}
471	/**
472	 * Get the values in the collection.
473	 *
474	 * @param  {Object|Array} collection
475	 *
476	 * @return {Array}
477	 */
478
479	function values(collection) {
480	  return map$1(collection, function (val) {
481	    return val;
482	  });
483	}
484	/**
485	 * Group collection members by attribute.
486	 *
487	 * @param  {Object|Array} collection
488	 * @param  {Function} extractor
489	 *
490	 * @return {Object} map with { attrValue => [ a, b, c ] }
491	 */
492
493	function groupBy(collection, extractor) {
494	  var grouped = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
495	  extractor = toExtractor(extractor);
496	  forEach(collection, function (val) {
497	    var discriminator = extractor(val) || '_';
498	    var group = grouped[discriminator];
499
500	    if (!group) {
501	      group = grouped[discriminator] = [];
502	    }
503
504	    group.push(val);
505	  });
506	  return grouped;
507	}
508	function uniqueBy(extractor) {
509	  extractor = toExtractor(extractor);
510	  var grouped = {};
511
512	  for (var _len = arguments.length, collections = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
513	    collections[_key - 1] = arguments[_key];
514	  }
515
516	  forEach(collections, function (c) {
517	    return groupBy(c, extractor, grouped);
518	  });
519	  var result = map$1(grouped, function (val, key) {
520	    return val[0];
521	  });
522	  return result;
523	}
524	var unionBy = uniqueBy;
525	/**
526	 * Sort collection by criteria.
527	 *
528	 * @param  {Object|Array} collection
529	 * @param  {String|Function} extractor
530	 *
531	 * @return {Array}
532	 */
533
534	function sortBy(collection, extractor) {
535	  extractor = toExtractor(extractor);
536	  var sorted = [];
537	  forEach(collection, function (value, key) {
538	    var disc = extractor(value, key);
539	    var entry = {
540	      d: disc,
541	      v: value
542	    };
543
544	    for (var idx = 0; idx < sorted.length; idx++) {
545	      var d = sorted[idx].d;
546
547	      if (disc < d) {
548	        sorted.splice(idx, 0, entry);
549	        return;
550	      }
551	    } // not inserted, append (!)
552
553
554	    sorted.push(entry);
555	  });
556	  return map$1(sorted, function (e) {
557	    return e.v;
558	  });
559	}
560	/**
561	 * Create an object pattern matcher.
562	 *
563	 * @example
564	 *
565	 * const matcher = matchPattern({ id: 1 });
566	 *
567	 * var element = find(elements, matcher);
568	 *
569	 * @param  {Object} pattern
570	 *
571	 * @return {Function} matcherFn
572	 */
573
574	function matchPattern(pattern) {
575	  return function (el) {
576	    return every(pattern, function (val, key) {
577	      return el[key] === val;
578	    });
579	  };
580	}
581
582	function toExtractor(extractor) {
583	  return isFunction(extractor) ? extractor : function (e) {
584	    return e[extractor];
585	  };
586	}
587
588	function toMatcher(matcher) {
589	  return isFunction(matcher) ? matcher : function (e) {
590	    return e === matcher;
591	  };
592	}
593
594	function identity(arg) {
595	  return arg;
596	}
597
598	function toNum(arg) {
599	  return Number(arg);
600	}
601
602	/**
603	 * Debounce fn, calling it only once if
604	 * the given time elapsed between calls.
605	 *
606	 * @param  {Function} fn
607	 * @param  {Number} timeout
608	 *
609	 * @return {Function} debounced function
610	 */
611	function debounce(fn, timeout) {
612	  var timer;
613	  var lastArgs;
614	  var lastThis;
615	  var lastNow;
616
617	  function fire() {
618	    var now = Date.now();
619	    var scheduledDiff = lastNow + timeout - now;
620
621	    if (scheduledDiff > 0) {
622	      return schedule(scheduledDiff);
623	    }
624
625	    fn.apply(lastThis, lastArgs);
626	    timer = lastNow = lastArgs = lastThis = undefined;
627	  }
628
629	  function schedule(timeout) {
630	    timer = setTimeout(fire, timeout);
631	  }
632
633	  return function () {
634	    lastNow = Date.now();
635
636	    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
637	      args[_key] = arguments[_key];
638	    }
639
640	    lastArgs = args;
641	    lastThis = this; // ensure an execution is scheduled
642
643	    if (!timer) {
644	      schedule(timeout);
645	    }
646	  };
647	}
648	/**
649	 * Bind function against target <this>.
650	 *
651	 * @param  {Function} fn
652	 * @param  {Object}   target
653	 *
654	 * @return {Function} bound function
655	 */
656
657	function bind$2(fn, target) {
658	  return fn.bind(target);
659	}
660
661	function _extends() {
662	  _extends = Object.assign || function (target) {
663	    for (var i = 1; i < arguments.length; i++) {
664	      var source = arguments[i];
665
666	      for (var key in source) {
667	        if (Object.prototype.hasOwnProperty.call(source, key)) {
668	          target[key] = source[key];
669	        }
670	      }
671	    }
672
673	    return target;
674	  };
675
676	  return _extends.apply(this, arguments);
677	}
678
679	/**
680	 * Convenience wrapper for `Object.assign`.
681	 *
682	 * @param {Object} target
683	 * @param {...Object} others
684	 *
685	 * @return {Object} the target
686	 */
687
688	function assign(target) {
689	  for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
690	    others[_key - 1] = arguments[_key];
691	  }
692
693	  return _extends.apply(void 0, [target].concat(others));
694	}
695	/**
696	 * Pick given properties from the target object.
697	 *
698	 * @param {Object} target
699	 * @param {Array} properties
700	 *
701	 * @return {Object} target
702	 */
703
704	function pick(target, properties) {
705	  var result = {};
706	  var obj = Object(target);
707	  forEach(properties, function (prop) {
708	    if (prop in obj) {
709	      result[prop] = target[prop];
710	    }
711	  });
712	  return result;
713	}
714	/**
715	 * Pick all target properties, excluding the given ones.
716	 *
717	 * @param {Object} target
718	 * @param {Array} properties
719	 *
720	 * @return {Object} target
721	 */
722
723	function omit(target, properties) {
724	  var result = {};
725	  var obj = Object(target);
726	  forEach(obj, function (prop, key) {
727	    if (properties.indexOf(key) === -1) {
728	      result[key] = prop;
729	    }
730	  });
731	  return result;
732	}
733
734	/**
735	 * Set attribute `name` to `val`, or get attr `name`.
736	 *
737	 * @param {Element} el
738	 * @param {String} name
739	 * @param {String} [val]
740	 * @api public
741	 */
742	function attr$1(el, name, val) {
743	  // get
744	  if (arguments.length == 2) {
745	    return el.getAttribute(name);
746	  }
747
748	  // remove
749	  if (val === null) {
750	    return el.removeAttribute(name);
751	  }
752
753	  // set
754	  el.setAttribute(name, val);
755
756	  return el;
757	}
758
759	var indexOf$1 = [].indexOf;
760
761	var indexof = function(arr, obj){
762	  if (indexOf$1) return arr.indexOf(obj);
763	  for (var i = 0; i < arr.length; ++i) {
764	    if (arr[i] === obj) return i;
765	  }
766	  return -1;
767	};
768
769	/**
770	 * Taken from https://github.com/component/classes
771	 *
772	 * Without the component bits.
773	 */
774
775	/**
776	 * Whitespace regexp.
777	 */
778
779	var re$1 = /\s+/;
780
781	/**
782	 * toString reference.
783	 */
784
785	var toString$1 = Object.prototype.toString;
786
787	/**
788	 * Wrap `el` in a `ClassList`.
789	 *
790	 * @param {Element} el
791	 * @return {ClassList}
792	 * @api public
793	 */
794
795	function classes$1(el) {
796	  return new ClassList$1(el);
797	}
798
799	/**
800	 * Initialize a new ClassList for `el`.
801	 *
802	 * @param {Element} el
803	 * @api private
804	 */
805
806	function ClassList$1(el) {
807	  if (!el || !el.nodeType) {
808	    throw new Error('A DOM element reference is required');
809	  }
810	  this.el = el;
811	  this.list = el.classList;
812	}
813
814	/**
815	 * Add class `name` if not already present.
816	 *
817	 * @param {String} name
818	 * @return {ClassList}
819	 * @api public
820	 */
821
822	ClassList$1.prototype.add = function (name) {
823	  // classList
824	  if (this.list) {
825	    this.list.add(name);
826	    return this;
827	  }
828
829	  // fallback
830	  var arr = this.array();
831	  var i = indexof(arr, name);
832	  if (!~i) arr.push(name);
833	  this.el.className = arr.join(' ');
834	  return this;
835	};
836
837	/**
838	 * Remove class `name` when present, or
839	 * pass a regular expression to remove
840	 * any which match.
841	 *
842	 * @param {String|RegExp} name
843	 * @return {ClassList}
844	 * @api public
845	 */
846
847	ClassList$1.prototype.remove = function (name) {
848	  if ('[object RegExp]' == toString$1.call(name)) {
849	    return this.removeMatching(name);
850	  }
851
852	  // classList
853	  if (this.list) {
854	    this.list.remove(name);
855	    return this;
856	  }
857
858	  // fallback
859	  var arr = this.array();
860	  var i = indexof(arr, name);
861	  if (~i) arr.splice(i, 1);
862	  this.el.className = arr.join(' ');
863	  return this;
864	};
865
866	/**
867	 * Remove all classes matching `re`.
868	 *
869	 * @param {RegExp} re
870	 * @return {ClassList}
871	 * @api private
872	 */
873
874	ClassList$1.prototype.removeMatching = function (re) {
875	  var arr = this.array();
876	  for (var i = 0; i < arr.length; i++) {
877	    if (re.test(arr[i])) {
878	      this.remove(arr[i]);
879	    }
880	  }
881	  return this;
882	};
883
884	/**
885	 * Toggle class `name`, can force state via `force`.
886	 *
887	 * For browsers that support classList, but do not support `force` yet,
888	 * the mistake will be detected and corrected.
889	 *
890	 * @param {String} name
891	 * @param {Boolean} force
892	 * @return {ClassList}
893	 * @api public
894	 */
895
896	ClassList$1.prototype.toggle = function (name, force) {
897	  // classList
898	  if (this.list) {
899	    if ('undefined' !== typeof force) {
900	      if (force !== this.list.toggle(name, force)) {
901	        this.list.toggle(name); // toggle again to correct
902	      }
903	    } else {
904	      this.list.toggle(name);
905	    }
906	    return this;
907	  }
908
909	  // fallback
910	  if ('undefined' !== typeof force) {
911	    if (!force) {
912	      this.remove(name);
913	    } else {
914	      this.add(name);
915	    }
916	  } else {
917	    if (this.has(name)) {
918	      this.remove(name);
919	    } else {
920	      this.add(name);
921	    }
922	  }
923
924	  return this;
925	};
926
927	/**
928	 * Return an array of classes.
929	 *
930	 * @return {Array}
931	 * @api public
932	 */
933
934	ClassList$1.prototype.array = function () {
935	  var className = this.el.getAttribute('class') || '';
936	  var str = className.replace(/^\s+|\s+$/g, '');
937	  var arr = str.split(re$1);
938	  if ('' === arr[0]) arr.shift();
939	  return arr;
940	};
941
942	/**
943	 * Check if class `name` is present.
944	 *
945	 * @param {String} name
946	 * @return {ClassList}
947	 * @api public
948	 */
949
950	ClassList$1.prototype.has = ClassList$1.prototype.contains = function (name) {
951	  return this.list ? this.list.contains(name) : !!~indexof(this.array(), name);
952	};
953
954	/**
955	 * Remove all children from the given element.
956	 */
957	function clear$1(el) {
958
959	  var c;
960
961	  while (el.childNodes.length) {
962	    c = el.childNodes[0];
963	    el.removeChild(c);
964	  }
965
966	  return el;
967	}
968
969	var proto = typeof Element !== 'undefined' ? Element.prototype : {};
970	var vendor = proto.matches
971	  || proto.matchesSelector
972	  || proto.webkitMatchesSelector
973	  || proto.mozMatchesSelector
974	  || proto.msMatchesSelector
975	  || proto.oMatchesSelector;
976
977	var matchesSelector = match;
978
979	/**
980	 * Match `el` to `selector`.
981	 *
982	 * @param {Element} el
983	 * @param {String} selector
984	 * @return {Boolean}
985	 * @api public
986	 */
987
988	function match(el, selector) {
989	  if (!el || el.nodeType !== 1) return false;
990	  if (vendor) return vendor.call(el, selector);
991	  var nodes = el.parentNode.querySelectorAll(selector);
992	  for (var i = 0; i < nodes.length; i++) {
993	    if (nodes[i] == el) return true;
994	  }
995	  return false;
996	}
997
998	/**
999	 * Closest
1000	 *
1001	 * @param {Element} el
1002	 * @param {String} selector
1003	 * @param {Boolean} checkYourSelf (optional)
1004	 */
1005	function closest (element, selector, checkYourSelf) {
1006	  var currentElem = checkYourSelf ? element : element.parentNode;
1007
1008	  while (currentElem && currentElem.nodeType !== document.DOCUMENT_NODE && currentElem.nodeType !== document.DOCUMENT_FRAGMENT_NODE) {
1009
1010	    if (matchesSelector(currentElem, selector)) {
1011	      return currentElem;
1012	    }
1013
1014	    currentElem = currentElem.parentNode;
1015	  }
1016
1017	  return matchesSelector(currentElem, selector) ? currentElem : null;
1018	}
1019
1020	var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
1021	    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
1022	    prefix$6 = bind !== 'addEventListener' ? 'on' : '';
1023
1024	/**
1025	 * Bind `el` event `type` to `fn`.
1026	 *
1027	 * @param {Element} el
1028	 * @param {String} type
1029	 * @param {Function} fn
1030	 * @param {Boolean} capture
1031	 * @return {Function}
1032	 * @api public
1033	 */
1034
1035	var bind_1 = function(el, type, fn, capture){
1036	  el[bind](prefix$6 + type, fn, capture || false);
1037	  return fn;
1038	};
1039
1040	/**
1041	 * Unbind `el` event `type`'s callback `fn`.
1042	 *
1043	 * @param {Element} el
1044	 * @param {String} type
1045	 * @param {Function} fn
1046	 * @param {Boolean} capture
1047	 * @return {Function}
1048	 * @api public
1049	 */
1050
1051	var unbind_1 = function(el, type, fn, capture){
1052	  el[unbind](prefix$6 + type, fn, capture || false);
1053	  return fn;
1054	};
1055
1056	var componentEvent = {
1057		bind: bind_1,
1058		unbind: unbind_1
1059	};
1060
1061	/**
1062	 * Module dependencies.
1063	 */
1064
1065	/**
1066	 * Delegate event `type` to `selector`
1067	 * and invoke `fn(e)`. A callback function
1068	 * is returned which may be passed to `.unbind()`.
1069	 *
1070	 * @param {Element} el
1071	 * @param {String} selector
1072	 * @param {String} type
1073	 * @param {Function} fn
1074	 * @param {Boolean} capture
1075	 * @return {Function}
1076	 * @api public
1077	 */
1078
1079	// Some events don't bubble, so we want to bind to the capture phase instead
1080	// when delegating.
1081	var forceCaptureEvents = ['focus', 'blur'];
1082
1083	function bind$1(el, selector, type, fn, capture) {
1084	  if (forceCaptureEvents.indexOf(type) !== -1) {
1085	    capture = true;
1086	  }
1087
1088	  return componentEvent.bind(el, type, function (e) {
1089	    var target = e.target || e.srcElement;
1090	    e.delegateTarget = closest(target, selector, true);
1091	    if (e.delegateTarget) {
1092	      fn.call(el, e);
1093	    }
1094	  }, capture);
1095	}
1096
1097	/**
1098	 * Unbind event `type`'s callback `fn`.
1099	 *
1100	 * @param {Element} el
1101	 * @param {String} type
1102	 * @param {Function} fn
1103	 * @param {Boolean} capture
1104	 * @api public
1105	 */
1106	function unbind$1(el, type, fn, capture) {
1107	  if (forceCaptureEvents.indexOf(type) !== -1) {
1108	    capture = true;
1109	  }
1110
1111	  return componentEvent.unbind(el, type, fn, capture);
1112	}
1113
1114	var delegate = {
1115	  bind: bind$1,
1116	  unbind: unbind$1
1117	};
1118
1119	/**
1120	 * Expose `parse`.
1121	 */
1122
1123	var domify = parse$1;
1124
1125	/**
1126	 * Tests for browser support.
1127	 */
1128
1129	var innerHTMLBug = false;
1130	var bugTestDiv;
1131	if (typeof document !== 'undefined') {
1132	  bugTestDiv = document.createElement('div');
1133	  // Setup
1134	  bugTestDiv.innerHTML = '  <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
1135	  // Make sure that link elements get serialized correctly by innerHTML
1136	  // This requires a wrapper element in IE
1137	  innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
1138	  bugTestDiv = undefined;
1139	}
1140
1141	/**
1142	 * Wrap map from jquery.
1143	 */
1144
1145	var map = {
1146	  legend: [1, '<fieldset>', '</fieldset>'],
1147	  tr: [2, '<table><tbody>', '</tbody></table>'],
1148	  col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
1149	  // for script/link/style tags to work in IE6-8, you have to wrap
1150	  // in a div with a non-whitespace character in front, ha!
1151	  _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
1152	};
1153
1154	map.td =
1155	map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
1156
1157	map.option =
1158	map.optgroup = [1, '<select multiple="multiple">', '</select>'];
1159
1160	map.thead =
1161	map.tbody =
1162	map.colgroup =
1163	map.caption =
1164	map.tfoot = [1, '<table>', '</table>'];
1165
1166	map.polyline =
1167	map.ellipse =
1168	map.polygon =
1169	map.circle =
1170	map.text =
1171	map.line =
1172	map.path =
1173	map.rect =
1174	map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
1175
1176	/**
1177	 * Parse `html` and return a DOM Node instance, which could be a TextNode,
1178	 * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
1179	 * instance, depending on the contents of the `html` string.
1180	 *
1181	 * @param {String} html - HTML string to "domify"
1182	 * @param {Document} doc - The `document` instance to create the Node for
1183	 * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
1184	 * @api private
1185	 */
1186
1187	function parse$1(html, doc) {
1188	  if ('string' != typeof html) throw new TypeError('String expected');
1189
1190	  // default to the global `document` object
1191	  if (!doc) doc = document;
1192
1193	  // tag name
1194	  var m = /<([\w:]+)/.exec(html);
1195	  if (!m) return doc.createTextNode(html);
1196
1197	  html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
1198
1199	  var tag = m[1];
1200
1201	  // body support
1202	  if (tag == 'body') {
1203	    var el = doc.createElement('html');
1204	    el.innerHTML = html;
1205	    return el.removeChild(el.lastChild);
1206	  }
1207
1208	  // wrap map
1209	  var wrap = map[tag] || map._default;
1210	  var depth = wrap[0];
1211	  var prefix = wrap[1];
1212	  var suffix = wrap[2];
1213	  var el = doc.createElement('div');
1214	  el.innerHTML = prefix + html + suffix;
1215	  while (depth--) el = el.lastChild;
1216
1217	  // one element
1218	  if (el.firstChild == el.lastChild) {
1219	    return el.removeChild(el.firstChild);
1220	  }
1221
1222	  // several elements
1223	  var fragment = doc.createDocumentFragment();
1224	  while (el.firstChild) {
1225	    fragment.appendChild(el.removeChild(el.firstChild));
1226	  }
1227
1228	  return fragment;
1229	}
1230
1231	function query(selector, el) {
1232	  el = el || document;
1233
1234	  return el.querySelector(selector);
1235	}
1236
1237	function all(selector, el) {
1238	  el = el || document;
1239
1240	  return el.querySelectorAll(selector);
1241	}
1242
1243	function remove$2(el) {
1244	  el.parentNode && el.parentNode.removeChild(el);
1245	}
1246
1247	function ensureImported(element, target) {
1248
1249	  if (element.ownerDocument !== target.ownerDocument) {
1250	    try {
1251	      // may fail on webkit
1252	      return target.ownerDocument.importNode(element, true);
1253	    } catch (e) {
1254	      // ignore
1255	    }
1256	  }
1257
1258	  return element;
1259	}
1260
1261	/**
1262	 * appendTo utility
1263	 */
1264
1265	/**
1266	 * Append a node to a target element and return the appended node.
1267	 *
1268	 * @param  {SVGElement} element
1269	 * @param  {SVGElement} target
1270	 *
1271	 * @return {SVGElement} the appended node
1272	 */
1273	function appendTo(element, target) {
1274	  return target.appendChild(ensureImported(element, target));
1275	}
1276
1277	/**
1278	 * append utility
1279	 */
1280
1281	/**
1282	 * Append a node to an element
1283	 *
1284	 * @param  {SVGElement} element
1285	 * @param  {SVGElement} node
1286	 *
1287	 * @return {SVGElement} the element
1288	 */
1289	function append(target, node) {
1290	  appendTo(node, target);
1291	  return target;
1292	}
1293
1294	/**
1295	 * attribute accessor utility
1296	 */
1297
1298	var LENGTH_ATTR = 2;
1299
1300	var CSS_PROPERTIES = {
1301	  'alignment-baseline': 1,
1302	  'baseline-shift': 1,
1303	  'clip': 1,
1304	  'clip-path': 1,
1305	  'clip-rule': 1,
1306	  'color': 1,
1307	  'color-interpolation': 1,
1308	  'color-interpolation-filters': 1,
1309	  'color-profile': 1,
1310	  'color-rendering': 1,
1311	  'cursor': 1,
1312	  'direction': 1,
1313	  'display': 1,
1314	  'dominant-baseline': 1,
1315	  'enable-background': 1,
1316	  'fill': 1,
1317	  'fill-opacity': 1,
1318	  'fill-rule': 1,
1319	  'filter': 1,
1320	  'flood-color': 1,
1321	  'flood-opacity': 1,
1322	  'font': 1,
1323	  'font-family': 1,
1324	  'font-size': LENGTH_ATTR,
1325	  'font-size-adjust': 1,
1326	  'font-stretch': 1,
1327	  'font-style': 1,
1328	  'font-variant': 1,
1329	  'font-weight': 1,
1330	  'glyph-orientation-horizontal': 1,
1331	  'glyph-orientation-vertical': 1,
1332	  'image-rendering': 1,
1333	  'kerning': 1,
1334	  'letter-spacing': 1,
1335	  'lighting-color': 1,
1336	  'marker': 1,
1337	  'marker-end': 1,
1338	  'marker-mid': 1,
1339	  'marker-start': 1,
1340	  'mask': 1,
1341	  'opacity': 1,
1342	  'overflow': 1,
1343	  'pointer-events': 1,
1344	  'shape-rendering': 1,
1345	  'stop-color': 1,
1346	  'stop-opacity': 1,
1347	  'stroke': 1,
1348	  'stroke-dasharray': 1,
1349	  'stroke-dashoffset': 1,
1350	  'stroke-linecap': 1,
1351	  'stroke-linejoin': 1,
1352	  'stroke-miterlimit': 1,
1353	  'stroke-opacity': 1,
1354	  'stroke-width': LENGTH_ATTR,
1355	  'text-anchor': 1,
1356	  'text-decoration': 1,
1357	  'text-rendering': 1,
1358	  'unicode-bidi': 1,
1359	  'visibility': 1,
1360	  'word-spacing': 1,
1361	  'writing-mode': 1
1362	};
1363
1364
1365	function getAttribute(node, name) {
1366	  if (CSS_PROPERTIES[name]) {
1367	    return node.style[name];
1368	  } else {
1369	    return node.getAttributeNS(null, name);
1370	  }
1371	}
1372
1373	function setAttribute(node, name, value) {
1374	  var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1375
1376	  var type = CSS_PROPERTIES[hyphenated];
1377
1378	  if (type) {
1379	    // append pixel unit, unless present
1380	    if (type === LENGTH_ATTR && typeof value === 'number') {
1381	      value = String(value) + 'px';
1382	    }
1383
1384	    node.style[hyphenated] = value;
1385	  } else {
1386	    node.setAttributeNS(null, name, value);
1387	  }
1388	}
1389
1390	function setAttributes(node, attrs) {
1391
1392	  var names = Object.keys(attrs), i, name;
1393
1394	  for (i = 0, name; (name = names[i]); i++) {
1395	    setAttribute(node, name, attrs[name]);
1396	  }
1397	}
1398
1399	/**
1400	 * Gets or sets raw attributes on a node.
1401	 *
1402	 * @param  {SVGElement} node
1403	 * @param  {Object} [attrs]
1404	 * @param  {String} [name]
1405	 * @param  {String} [value]
1406	 *
1407	 * @return {String}
1408	 */
1409	function attr(node, name, value) {
1410	  if (typeof name === 'string') {
1411	    if (value !== undefined) {
1412	      setAttribute(node, name, value);
1413	    } else {
1414	      return getAttribute(node, name);
1415	    }
1416	  } else {
1417	    setAttributes(node, name);
1418	  }
1419
1420	  return node;
1421	}
1422
1423	/**
1424	 * Clear utility
1425	 */
1426	function index(arr, obj) {
1427	  if (arr.indexOf) {
1428	    return arr.indexOf(obj);
1429	  }
1430
1431
1432	  for (var i = 0; i < arr.length; ++i) {
1433	    if (arr[i] === obj) {
1434	      return i;
1435	    }
1436	  }
1437
1438	  return -1;
1439	}
1440
1441	var re = /\s+/;
1442
1443	var toString = Object.prototype.toString;
1444
1445	function defined(o) {
1446	  return typeof o !== 'undefined';
1447	}
1448
1449	/**
1450	 * Wrap `el` in a `ClassList`.
1451	 *
1452	 * @param {Element} el
1453	 * @return {ClassList}
1454	 * @api public
1455	 */
1456
1457	function classes(el) {
1458	  return new ClassList(el);
1459	}
1460
1461	function ClassList(el) {
1462	  if (!el || !el.nodeType) {
1463	    throw new Error('A DOM element reference is required');
1464	  }
1465	  this.el = el;
1466	  this.list = el.classList;
1467	}
1468
1469	/**
1470	 * Add class `name` if not already present.
1471	 *
1472	 * @param {String} name
1473	 * @return {ClassList}
1474	 * @api public
1475	 */
1476
1477	ClassList.prototype.add = function(name) {
1478
1479	  // classList
1480	  if (this.list) {
1481	    this.list.add(name);
1482	    return this;
1483	  }
1484
1485	  // fallback
1486	  var arr = this.array();
1487	  var i = index(arr, name);
1488	  if (!~i) {
1489	    arr.push(name);
1490	  }
1491
1492	  if (defined(this.el.className.baseVal)) {
1493	    this.el.className.baseVal = arr.join(' ');
1494	  } else {
1495	    this.el.className = arr.join(' ');
1496	  }
1497
1498	  return this;
1499	};
1500
1501	/**
1502	 * Remove class `name` when present, or
1503	 * pass a regular expression to remove
1504	 * any which match.
1505	 *
1506	 * @param {String|RegExp} name
1507	 * @return {ClassList}
1508	 * @api public
1509	 */
1510
1511	ClassList.prototype.remove = function(name) {
1512	  if ('[object RegExp]' === toString.call(name)) {
1513	    return this.removeMatching(name);
1514	  }
1515
1516	  // classList
1517	  if (this.list) {
1518	    this.list.remove(name);
1519	    return this;
1520	  }
1521
1522	  // fallback
1523	  var arr = this.array();
1524	  var i = index(arr, name);
1525	  if (~i) {
1526	    arr.splice(i, 1);
1527	  }
1528	  this.el.className.baseVal = arr.join(' ');
1529	  return this;
1530	};
1531
1532	/**
1533	 * Remove all classes matching `re`.
1534	 *
1535	 * @param {RegExp} re
1536	 * @return {ClassList}
1537	 * @api private
1538	 */
1539
1540	ClassList.prototype.removeMatching = function(re) {
1541	  var arr = this.array();
1542	  for (var i = 0; i < arr.length; i++) {
1543	    if (re.test(arr[i])) {
1544	      this.remove(arr[i]);
1545	    }
1546	  }
1547	  return this;
1548	};
1549
1550	/**
1551	 * Toggle class `name`, can force state via `force`.
1552	 *
1553	 * For browsers that support classList, but do not support `force` yet,
1554	 * the mistake will be detected and corrected.
1555	 *
1556	 * @param {String} name
1557	 * @param {Boolean} force
1558	 * @return {ClassList}
1559	 * @api public
1560	 */
1561
1562	ClassList.prototype.toggle = function(name, force) {
1563	  // classList
1564	  if (this.list) {
1565	    if (defined(force)) {
1566	      if (force !== this.list.toggle(name, force)) {
1567	        this.list.toggle(name); // toggle again to correct
1568	      }
1569	    } else {
1570	      this.list.toggle(name);
1571	    }
1572	    return this;
1573	  }
1574
1575	  // fallback
1576	  if (defined(force)) {
1577	    if (!force) {
1578	      this.remove(name);
1579	    } else {
1580	      this.add(name);
1581	    }
1582	  } else {
1583	    if (this.has(name)) {
1584	      this.remove(name);
1585	    } else {
1586	      this.add(name);
1587	    }
1588	  }
1589
1590	  return this;
1591	};
1592
1593	/**
1594	 * Return an array of classes.
1595	 *
1596	 * @return {Array}
1597	 * @api public
1598	 */
1599
1600	ClassList.prototype.array = function() {
1601	  var className = this.el.getAttribute('class') || '';
1602	  var str = className.replace(/^\s+|\s+$/g, '');
1603	  var arr = str.split(re);
1604	  if ('' === arr[0]) {
1605	    arr.shift();
1606	  }
1607	  return arr;
1608	};
1609
1610	/**
1611	 * Check if class `name` is present.
1612	 *
1613	 * @param {String} name
1614	 * @return {ClassList}
1615	 * @api public
1616	 */
1617
1618	ClassList.prototype.has =
1619	ClassList.prototype.contains = function(name) {
1620	  return (
1621	    this.list ?
1622	      this.list.contains(name) :
1623	      !! ~index(this.array(), name)
1624	  );
1625	};
1626
1627	function remove$1(element) {
1628	  var parent = element.parentNode;
1629
1630	  if (parent) {
1631	    parent.removeChild(element);
1632	  }
1633
1634	  return element;
1635	}
1636
1637	/**
1638	 * Clear utility
1639	 */
1640
1641	/**
1642	 * Removes all children from the given element
1643	 *
1644	 * @param  {DOMElement} element
1645	 * @return {DOMElement} the element (for chaining)
1646	 */
1647	function clear(element) {
1648	  var child;
1649
1650	  while ((child = element.firstChild)) {
1651	    remove$1(child);
1652	  }
1653
1654	  return element;
1655	}
1656
1657	function clone$1(element) {
1658	  return element.cloneNode(true);
1659	}
1660
1661	var ns = {
1662	  svg: 'http://www.w3.org/2000/svg'
1663	};
1664
1665	/**
1666	 * DOM parsing utility
1667	 */
1668
1669	var SVG_START = '<svg xmlns="' + ns.svg + '"';
1670
1671	function parse(svg) {
1672
1673	  var unwrap = false;
1674
1675	  // ensure we import a valid svg document
1676	  if (svg.substring(0, 4) === '<svg') {
1677	    if (svg.indexOf(ns.svg) === -1) {
1678	      svg = SVG_START + svg.substring(4);
1679	    }
1680	  } else {
1681	    // namespace svg
1682	    svg = SVG_START + '>' + svg + '</svg>';
1683	    unwrap = true;
1684	  }
1685
1686	  var parsed = parseDocument(svg);
1687
1688	  if (!unwrap) {
1689	    return parsed;
1690	  }
1691
1692	  var fragment = document.createDocumentFragment();
1693
1694	  var parent = parsed.firstChild;
1695
1696	  while (parent.firstChild) {
1697	    fragment.appendChild(parent.firstChild);
1698	  }
1699
1700	  return fragment;
1701	}
1702
1703	function parseDocument(svg) {
1704
1705	  var parser;
1706
1707	  // parse
1708	  parser = new DOMParser();
1709	  parser.async = false;
1710
1711	  return parser.parseFromString(svg, 'text/xml');
1712	}
1713
1714	/**
1715	 * Create utility for SVG elements
1716	 */
1717
1718
1719	/**
1720	 * Create a specific type from name or SVG markup.
1721	 *
1722	 * @param {String} name the name or markup of the element
1723	 * @param {Object} [attrs] attributes to set on the element
1724	 *
1725	 * @returns {SVGElement}
1726	 */
1727	function create$1(name, attrs) {
1728	  var element;
1729
1730	  if (name.charAt(0) === '<') {
1731	    element = parse(name).firstChild;
1732	    element = document.importNode(element, true);
1733	  } else {
1734	    element = document.createElementNS(ns.svg, name);
1735	  }
1736
1737	  if (attrs) {
1738	    attr(element, attrs);
1739	  }
1740
1741	  return element;
1742	}
1743
1744	/**
1745	 * Geometry helpers
1746	 */
1747
1748	// fake node used to instantiate svg geometry elements
1749	var node = create$1('svg');
1750
1751	function extend$1(object, props) {
1752	  var i, k, keys = Object.keys(props);
1753
1754	  for (i = 0; (k = keys[i]); i++) {
1755	    object[k] = props[k];
1756	  }
1757
1758	  return object;
1759	}
1760
1761	/**
1762	 * Create matrix via args.
1763	 *
1764	 * @example
1765	 *
1766	 * createMatrix({ a: 1, b: 1 });
1767	 * createMatrix();
1768	 * createMatrix(1, 2, 0, 0, 30, 20);
1769	 *
1770	 * @return {SVGMatrix}
1771	 */
1772	function createMatrix(a, b, c, d, e, f) {
1773	  var matrix = node.createSVGMatrix();
1774
1775	  switch (arguments.length) {
1776	  case 0:
1777	    return matrix;
1778	  case 1:
1779	    return extend$1(matrix, a);
1780	  case 6:
1781	    return extend$1(matrix, {
1782	      a: a,
1783	      b: b,
1784	      c: c,
1785	      d: d,
1786	      e: e,
1787	      f: f
1788	    });
1789	  }
1790	}
1791
1792	function createTransform(matrix) {
1793	  if (matrix) {
1794	    return node.createSVGTransformFromMatrix(matrix);
1795	  } else {
1796	    return node.createSVGTransform();
1797	  }
1798	}
1799
1800	/**
1801	 * Serialization util
1802	 */
1803
1804	var TEXT_ENTITIES = /([&<>]{1})/g;
1805	var ATTR_ENTITIES = /([\n\r"]{1})/g;
1806
1807	var ENTITY_REPLACEMENT = {
1808	  '&': '&amp;',
1809	  '<': '&lt;',
1810	  '>': '&gt;',
1811	  '"': '\''
1812	};
1813
1814	function escape$1(str, pattern) {
1815
1816	  function replaceFn(match, entity) {
1817	    return ENTITY_REPLACEMENT[entity] || entity;
1818	  }
1819
1820	  return str.replace(pattern, replaceFn);
1821	}
1822
1823	function serialize(node, output) {
1824
1825	  var i, len, attrMap, attrNode, childNodes;
1826
1827	  switch (node.nodeType) {
1828	  // TEXT
1829	  case 3:
1830	    // replace special XML characters
1831	    output.push(escape$1(node.textContent, TEXT_ENTITIES));
1832	    break;
1833
1834	  // ELEMENT
1835	  case 1:
1836	    output.push('<', node.tagName);
1837
1838	    if (node.hasAttributes()) {
1839	      attrMap = node.attributes;
1840	      for (i = 0, len = attrMap.length; i < len; ++i) {
1841	        attrNode = attrMap.item(i);
1842	        output.push(' ', attrNode.name, '="', escape$1(attrNode.value, ATTR_ENTITIES), '"');
1843	      }
1844	    }
1845
1846	    if (node.hasChildNodes()) {
1847	      output.push('>');
1848	      childNodes = node.childNodes;
1849	      for (i = 0, len = childNodes.length; i < len; ++i) {
1850	        serialize(childNodes.item(i), output);
1851	      }
1852	      output.push('</', node.tagName, '>');
1853	    } else {
1854	      output.push('/>');
1855	    }
1856	    break;
1857
1858	  // COMMENT
1859	  case 8:
1860	    output.push('<!--', escape$1(node.nodeValue, TEXT_ENTITIES), '-->');
1861	    break;
1862
1863	  // CDATA
1864	  case 4:
1865	    output.push('<![CDATA[', node.nodeValue, ']]>');
1866	    break;
1867
1868	  default:
1869	    throw new Error('unable to handle node ' + node.nodeType);
1870	  }
1871
1872	  return output;
1873	}
1874
1875	/**
1876	 * innerHTML like functionality for SVG elements.
1877	 * based on innerSVG (https://code.google.com/p/innersvg)
1878	 */
1879
1880
1881	function set$1(element, svg) {
1882
1883	  var parsed = parse(svg);
1884
1885	  // clear element contents
1886	  clear(element);
1887
1888	  if (!svg) {
1889	    return;
1890	  }
1891
1892	  if (!isFragment(parsed)) {
1893	    // extract <svg> from parsed document
1894	    parsed = parsed.documentElement;
1895	  }
1896
1897	  var nodes = slice$1(parsed.childNodes);
1898
1899	  // import + append each node
1900	  for (var i = 0; i < nodes.length; i++) {
1901	    appendTo(nodes[i], element);
1902	  }
1903
1904	}
1905
1906	function get$1(element) {
1907	  var child = element.firstChild,
1908	      output = [];
1909
1910	  while (child) {
1911	    serialize(child, output);
1912	    child = child.nextSibling;
1913	  }
1914
1915	  return output.join('');
1916	}
1917
1918	function isFragment(node) {
1919	  return node.nodeName === '#document-fragment';
1920	}
1921
1922	function innerSVG(element, svg) {
1923
1924	  if (svg !== undefined) {
1925
1926	    try {
1927	      set$1(element, svg);
1928	    } catch (e) {
1929	      throw new Error('error parsing SVG: ' + e.message);
1930	    }
1931
1932	    return element;
1933	  } else {
1934	    return get$1(element);
1935	  }
1936	}
1937
1938
1939	function slice$1(arr) {
1940	  return Array.prototype.slice.call(arr);
1941	}
1942
1943	/**
1944	 * transform accessor utility
1945	 */
1946
1947	function wrapMatrix(transformList, transform) {
1948	  if (transform instanceof SVGMatrix) {
1949	    return transformList.createSVGTransformFromMatrix(transform);
1950	  }
1951
1952	  return transform;
1953	}
1954
1955
1956	function setTransforms(transformList, transforms) {
1957	  var i, t;
1958
1959	  transformList.clear();
1960
1961	  for (i = 0; (t = transforms[i]); i++) {
1962	    transformList.appendItem(wrapMatrix(transformList, t));
1963	  }
1964	}
1965
1966	/**
1967	 * Get or set the transforms on the given node.
1968	 *
1969	 * @param {SVGElement} node
1970	 * @param  {SVGTransform|SVGMatrix|Array<SVGTransform|SVGMatrix>} [transforms]
1971	 *
1972	 * @return {SVGTransform} the consolidated transform
1973	 */
1974	function transform$1(node, transforms) {
1975	  var transformList = node.transform.baseVal;
1976
1977	  if (transforms) {
1978
1979	    if (!Array.isArray(transforms)) {
1980	      transforms = [ transforms ];
1981	    }
1982
1983	    setTransforms(transformList, transforms);
1984	  }
1985
1986	  return transformList.consolidate();
1987	}
1988
1989	var CLASS_PATTERN = /^class /;
1990
1991	function isClass(fn) {
1992	  return CLASS_PATTERN.test(fn.toString());
1993	}
1994
1995	function isArray$1(obj) {
1996	  return Object.prototype.toString.call(obj) === '[object Array]';
1997	}
1998
1999	function hasOwnProp(obj, prop) {
2000	  return Object.prototype.hasOwnProperty.call(obj, prop);
2001	}
2002
2003	function annotate() {
2004	  var args = Array.prototype.slice.call(arguments);
2005
2006	  if (args.length === 1 && isArray$1(args[0])) {
2007	    args = args[0];
2008	  }
2009
2010	  var fn = args.pop();
2011
2012	  fn.$inject = args;
2013
2014	  return fn;
2015	}
2016
2017
2018	// Current limitations:
2019	// - can't put into "function arg" comments
2020	// function /* (no parenthesis like this) */ (){}
2021	// function abc( /* xx (no parenthesis like this) */ a, b) {}
2022	//
2023	// Just put the comment before function or inside:
2024	// /* (((this is fine))) */ function(a, b) {}
2025	// function abc(a) { /* (((this is fine))) */}
2026	//
2027	// - can't reliably auto-annotate constructor; we'll match the
2028	// first constructor(...) pattern found which may be the one
2029	// of a nested class, too.
2030
2031	var CONSTRUCTOR_ARGS = /constructor\s*[^(]*\(\s*([^)]*)\)/m;
2032	var FN_ARGS = /^(?:async )?(?:function\s*)?[^(]*\(\s*([^)]*)\)/m;
2033	var FN_ARG = /\/\*([^*]*)\*\//m;
2034
2035	function parseAnnotations(fn) {
2036
2037	  if (typeof fn !== 'function') {
2038	    throw new Error('Cannot annotate "' + fn + '". Expected a function!');
2039	  }
2040
2041	  var match = fn.toString().match(isClass(fn) ? CONSTRUCTOR_ARGS : FN_ARGS);
2042
2043	  // may parse class without constructor
2044	  if (!match) {
2045	    return [];
2046	  }
2047
2048	  return match[1] && match[1].split(',').map(function(arg) {
2049	    match = arg.match(FN_ARG);
2050	    return match ? match[1].trim() : arg.trim();
2051	  }) || [];
2052	}
2053
2054	function Module() {
2055	  var providers = [];
2056
2057	  this.factory = function(name, factory) {
2058	    providers.push([name, 'factory', factory]);
2059	    return this;
2060	  };
2061
2062	  this.value = function(name, value) {
2063	    providers.push([name, 'value', value]);
2064	    return this;
2065	  };
2066
2067	  this.type = function(name, type) {
2068	    providers.push([name, 'type', type]);
2069	    return this;
2070	  };
2071
2072	  this.forEach = function(iterator) {
2073	    providers.forEach(iterator);
2074	  };
2075
2076	}
2077
2078	function Injector(modules, parent) {
2079	  parent = parent || {
2080	    get: function(name, strict) {
2081	      currentlyResolving.push(name);
2082
2083	      if (strict === false) {
2084	        return null;
2085	      } else {
2086	        throw error('No provider for "' + name + '"!');
2087	      }
2088	    }
2089	  };
2090
2091	  var currentlyResolving = [];
2092	  var providers = this._providers = Object.create(parent._providers || null);
2093	  var instances = this._instances = Object.create(null);
2094
2095	  var self = instances.injector = this;
2096
2097	  var error = function(msg) {
2098	    var stack = currentlyResolving.join(' -> ');
2099	    currentlyResolving.length = 0;
2100	    return new Error(stack ? msg + ' (Resolving: ' + stack + ')' : msg);
2101	  };
2102
2103	  /**
2104	   * Return a named service.
2105	   *
2106	   * @param {String} name
2107	   * @param {Boolean} [strict=true] if false, resolve missing services to null
2108	   *
2109	   * @return {Object}
2110	   */
2111	  var get = function(name, strict) {
2112	    if (!providers[name] && name.indexOf('.') !== -1) {
2113	      var parts = name.split('.');
2114	      var pivot = get(parts.shift());
2115
2116	      while (parts.length) {
2117	        pivot = pivot[parts.shift()];
2118	      }
2119
2120	      return pivot;
2121	    }
2122
2123	    if (hasOwnProp(instances, name)) {
2124	      return instances[name];
2125	    }
2126
2127	    if (hasOwnProp(providers, name)) {
2128	      if (currentlyResolving.indexOf(name) !== -1) {
2129	        currentlyResolving.push(name);
2130	        throw error('Cannot resolve circular dependency!');
2131	      }
2132
2133	      currentlyResolving.push(name);
2134	      instances[name] = providers[name][0](providers[name][1]);
2135	      currentlyResolving.pop();
2136
2137	      return instances[name];
2138	    }
2139
2140	    return parent.get(name, strict);
2141	  };
2142
2143	  var fnDef = function(fn, locals) {
2144
2145	    if (typeof locals === 'undefined') {
2146	      locals = {};
2147	    }
2148
2149	    if (typeof fn !== 'function') {
2150	      if (isArray$1(fn)) {
2151	        fn = annotate(fn.slice());
2152	      } else {
2153	        throw new Error('Cannot invoke "' + fn + '". Expected a function!');
2154	      }
2155	    }
2156
2157	    var inject = fn.$inject || parseAnnotations(fn);
2158	    var dependencies = inject.map(function(dep) {
2159	      if (hasOwnProp(locals, dep)) {
2160	        return locals[dep];
2161	      } else {
2162	        return get(dep);
2163	      }
2164	    });
2165
2166	    return {
2167	      fn: fn,
2168	      dependencies: dependencies
2169	    };
2170	  };
2171
2172	  var instantiate = function(Type) {
2173	    var def = fnDef(Type);
2174
2175	    var fn = def.fn,
2176	        dependencies = def.dependencies;
2177
2178	    // instantiate var args constructor
2179	    var Constructor = Function.prototype.bind.apply(fn, [ null ].concat(dependencies));
2180
2181	    return new Constructor();
2182	  };
2183
2184	  var invoke = function(func, context, locals) {
2185	    var def = fnDef(func, locals);
2186
2187	    var fn = def.fn,
2188	        dependencies = def.dependencies;
2189
2190	    return fn.apply(context, dependencies);
2191	  };
2192
2193
2194	  var createPrivateInjectorFactory = function(privateChildInjector) {
2195	    return annotate(function(key) {
2196	      return privateChildInjector.get(key);
2197	    });
2198	  };
2199
2200	  var createChild = function(modules, forceNewInstances) {
2201	    if (forceNewInstances && forceNewInstances.length) {
2202	      var fromParentModule = Object.create(null);
2203	      var matchedScopes = Object.create(null);
2204
2205	      var privateInjectorsCache = [];
2206	      var privateChildInjectors = [];
2207	      var privateChildFactories = [];
2208
2209	      var provider;
2210	      var cacheIdx;
2211	      var privateChildInjector;
2212	      var privateChildInjectorFactory;
2213	      for (var name in providers) {
2214	        provider = providers[name];
2215
2216	        if (forceNewInstances.indexOf(name) !== -1) {
2217	          if (provider[2] === 'private') {
2218	            cacheIdx = privateInjectorsCache.indexOf(provider[3]);
2219	            if (cacheIdx === -1) {
2220	              privateChildInjector = provider[3].createChild([], forceNewInstances);
2221	              privateChildInjectorFactory = createPrivateInjectorFactory(privateChildInjector);
2222	              privateInjectorsCache.push(provider[3]);
2223	              privateChildInjectors.push(privateChildInjector);
2224	              privateChildFactories.push(privateChildInjectorFactory);
2225	              fromParentModule[name] = [privateChildInjectorFactory, name, 'private', privateChildInjector];
2226	            } else {
2227	              fromParentModule[name] = [privateChildFactories[cacheIdx], name, 'private', privateChildInjectors[cacheIdx]];
2228	            }
2229	          } else {
2230	            fromParentModule[name] = [provider[2], provider[1]];
2231	          }
2232	          matchedScopes[name] = true;
2233	        }
2234
2235	        if ((provider[2] === 'factory' || provider[2] === 'type') && provider[1].$scope) {
2236	          /* jshint -W083 */
2237	          forceNewInstances.forEach(function(scope) {
2238	            if (provider[1].$scope.indexOf(scope) !== -1) {
2239	              fromParentModule[name] = [provider[2], provider[1]];
2240	              matchedScopes[scope] = true;
2241	            }
2242	          });
2243	        }
2244	      }
2245
2246	      forceNewInstances.forEach(function(scope) {
2247	        if (!matchedScopes[scope]) {
2248	          throw new Error('No provider for "' + scope + '". Cannot use provider from the parent!');
2249	        }
2250	      });
2251
2252	      modules.unshift(fromParentModule);
2253	    }
2254
2255	    return new Injector(modules, self);
2256	  };
2257
2258	  var factoryMap = {
2259	    factory: invoke,
2260	    type: instantiate,
2261	    value: function(value) {
2262	      return value;
2263	    }
2264	  };
2265
2266	  modules.forEach(function(module) {
2267
2268	    function arrayUnwrap(type, value) {
2269	      if (type !== 'value' && isArray$1(value)) {
2270	        value = annotate(value.slice());
2271	      }
2272
2273	      return value;
2274	    }
2275
2276	    // TODO(vojta): handle wrong inputs (modules)
2277	    if (module instanceof Module) {
2278	      module.forEach(function(provider) {
2279	        var name = provider[0];
2280	        var type = provider[1];
2281	        var value = provider[2];
2282
2283	        providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
2284	      });
2285	    } else if (typeof module === 'object') {
2286	      if (module.__exports__) {
2287	        var clonedModule = Object.keys(module).reduce(function(m, key) {
2288	          if (key.substring(0, 2) !== '__') {
2289	            m[key] = module[key];
2290	          }
2291	          return m;
2292	        }, Object.create(null));
2293
2294	        var privateInjector = new Injector((module.__modules__ || []).concat([clonedModule]), self);
2295	        var getFromPrivateInjector = annotate(function(key) {
2296	          return privateInjector.get(key);
2297	        });
2298	        module.__exports__.forEach(function(key) {
2299	          providers[key] = [getFromPrivateInjector, key, 'private', privateInjector];
2300	        });
2301	      } else {
2302	        Object.keys(module).forEach(function(name) {
2303	          if (module[name][2] === 'private') {
2304	            providers[name] = module[name];
2305	            return;
2306	          }
2307
2308	          var type = module[name][0];
2309	          var value = module[name][1];
2310
2311	          providers[name] = [factoryMap[type], arrayUnwrap(type, value), type];
2312	        });
2313	      }
2314	    }
2315	  });
2316
2317	  // public API
2318	  this.get = get;
2319	  this.invoke = invoke;
2320	  this.instantiate = instantiate;
2321	  this.createChild = createChild;
2322	}
2323
2324	var DEFAULT_RENDER_PRIORITY$1 = 1000;
2325
2326	/**
2327	 * The base implementation of shape and connection renderers.
2328	 *
2329	 * @param {EventBus} eventBus
2330	 * @param {number} [renderPriority=1000]
2331	 */
2332	function BaseRenderer(eventBus, renderPriority) {
2333	  var self = this;
2334
2335	  renderPriority = renderPriority || DEFAULT_RENDER_PRIORITY$1;
2336
2337	  eventBus.on([ 'render.shape', 'render.connection' ], renderPriority, function(evt, context) {
2338	    var type = evt.type,
2339	        element = context.element,
2340	        visuals = context.gfx;
2341
2342	    if (self.canRender(element)) {
2343	      if (type === 'render.shape') {
2344	        return self.drawShape(visuals, element);
2345	      } else {
2346	        return self.drawConnection(visuals, element);
2347	      }
2348	    }
2349	  });
2350
2351	  eventBus.on([ 'render.getShapePath', 'render.getConnectionPath'], renderPriority, function(evt, element) {
2352	    if (self.canRender(element)) {
2353	      if (evt.type === 'render.getShapePath') {
2354	        return self.getShapePath(element);
2355	      } else {
2356	        return self.getConnectionPath(element);
2357	      }
2358	    }
2359	  });
2360	}
2361
2362	/**
2363	 * Should check whether *this* renderer can render
2364	 * the element/connection.
2365	 *
2366	 * @param {element} element
2367	 *
2368	 * @returns {boolean}
2369	 */
2370	BaseRenderer.prototype.canRender = function() {};
2371
2372	/**
2373	 * Provides the shape's snap svg element to be drawn on the `canvas`.
2374	 *
2375	 * @param {djs.Graphics} visuals
2376	 * @param {Shape} shape
2377	 *
2378	 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2379	 */
2380	BaseRenderer.prototype.drawShape = function() {};
2381
2382	/**
2383	 * Provides the shape's snap svg element to be drawn on the `canvas`.
2384	 *
2385	 * @param {djs.Graphics} visuals
2386	 * @param {Connection} connection
2387	 *
2388	 * @returns {Snap.svg} [returns a Snap.svg paper element ]
2389	 */
2390	BaseRenderer.prototype.drawConnection = function() {};
2391
2392	/**
2393	 * Gets the SVG path of a shape that represents it's visual bounds.
2394	 *
2395	 * @param {Shape} shape
2396	 *
2397	 * @return {string} svg path
2398	 */
2399	BaseRenderer.prototype.getShapePath = function() {};
2400
2401	/**
2402	 * Gets the SVG path of a connection that represents it's visual bounds.
2403	 *
2404	 * @param {Connection} connection
2405	 *
2406	 * @return {string} svg path
2407	 */
2408	BaseRenderer.prototype.getConnectionPath = function() {};
2409
2410	function componentsToPath(elements) {
2411	  return elements.join(',').replace(/,?([A-z]),?/g, '$1');
2412	}
2413
2414	function toSVGPoints(points) {
2415	  var result = '';
2416
2417	  for (var i = 0, p; (p = points[i]); i++) {
2418	    result += p.x + ',' + p.y + ' ';
2419	  }
2420
2421	  return result;
2422	}
2423
2424	function createLine(points, attrs) {
2425
2426	  var line = create$1('polyline');
2427	  attr(line, { points: toSVGPoints(points) });
2428
2429	  if (attrs) {
2430	    attr(line, attrs);
2431	  }
2432
2433	  return line;
2434	}
2435
2436	function updateLine(gfx, points) {
2437	  attr(gfx, { points: toSVGPoints(points) });
2438
2439	  return gfx;
2440	}
2441
2442	/**
2443	 * Get parent elements.
2444	 *
2445	 * @param {Array<djs.model.base>} elements
2446	 *
2447	 * @returns {Array<djs.model.Base>}
2448	 */
2449	function getParents$1(elements) {
2450
2451	  // find elements that are not children of any other elements
2452	  return filter(elements, function(element) {
2453	    return !find(elements, function(e) {
2454	      return e !== element && getParent$1(element, e);
2455	    });
2456	  });
2457	}
2458
2459
2460	function getParent$1(element, parent) {
2461	  if (!parent) {
2462	    return;
2463	  }
2464
2465	  if (element === parent) {
2466	    return parent;
2467	  }
2468
2469	  if (!element.parent) {
2470	    return;
2471	  }
2472
2473	  return getParent$1(element.parent, parent);
2474	}
2475
2476
2477	/**
2478	 * Adds an element to a collection and returns true if the
2479	 * element was added.
2480	 *
2481	 * @param {Array<Object>} elements
2482	 * @param {Object} e
2483	 * @param {boolean} unique
2484	 */
2485	function add$1(elements, e, unique) {
2486	  var canAdd = !unique || elements.indexOf(e) === -1;
2487
2488	  if (canAdd) {
2489	    elements.push(e);
2490	  }
2491
2492	  return canAdd;
2493	}
2494
2495
2496	/**
2497	 * Iterate over each element in a collection, calling the iterator function `fn`
2498	 * with (element, index, recursionDepth).
2499	 *
2500	 * Recurse into all elements that are returned by `fn`.
2501	 *
2502	 * @param  {Object|Array<Object>} elements
2503	 * @param  {Function} fn iterator function called with (element, index, recursionDepth)
2504	 * @param  {number} [depth] maximum recursion depth
2505	 */
2506	function eachElement(elements, fn, depth) {
2507
2508	  depth = depth || 0;
2509
2510	  if (!isArray$2(elements)) {
2511	    elements = [ elements ];
2512	  }
2513
2514	  forEach(elements, function(s, i) {
2515	    var filter = fn(s, i, depth);
2516
2517	    if (isArray$2(filter) && filter.length) {
2518	      eachElement(filter, fn, depth + 1);
2519	    }
2520	  });
2521	}
2522
2523
2524	/**
2525	 * Collects self + child elements up to a given depth from a list of elements.
2526	 *
2527	 * @param  {djs.model.Base|Array<djs.model.Base>} elements the elements to select the children from
2528	 * @param  {boolean} unique whether to return a unique result set (no duplicates)
2529	 * @param  {number} maxDepth the depth to search through or -1 for infinite
2530	 *
2531	 * @return {Array<djs.model.Base>} found elements
2532	 */
2533	function selfAndChildren(elements, unique, maxDepth) {
2534	  var result = [],
2535	      processedChildren = [];
2536
2537	  eachElement(elements, function(element, i, depth) {
2538	    add$1(result, element, unique);
2539
2540	    var children = element.children;
2541
2542	    // max traversal depth not reached yet
2543	    if (maxDepth === -1 || depth < maxDepth) {
2544
2545	      // children exist && children not yet processed
2546	      if (children && add$1(processedChildren, children, unique)) {
2547	        return children;
2548	      }
2549	    }
2550	  });
2551
2552	  return result;
2553	}
2554
2555
2556	/**
2557	 * Return self + ALL children for a number of elements
2558	 *
2559	 * @param  {Array<djs.model.Base>} elements to query
2560	 * @param  {boolean} allowDuplicates to allow duplicates in the result set
2561	 *
2562	 * @return {Array<djs.model.Base>} the collected elements
2563	 */
2564	function selfAndAllChildren(elements, allowDuplicates) {
2565	  return selfAndChildren(elements, !allowDuplicates, -1);
2566	}
2567
2568
2569	/**
2570	 * Gets the the closure for all selected elements,
2571	 * their enclosed children and connections.
2572	 *
2573	 * @param {Array<djs.model.Base>} elements
2574	 * @param {boolean} [isTopLevel=true]
2575	 * @param {Object} [existingClosure]
2576	 *
2577	 * @return {Object} newClosure
2578	 */
2579	function getClosure(elements, isTopLevel, closure) {
2580
2581	  if (isUndefined$1(isTopLevel)) {
2582	    isTopLevel = true;
2583	  }
2584
2585	  if (isObject(isTopLevel)) {
2586	    closure = isTopLevel;
2587	    isTopLevel = true;
2588	  }
2589
2590
2591	  closure = closure || {};
2592
2593	  var allShapes = copyObject(closure.allShapes),
2594	      allConnections = copyObject(closure.allConnections),
2595	      enclosedElements = copyObject(closure.enclosedElements),
2596	      enclosedConnections = copyObject(closure.enclosedConnections);
2597
2598	  var topLevel = copyObject(
2599	    closure.topLevel,
2600	    isTopLevel && groupBy(elements, function(e) { return e.id; })
2601	  );
2602
2603
2604	  function handleConnection(c) {
2605	    if (topLevel[c.source.id] && topLevel[c.target.id]) {
2606	      topLevel[c.id] = [ c ];
2607	    }
2608
2609	    // not enclosed as a child, but maybe logically
2610	    // (connecting two moved elements?)
2611	    if (allShapes[c.source.id] && allShapes[c.target.id]) {
2612	      enclosedConnections[c.id] = enclosedElements[c.id] = c;
2613	    }
2614
2615	    allConnections[c.id] = c;
2616	  }
2617
2618	  function handleElement(element) {
2619
2620	    enclosedElements[element.id] = element;
2621
2622	    if (element.waypoints) {
2623
2624	      // remember connection
2625	      enclosedConnections[element.id] = allConnections[element.id] = element;
2626	    } else {
2627
2628	      // remember shape
2629	      allShapes[element.id] = element;
2630
2631	      // remember all connections
2632	      forEach(element.incoming, handleConnection);
2633
2634	      forEach(element.outgoing, handleConnection);
2635
2636	      // recurse into children
2637	      return element.children;
2638	    }
2639	  }
2640
2641	  eachElement(elements, handleElement);
2642
2643	  return {
2644	    allShapes: allShapes,
2645	    allConnections: allConnections,
2646	    topLevel: topLevel,
2647	    enclosedConnections: enclosedConnections,
2648	    enclosedElements: enclosedElements
2649	  };
2650	}
2651
2652	/**
2653	 * Returns the surrounding bbox for all elements in
2654	 * the array or the element primitive.
2655	 *
2656	 * @param {Array<djs.model.Shape>|djs.model.Shape} elements
2657	 * @param {boolean} stopRecursion
2658	 */
2659	function getBBox(elements, stopRecursion) {
2660
2661	  stopRecursion = !!stopRecursion;
2662	  if (!isArray$2(elements)) {
2663	    elements = [elements];
2664	  }
2665
2666	  var minX,
2667	      minY,
2668	      maxX,
2669	      maxY;
2670
2671	  forEach(elements, function(element) {
2672
2673	    // If element is a connection the bbox must be computed first
2674	    var bbox = element;
2675	    if (element.waypoints && !stopRecursion) {
2676	      bbox = getBBox(element.waypoints, true);
2677	    }
2678
2679	    var x = bbox.x,
2680	        y = bbox.y,
2681	        height = bbox.height || 0,
2682	        width = bbox.width || 0;
2683
2684	    if (x < minX || minX === undefined) {
2685	      minX = x;
2686	    }
2687	    if (y < minY || minY === undefined) {
2688	      minY = y;
2689	    }
2690
2691	    if ((x + width) > maxX || maxX === undefined) {
2692	      maxX = x + width;
2693	    }
2694	    if ((y + height) > maxY || maxY === undefined) {
2695	      maxY = y + height;
2696	    }
2697	  });
2698
2699	  return {
2700	    x: minX,
2701	    y: minY,
2702	    height: maxY - minY,
2703	    width: maxX - minX
2704	  };
2705	}
2706
2707
2708	/**
2709	 * Returns all elements that are enclosed from the bounding box.
2710	 *
2711	 *   * If bbox.(width|height) is not specified the method returns
2712	 *     all elements with element.x/y > bbox.x/y
2713	 *   * If only bbox.x or bbox.y is specified, method return all elements with
2714	 *     e.x > bbox.x or e.y > bbox.y
2715	 *
2716	 * @param {Array<djs.model.Shape>} elements List of Elements to search through
2717	 * @param {djs.model.Shape} bbox the enclosing bbox.
2718	 *
2719	 * @return {Array<djs.model.Shape>} enclosed elements
2720	 */
2721	function getEnclosedElements(elements, bbox) {
2722
2723	  var filteredElements = {};
2724
2725	  forEach(elements, function(element) {
2726
2727	    var e = element;
2728
2729	    if (e.waypoints) {
2730	      e = getBBox(e);
2731	    }
2732
2733	    if (!isNumber(bbox.y) && (e.x > bbox.x)) {
2734	      filteredElements[element.id] = element;
2735	    }
2736	    if (!isNumber(bbox.x) && (e.y > bbox.y)) {
2737	      filteredElements[element.id] = element;
2738	    }
2739	    if (e.x > bbox.x && e.y > bbox.y) {
2740	      if (isNumber(bbox.width) && isNumber(bbox.height) &&
2741	          e.width + e.x < bbox.width + bbox.x &&
2742	          e.height + e.y < bbox.height + bbox.y) {
2743
2744	        filteredElements[element.id] = element;
2745	      } else if (!isNumber(bbox.width) || !isNumber(bbox.height)) {
2746	        filteredElements[element.id] = element;
2747	      }
2748	    }
2749	  });
2750
2751	  return filteredElements;
2752	}
2753
2754
2755	function getType(element) {
2756
2757	  if ('waypoints' in element) {
2758	    return 'connection';
2759	  }
2760
2761	  if ('x' in element) {
2762	    return 'shape';
2763	  }
2764
2765	  return 'root';
2766	}
2767
2768	function isFrameElement$1(element) {
2769
2770	  return !!(element && element.isFrame);
2771	}
2772
2773	// helpers ///////////////////////////////
2774
2775	function copyObject(src1, src2) {
2776	  return assign({}, src1 || {}, src2 || {});
2777	}
2778
2779	// apply default renderer with lowest possible priority
2780	// so that it only kicks in if noone else could render
2781	var DEFAULT_RENDER_PRIORITY = 1;
2782
2783	/**
2784	 * The default renderer used for shapes and connections.
2785	 *
2786	 * @param {EventBus} eventBus
2787	 * @param {Styles} styles
2788	 */
2789	function DefaultRenderer(eventBus, styles) {
2790
2791	  //
2792	  BaseRenderer.call(this, eventBus, DEFAULT_RENDER_PRIORITY);
2793
2794	  this.CONNECTION_STYLE = styles.style([ 'no-fill' ], { strokeWidth: 5, stroke: 'fuchsia' });
2795	  this.SHAPE_STYLE = styles.style({ fill: 'white', stroke: 'fuchsia', strokeWidth: 2 });
2796	  this.FRAME_STYLE = styles.style([ 'no-fill' ], { stroke: 'fuchsia', strokeDasharray: 4, strokeWidth: 2 });
2797	}
2798
2799	inherits$1(DefaultRenderer, BaseRenderer);
2800
2801
2802	DefaultRenderer.prototype.canRender = function() {
2803	  return true;
2804	};
2805
2806	DefaultRenderer.prototype.drawShape = function drawShape(visuals, element) {
2807	  var rect = create$1('rect');
2808
2809	  attr(rect, {
2810	    x: 0,
2811	    y: 0,
2812	    width: element.width || 0,
2813	    height: element.height || 0
2814	  });
2815
2816	  if (isFrameElement$1(element)) {
2817	    attr(rect, this.FRAME_STYLE);
2818	  } else {
2819	    attr(rect, this.SHAPE_STYLE);
2820	  }
2821
2822	  append(visuals, rect);
2823
2824	  return rect;
2825	};
2826
2827	DefaultRenderer.prototype.drawConnection = function drawConnection(visuals, connection) {
2828
2829	  var line = createLine(connection.waypoints, this.CONNECTION_STYLE);
2830	  append(visuals, line);
2831
2832	  return line;
2833	};
2834
2835	DefaultRenderer.prototype.getShapePath = function getShapePath(shape) {
2836
2837	  var x = shape.x,
2838	      y = shape.y,
2839	      width = shape.width,
2840	      height = shape.height;
2841
2842	  var shapePath = [
2843	    ['M', x, y],
2844	    ['l', width, 0],
2845	    ['l', 0, height],
2846	    ['l', -width, 0],
2847	    ['z']
2848	  ];
2849
2850	  return componentsToPath(shapePath);
2851	};
2852
2853	DefaultRenderer.prototype.getConnectionPath = function getConnectionPath(connection) {
2854	  var waypoints = connection.waypoints;
2855
2856	  var idx, point, connectionPath = [];
2857
2858	  for (idx = 0; (point = waypoints[idx]); idx++) {
2859
2860	    // take invisible docking into account
2861	    // when creating the path
2862	    point = point.original || point;
2863
2864	    connectionPath.push([ idx === 0 ? 'M' : 'L', point.x, point.y ]);
2865	  }
2866
2867	  return componentsToPath(connectionPath);
2868	};
2869
2870
2871	DefaultRenderer.$inject = [ 'eventBus', 'styles' ];
2872
2873	/**
2874	 * A component that manages shape styles
2875	 */
2876	function Styles() {
2877
2878	  var defaultTraits = {
2879
2880	    'no-fill': {
2881	      fill: 'none'
2882	    },
2883	    'no-border': {
2884	      strokeOpacity: 0.0
2885	    },
2886	    'no-events': {
2887	      pointerEvents: 'none'
2888	    }
2889	  };
2890
2891	  var self = this;
2892
2893	  /**
2894	   * Builds a style definition from a className, a list of traits and an object of additional attributes.
2895	   *
2896	   * @param  {string} className
2897	   * @param  {Array<string>} traits
2898	   * @param  {Object} additionalAttrs
2899	   *
2900	   * @return {Object} the style defintion
2901	   */
2902	  this.cls = function(className, traits, additionalAttrs) {
2903	    var attrs = this.style(traits, additionalAttrs);
2904
2905	    return assign(attrs, { 'class': className });
2906	  };
2907
2908	  /**
2909	   * Builds a style definition from a list of traits and an object of additional attributes.
2910	   *
2911	   * @param  {Array<string>} traits
2912	   * @param  {Object} additionalAttrs
2913	   *
2914	   * @return {Object} the style defintion
2915	   */
2916	  this.style = function(traits, additionalAttrs) {
2917
2918	    if (!isArray$2(traits) && !additionalAttrs) {
2919	      additionalAttrs = traits;
2920	      traits = [];
2921	    }
2922
2923	    var attrs = reduce(traits, function(attrs, t) {
2924	      return assign(attrs, defaultTraits[t] || {});
2925	    }, {});
2926
2927	    return additionalAttrs ? assign(attrs, additionalAttrs) : attrs;
2928	  };
2929
2930	  this.computeStyle = function(custom, traits, defaultStyles) {
2931	    if (!isArray$2(traits)) {
2932	      defaultStyles = traits;
2933	      traits = [];
2934	    }
2935
2936	    return self.style(traits || [], assign({}, defaultStyles, custom || {}));
2937	  };
2938	}
2939
2940	var DrawModule$1 = {
2941	  __init__: [ 'defaultRenderer' ],
2942	  defaultRenderer: [ 'type', DefaultRenderer ],
2943	  styles: [ 'type', Styles ]
2944	};
2945
2946	/**
2947	 * Failsafe remove an element from a collection
2948	 *
2949	 * @param  {Array<Object>} [collection]
2950	 * @param  {Object} [element]
2951	 *
2952	 * @return {number} the previous index of the element
2953	 */
2954	function remove(collection, element) {
2955
2956	  if (!collection || !element) {
2957	    return -1;
2958	  }
2959
2960	  var idx = collection.indexOf(element);
2961
2962	  if (idx !== -1) {
2963	    collection.splice(idx, 1);
2964	  }
2965
2966	  return idx;
2967	}
2968
2969	/**
2970	 * Fail save add an element to the given connection, ensuring
2971	 * it does not yet exist.
2972	 *
2973	 * @param {Array<Object>} collection
2974	 * @param {Object} element
2975	 * @param {number} idx
2976	 */
2977	function add(collection, element, idx) {
2978
2979	  if (!collection || !element) {
2980	    return;
2981	  }
2982
2983	  if (typeof idx !== 'number') {
2984	    idx = -1;
2985	  }
2986
2987	  var currentIdx = collection.indexOf(element);
2988
2989	  if (currentIdx !== -1) {
2990
2991	    if (currentIdx === idx) {
2992
2993	      // nothing to do, position has not changed
2994	      return;
2995	    } else {
2996
2997	      if (idx !== -1) {
2998
2999	        // remove from current position
3000	        collection.splice(currentIdx, 1);
3001	      } else {
3002
3003	        // already exists in collection
3004	        return;
3005	      }
3006	    }
3007	  }
3008
3009	  if (idx !== -1) {
3010
3011	    // insert at specified position
3012	    collection.splice(idx, 0, element);
3013	  } else {
3014
3015	    // push to end
3016	    collection.push(element);
3017	  }
3018	}
3019
3020
3021	/**
3022	 * Fail save get the index of an element in a collection.
3023	 *
3024	 * @param {Array<Object>} collection
3025	 * @param {Object} element
3026	 *
3027	 * @return {number} the index or -1 if collection or element do
3028	 *                  not exist or the element is not contained.
3029	 */
3030	function indexOf(collection, element) {
3031
3032	  if (!collection || !element) {
3033	    return -1;
3034	  }
3035
3036	  return collection.indexOf(element);
3037	}
3038
3039	/**
3040	 * Computes the distance between two points
3041	 *
3042	 * @param  {Point}  p
3043	 * @param  {Point}  q
3044	 *
3045	 * @return {number}  distance
3046	 */
3047	function pointDistance(a, b) {
3048	  if (!a || !b) {
3049	    return -1;
3050	  }
3051
3052	  return Math.sqrt(
3053	    Math.pow(a.x - b.x, 2) +
3054	    Math.pow(a.y - b.y, 2)
3055	  );
3056	}
3057
3058
3059	/**
3060	 * Returns true if the point r is on the line between p and q
3061	 *
3062	 * @param  {Point}  p
3063	 * @param  {Point}  q
3064	 * @param  {Point}  r
3065	 * @param  {number} [accuracy=5] accuracy for points on line check (lower is better)
3066	 *
3067	 * @return {boolean}
3068	 */
3069	function pointsOnLine(p, q, r, accuracy) {
3070
3071	  if (typeof accuracy === 'undefined') {
3072	    accuracy = 5;
3073	  }
3074
3075	  if (!p || !q || !r) {
3076	    return false;
3077	  }
3078
3079	  var val = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x),
3080	      dist = pointDistance(p, q);
3081
3082	  // @see http://stackoverflow.com/a/907491/412190
3083	  return Math.abs(val / dist) <= accuracy;
3084	}
3085
3086
3087	var ALIGNED_THRESHOLD = 2;
3088
3089	/**
3090	 * Check whether two points are horizontally or vertically aligned.
3091	 *
3092	 * @param {Array<Point>|Point}
3093	 * @param {Point}
3094	 *
3095	 * @return {string|boolean}
3096	 */
3097	function pointsAligned(a, b) {
3098	  var points;
3099
3100	  if (isArray$2(a)) {
3101	    points = a;
3102	  } else {
3103	    points = [ a, b ];
3104	  }
3105
3106	  if (pointsAlignedHorizontally(points)) {
3107	    return 'h';
3108	  }
3109
3110	  if (pointsAlignedVertically(points)) {
3111	    return 'v';
3112	  }
3113
3114	  return false;
3115	}
3116
3117	function pointsAlignedHorizontally(a, b) {
3118	  var points;
3119
3120	  if (isArray$2(a)) {
3121	    points = a;
3122	  } else {
3123	    points = [ a, b ];
3124	  }
3125
3126	  var firstPoint = points.slice().shift();
3127
3128	  return every(points, function(point) {
3129	    return Math.abs(firstPoint.y - point.y) <= ALIGNED_THRESHOLD;
3130	  });
3131	}
3132
3133	function pointsAlignedVertically(a, b) {
3134	  var points;
3135
3136	  if (isArray$2(a)) {
3137	    points = a;
3138	  } else {
3139	    points = [ a, b ];
3140	  }
3141
3142	  var firstPoint = points.slice().shift();
3143
3144	  return every(points, function(point) {
3145	    return Math.abs(firstPoint.x - point.x) <= ALIGNED_THRESHOLD;
3146	  });
3147	}
3148
3149
3150
3151	/**
3152	 * Returns true if the point p is inside the rectangle rect
3153	 *
3154	 * @param  {Point}  p
3155	 * @param  {Rect} rect
3156	 * @param  {number} tolerance
3157	 *
3158	 * @return {boolean}
3159	 */
3160	function pointInRect(p, rect, tolerance) {
3161	  tolerance = tolerance || 0;
3162
3163	  return p.x > rect.x - tolerance &&
3164	         p.y > rect.y - tolerance &&
3165	         p.x < rect.x + rect.width + tolerance &&
3166	         p.y < rect.y + rect.height + tolerance;
3167	}
3168
3169	/**
3170	 * Returns a point in the middle of points p and q
3171	 *
3172	 * @param  {Point}  p
3173	 * @param  {Point}  q
3174	 *
3175	 * @return {Point} middle point
3176	 */
3177	function getMidPoint(p, q) {
3178	  return {
3179	    x: Math.round(p.x + ((q.x - p.x) / 2.0)),
3180	    y: Math.round(p.y + ((q.y - p.y) / 2.0))
3181	  };
3182	}
3183
3184	/**
3185	 * This file contains source code adapted from Snap.svg (licensed Apache-2.0).
3186	 *
3187	 * @see https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js
3188	 */
3189
3190	/* eslint no-fallthrough: "off" */
3191
3192	var p2s = /,?([a-z]),?/gi,
3193	    toFloat = parseFloat,
3194	    math = Math,
3195	    PI = math.PI,
3196	    mmin = math.min,
3197	    mmax = math.max,
3198	    pow = math.pow,
3199	    abs$7 = math.abs,
3200	    pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?[\s]*,?[\s]*)+)/ig,
3201	    pathValues = /(-?\d*\.?\d*(?:e[-+]?\d+)?)[\s]*,?[\s]*/ig;
3202
3203	var isArray = Array.isArray || function(o) { return o instanceof Array; };
3204
3205	function hasProperty(obj, property) {
3206	  return Object.prototype.hasOwnProperty.call(obj, property);
3207	}
3208
3209	function clone(obj) {
3210
3211	  if (typeof obj == 'function' || Object(obj) !== obj) {
3212	    return obj;
3213	  }
3214
3215	  var res = new obj.constructor;
3216
3217	  for (var key in obj) {
3218	    if (hasProperty(obj, key)) {
3219	      res[key] = clone(obj[key]);
3220	    }
3221	  }
3222
3223	  return res;
3224	}
3225
3226	function repush(array, item) {
3227	  for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
3228	    return array.push(array.splice(i, 1)[0]);
3229	  }
3230	}
3231
3232	function cacher(f) {
3233
3234	  function newf() {
3235
3236	    var arg = Array.prototype.slice.call(arguments, 0),
3237	        args = arg.join('\u2400'),
3238	        cache = newf.cache = newf.cache || {},
3239	        count = newf.count = newf.count || [];
3240
3241	    if (hasProperty(cache, args)) {
3242	      repush(count, args);
3243	      return cache[args];
3244	    }
3245
3246	    count.length >= 1e3 && delete cache[count.shift()];
3247	    count.push(args);
3248	    cache[args] = f.apply(0, arg);
3249
3250	    return cache[args];
3251	  }
3252	  return newf;
3253	}
3254
3255	function parsePathString(pathString) {
3256
3257	  if (!pathString) {
3258	    return null;
3259	  }
3260
3261	  var pth = paths(pathString);
3262
3263	  if (pth.arr) {
3264	    return clone(pth.arr);
3265	  }
3266
3267	  var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0 },
3268	      data = [];
3269
3270	  if (isArray(pathString) && isArray(pathString[0])) { // rough assumption
3271	    data = clone(pathString);
3272	  }
3273
3274	  if (!data.length) {
3275
3276	    String(pathString).replace(pathCommand, function(a, b, c) {
3277	      var params = [],
3278	          name = b.toLowerCase();
3279
3280	      c.replace(pathValues, function(a, b) {
3281	        b && params.push(+b);
3282	      });
3283
3284	      if (name == 'm' && params.length > 2) {
3285	        data.push([b].concat(params.splice(0, 2)));
3286	        name = 'l';
3287	        b = b == 'm' ? 'l' : 'L';
3288	      }
3289
3290	      while (params.length >= paramCounts[name]) {
3291	        data.push([b].concat(params.splice(0, paramCounts[name])));
3292	        if (!paramCounts[name]) {
3293	          break;
3294	        }
3295	      }
3296	    });
3297	  }
3298
3299	  data.toString = paths.toString;
3300	  pth.arr = clone(data);
3301
3302	  return data;
3303	}
3304
3305	function paths(ps) {
3306	  var p = paths.ps = paths.ps || {};
3307
3308	  if (p[ps]) {
3309	    p[ps].sleep = 100;
3310	  } else {
3311	    p[ps] = {
3312	      sleep: 100
3313	    };
3314	  }
3315
3316	  setTimeout(function() {
3317	    for (var key in p) {
3318	      if (hasProperty(p, key) && key != ps) {
3319	        p[key].sleep--;
3320	        !p[key].sleep && delete p[key];
3321	      }
3322	    }
3323	  });
3324
3325	  return p[ps];
3326	}
3327
3328	function rectBBox(x, y, width, height) {
3329
3330	  if (arguments.length === 1) {
3331	    y = x.y;
3332	    width = x.width;
3333	    height = x.height;
3334	    x = x.x;
3335	  }
3336
3337	  return {
3338	    x: x,
3339	    y: y,
3340	    width: width,
3341	    height: height,
3342	    x2: x + width,
3343	    y2: y + height
3344	  };
3345	}
3346
3347	function pathToString() {
3348	  return this.join(',').replace(p2s, '$1');
3349	}
3350
3351	function pathClone(pathArray) {
3352	  var res = clone(pathArray);
3353	  res.toString = pathToString;
3354	  return res;
3355	}
3356
3357	function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
3358	  var t1 = 1 - t,
3359	      t13 = pow(t1, 3),
3360	      t12 = pow(t1, 2),
3361	      t2 = t * t,
3362	      t3 = t2 * t,
3363	      x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
3364	      y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y;
3365
3366	  return {
3367	    x: fixError(x),
3368	    y: fixError(y)
3369	  };
3370	}
3371
3372	function bezierBBox(points) {
3373
3374	  var bbox = curveBBox.apply(null, points);
3375
3376	  return rectBBox(
3377	    bbox.x0,
3378	    bbox.y0,
3379	    bbox.x1 - bbox.x0,
3380	    bbox.y1 - bbox.y0
3381	  );
3382	}
3383
3384	function isPointInsideBBox$2(bbox, x, y) {
3385	  return x >= bbox.x &&
3386	    x <= bbox.x + bbox.width &&
3387	    y >= bbox.y &&
3388	    y <= bbox.y + bbox.height;
3389	}
3390
3391	function isBBoxIntersect(bbox1, bbox2) {
3392	  bbox1 = rectBBox(bbox1);
3393	  bbox2 = rectBBox(bbox2);
3394	  return isPointInsideBBox$2(bbox2, bbox1.x, bbox1.y)
3395	    || isPointInsideBBox$2(bbox2, bbox1.x2, bbox1.y)
3396	    || isPointInsideBBox$2(bbox2, bbox1.x, bbox1.y2)
3397	    || isPointInsideBBox$2(bbox2, bbox1.x2, bbox1.y2)
3398	    || isPointInsideBBox$2(bbox1, bbox2.x, bbox2.y)
3399	    || isPointInsideBBox$2(bbox1, bbox2.x2, bbox2.y)
3400	    || isPointInsideBBox$2(bbox1, bbox2.x, bbox2.y2)
3401	    || isPointInsideBBox$2(bbox1, bbox2.x2, bbox2.y2)
3402	    || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x
3403	        || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
3404	    && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y
3405	        || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
3406	}
3407
3408	function base3(t, p1, p2, p3, p4) {
3409	  var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
3410	      t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
3411	  return t * t2 - 3 * p1 + 3 * p2;
3412	}
3413
3414	function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
3415
3416	  if (z == null) {
3417	    z = 1;
3418	  }
3419
3420	  z = z > 1 ? 1 : z < 0 ? 0 : z;
3421
3422	  var z2 = z / 2,
3423	      n = 12,
3424	      Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],
3425	      Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472],
3426	      sum = 0;
3427
3428	  for (var i = 0; i < n; i++) {
3429	    var ct = z2 * Tvalues[i] + z2,
3430	        xbase = base3(ct, x1, x2, x3, x4),
3431	        ybase = base3(ct, y1, y2, y3, y4),
3432	        comb = xbase * xbase + ybase * ybase;
3433
3434	    sum += Cvalues[i] * math.sqrt(comb);
3435	  }
3436
3437	  return z2 * sum;
3438	}
3439
3440
3441	function intersectLines(x1, y1, x2, y2, x3, y3, x4, y4) {
3442
3443	  if (
3444	    mmax(x1, x2) < mmin(x3, x4) ||
3445	      mmin(x1, x2) > mmax(x3, x4) ||
3446	      mmax(y1, y2) < mmin(y3, y4) ||
3447	      mmin(y1, y2) > mmax(y3, y4)
3448	  ) {
3449	    return;
3450	  }
3451
3452	  var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
3453	      ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
3454	      denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
3455
3456	  if (!denominator) {
3457	    return;
3458	  }
3459
3460	  var px = fixError(nx / denominator),
3461	      py = fixError(ny / denominator),
3462	      px2 = +px.toFixed(2),
3463	      py2 = +py.toFixed(2);
3464
3465	  if (
3466	    px2 < +mmin(x1, x2).toFixed(2) ||
3467	      px2 > +mmax(x1, x2).toFixed(2) ||
3468	      px2 < +mmin(x3, x4).toFixed(2) ||
3469	      px2 > +mmax(x3, x4).toFixed(2) ||
3470	      py2 < +mmin(y1, y2).toFixed(2) ||
3471	      py2 > +mmax(y1, y2).toFixed(2) ||
3472	      py2 < +mmin(y3, y4).toFixed(2) ||
3473	      py2 > +mmax(y3, y4).toFixed(2)
3474	  ) {
3475	    return;
3476	  }
3477
3478	  return { x: px, y: py };
3479	}
3480
3481	function fixError(number) {
3482	  return Math.round(number * 100000000000) / 100000000000;
3483	}
3484
3485	function findBezierIntersections(bez1, bez2, justCount) {
3486	  var bbox1 = bezierBBox(bez1),
3487	      bbox2 = bezierBBox(bez2);
3488
3489	  if (!isBBoxIntersect(bbox1, bbox2)) {
3490	    return justCount ? 0 : [];
3491	  }
3492
3493	  // As an optimization, lines will have only 1 segment
3494
3495	  var l1 = bezlen.apply(0, bez1),
3496	      l2 = bezlen.apply(0, bez2),
3497	      n1 = isLine(bez1) ? 1 : ~~(l1 / 5) || 1,
3498	      n2 = isLine(bez2) ? 1 : ~~(l2 / 5) || 1,
3499	      dots1 = [],
3500	      dots2 = [],
3501	      xy = {},
3502	      res = justCount ? 0 : [];
3503
3504	  for (var i = 0; i < n1 + 1; i++) {
3505	    var p = findDotsAtSegment.apply(0, bez1.concat(i / n1));
3506	    dots1.push({ x: p.x, y: p.y, t: i / n1 });
3507	  }
3508
3509	  for (i = 0; i < n2 + 1; i++) {
3510	    p = findDotsAtSegment.apply(0, bez2.concat(i / n2));
3511	    dots2.push({ x: p.x, y: p.y, t: i / n2 });
3512	  }
3513
3514	  for (i = 0; i < n1; i++) {
3515
3516	    for (var j = 0; j < n2; j++) {
3517	      var di = dots1[i],
3518	          di1 = dots1[i + 1],
3519	          dj = dots2[j],
3520	          dj1 = dots2[j + 1],
3521	          ci = abs$7(di1.x - di.x) < .01 ? 'y' : 'x',
3522	          cj = abs$7(dj1.x - dj.x) < .01 ? 'y' : 'x',
3523	          is = intersectLines(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y),
3524	          key;
3525
3526	      if (is) {
3527	        key = is.x.toFixed(9) + '#' + is.y.toFixed(9);
3528
3529	        if (xy[key]) {
3530	          continue;
3531	        }
3532
3533	        xy[key] = true;
3534
3535	        var t1 = di.t + abs$7((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
3536	            t2 = dj.t + abs$7((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
3537
3538	        if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
3539
3540	          if (justCount) {
3541	            res++;
3542	          } else {
3543	            res.push({
3544	              x: is.x,
3545	              y: is.y,
3546	              t1: t1,
3547	              t2: t2
3548	            });
3549	          }
3550	        }
3551	      }
3552	    }
3553	  }
3554
3555	  return res;
3556	}
3557
3558
3559	/**
3560	 * Find or counts the intersections between two SVG paths.
3561	 *
3562	 * Returns a number in counting mode and a list of intersections otherwise.
3563	 *
3564	 * A single intersection entry contains the intersection coordinates (x, y)
3565	 * as well as additional information regarding the intersecting segments
3566	 * on each path (segment1, segment2) and the relative location of the
3567	 * intersection on these segments (t1, t2).
3568	 *
3569	 * The path may be an SVG path string or a list of path components
3570	 * such as `[ [ 'M', 0, 10 ], [ 'L', 20, 0 ] ]`.
3571	 *
3572	 * @example
3573	 *
3574	 * var intersections = findPathIntersections(
3575	 *   'M0,0L100,100',
3576	 *   [ [ 'M', 0, 100 ], [ 'L', 100, 0 ] ]
3577	 * );
3578	 *
3579	 * // intersections = [
3580	 * //   { x: 50, y: 50, segment1: 1, segment2: 1, t1: 0.5, t2: 0.5 }
3581	 * // ]
3582	 *
3583	 * @param {String|Array<PathDef>} path1
3584	 * @param {String|Array<PathDef>} path2
3585	 * @param {Boolean} [justCount=false]
3586	 *
3587	 * @return {Array<Intersection>|Number}
3588	 */
3589	function findPathIntersections(path1, path2, justCount) {
3590	  path1 = pathToCurve(path1);
3591	  path2 = pathToCurve(path2);
3592
3593	  var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
3594	      res = justCount ? 0 : [];
3595
3596	  for (var i = 0, ii = path1.length; i < ii; i++) {
3597	    var pi = path1[i];
3598
3599	    if (pi[0] == 'M') {
3600	      x1 = x1m = pi[1];
3601	      y1 = y1m = pi[2];
3602	    } else {
3603
3604	      if (pi[0] == 'C') {
3605	        bez1 = [x1, y1].concat(pi.slice(1));
3606	        x1 = bez1[6];
3607	        y1 = bez1[7];
3608	      } else {
3609	        bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
3610	        x1 = x1m;
3611	        y1 = y1m;
3612	      }
3613
3614	      for (var j = 0, jj = path2.length; j < jj; j++) {
3615	        var pj = path2[j];
3616
3617	        if (pj[0] == 'M') {
3618	          x2 = x2m = pj[1];
3619	          y2 = y2m = pj[2];
3620	        } else {
3621
3622	          if (pj[0] == 'C') {
3623	            bez2 = [x2, y2].concat(pj.slice(1));
3624	            x2 = bez2[6];
3625	            y2 = bez2[7];
3626	          } else {
3627	            bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
3628	            x2 = x2m;
3629	            y2 = y2m;
3630	          }
3631
3632	          var intr = findBezierIntersections(bez1, bez2, justCount);
3633
3634	          if (justCount) {
3635	            res += intr;
3636	          } else {
3637
3638	            for (var k = 0, kk = intr.length; k < kk; k++) {
3639	              intr[k].segment1 = i;
3640	              intr[k].segment2 = j;
3641	              intr[k].bez1 = bez1;
3642	              intr[k].bez2 = bez2;
3643	            }
3644
3645	            res = res.concat(intr);
3646	          }
3647	        }
3648	      }
3649	    }
3650	  }
3651
3652	  return res;
3653	}
3654
3655
3656	function pathToAbsolute(pathArray) {
3657	  var pth = paths(pathArray);
3658
3659	  if (pth.abs) {
3660	    return pathClone(pth.abs);
3661	  }
3662
3663	  if (!isArray(pathArray) || !isArray(pathArray && pathArray[0])) { // rough assumption
3664	    pathArray = parsePathString(pathArray);
3665	  }
3666
3667	  if (!pathArray || !pathArray.length) {
3668	    return [['M', 0, 0]];
3669	  }
3670
3671	  var res = [],
3672	      x = 0,
3673	      y = 0,
3674	      mx = 0,
3675	      my = 0,
3676	      start = 0,
3677	      pa0;
3678
3679	  if (pathArray[0][0] == 'M') {
3680	    x = +pathArray[0][1];
3681	    y = +pathArray[0][2];
3682	    mx = x;
3683	    my = y;
3684	    start++;
3685	    res[0] = ['M', x, y];
3686	  }
3687
3688	  for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
3689	    res.push(r = []);
3690	    pa = pathArray[i];
3691	    pa0 = pa[0];
3692
3693	    if (pa0 != pa0.toUpperCase()) {
3694	      r[0] = pa0.toUpperCase();
3695
3696	      switch (r[0]) {
3697	      case 'A':
3698	        r[1] = pa[1];
3699	        r[2] = pa[2];
3700	        r[3] = pa[3];
3701	        r[4] = pa[4];
3702	        r[5] = pa[5];
3703	        r[6] = +pa[6] + x;
3704	        r[7] = +pa[7] + y;
3705	        break;
3706	      case 'V':
3707	        r[1] = +pa[1] + y;
3708	        break;
3709	      case 'H':
3710	        r[1] = +pa[1] + x;
3711	        break;
3712	      case 'M':
3713	        mx = +pa[1] + x;
3714	        my = +pa[2] + y;
3715	      default:
3716	        for (var j = 1, jj = pa.length; j < jj; j++) {
3717	          r[j] = +pa[j] + ((j % 2) ? x : y);
3718	        }
3719	      }
3720	    } else {
3721	      for (var k = 0, kk = pa.length; k < kk; k++) {
3722	        r[k] = pa[k];
3723	      }
3724	    }
3725	    pa0 = pa0.toUpperCase();
3726
3727	    switch (r[0]) {
3728	    case 'Z':
3729	      x = +mx;
3730	      y = +my;
3731	      break;
3732	    case 'H':
3733	      x = r[1];
3734	      break;
3735	    case 'V':
3736	      y = r[1];
3737	      break;
3738	    case 'M':
3739	      mx = r[r.length - 2];
3740	      my = r[r.length - 1];
3741	    default:
3742	      x = r[r.length - 2];
3743	      y = r[r.length - 1];
3744	    }
3745	  }
3746
3747	  res.toString = pathToString;
3748	  pth.abs = pathClone(res);
3749
3750	  return res;
3751	}
3752
3753	function isLine(bez) {
3754	  return (
3755	    bez[0] === bez[2] &&
3756	    bez[1] === bez[3] &&
3757	    bez[4] === bez[6] &&
3758	    bez[5] === bez[7]
3759	  );
3760	}
3761
3762	function lineToCurve(x1, y1, x2, y2) {
3763	  return [
3764	    x1, y1, x2,
3765	    y2, x2, y2
3766	  ];
3767	}
3768
3769	function qubicToCurve(x1, y1, ax, ay, x2, y2) {
3770	  var _13 = 1 / 3,
3771	      _23 = 2 / 3;
3772
3773	  return [
3774	    _13 * x1 + _23 * ax,
3775	    _13 * y1 + _23 * ay,
3776	    _13 * x2 + _23 * ax,
3777	    _13 * y2 + _23 * ay,
3778	    x2,
3779	    y2
3780	  ];
3781	}
3782
3783	function arcToCurve(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
3784
3785	  // for more information of where this math came from visit:
3786	  // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
3787	  var _120 = PI * 120 / 180,
3788	      rad = PI / 180 * (+angle || 0),
3789	      res = [],
3790	      xy,
3791	      rotate = cacher(function(x, y, rad) {
3792	        var X = x * math.cos(rad) - y * math.sin(rad),
3793	            Y = x * math.sin(rad) + y * math.cos(rad);
3794
3795	        return { x: X, y: Y };
3796	      });
3797
3798	  if (!recursive) {
3799	    xy = rotate(x1, y1, -rad);
3800	    x1 = xy.x;
3801	    y1 = xy.y;
3802	    xy = rotate(x2, y2, -rad);
3803	    x2 = xy.x;
3804	    y2 = xy.y;
3805
3806	    var x = (x1 - x2) / 2,
3807	        y = (y1 - y2) / 2;
3808
3809	    var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
3810
3811	    if (h > 1) {
3812	      h = math.sqrt(h);
3813	      rx = h * rx;
3814	      ry = h * ry;
3815	    }
3816
3817	    var rx2 = rx * rx,
3818	        ry2 = ry * ry,
3819	        k = (large_arc_flag == sweep_flag ? -1 : 1) *
3820	            math.sqrt(abs$7((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
3821	        cx = k * rx * y / ry + (x1 + x2) / 2,
3822	        cy = k * -ry * x / rx + (y1 + y2) / 2,
3823	        f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
3824	        f2 = math.asin(((y2 - cy) / ry).toFixed(9));
3825
3826	    f1 = x1 < cx ? PI - f1 : f1;
3827	    f2 = x2 < cx ? PI - f2 : f2;
3828	    f1 < 0 && (f1 = PI * 2 + f1);
3829	    f2 < 0 && (f2 = PI * 2 + f2);
3830
3831	    if (sweep_flag && f1 > f2) {
3832	      f1 = f1 - PI * 2;
3833	    }
3834	    if (!sweep_flag && f2 > f1) {
3835	      f2 = f2 - PI * 2;
3836	    }
3837	  } else {
3838	    f1 = recursive[0];
3839	    f2 = recursive[1];
3840	    cx = recursive[2];
3841	    cy = recursive[3];
3842	  }
3843
3844	  var df = f2 - f1;
3845
3846	  if (abs$7(df) > _120) {
3847	    var f2old = f2,
3848	        x2old = x2,
3849	        y2old = y2;
3850
3851	    f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
3852	    x2 = cx + rx * math.cos(f2);
3853	    y2 = cy + ry * math.sin(f2);
3854	    res = arcToCurve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
3855	  }
3856
3857	  df = f2 - f1;
3858
3859	  var c1 = math.cos(f1),
3860	      s1 = math.sin(f1),
3861	      c2 = math.cos(f2),
3862	      s2 = math.sin(f2),
3863	      t = math.tan(df / 4),
3864	      hx = 4 / 3 * rx * t,
3865	      hy = 4 / 3 * ry * t,
3866	      m1 = [x1, y1],
3867	      m2 = [x1 + hx * s1, y1 - hy * c1],
3868	      m3 = [x2 + hx * s2, y2 - hy * c2],
3869	      m4 = [x2, y2];
3870
3871	  m2[0] = 2 * m1[0] - m2[0];
3872	  m2[1] = 2 * m1[1] - m2[1];
3873
3874	  if (recursive) {
3875	    return [m2, m3, m4].concat(res);
3876	  } else {
3877	    res = [m2, m3, m4].concat(res).join().split(',');
3878	    var newres = [];
3879
3880	    for (var i = 0, ii = res.length; i < ii; i++) {
3881	      newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
3882	    }
3883
3884	    return newres;
3885	  }
3886	}
3887
3888	// Returns bounding box of cubic bezier curve.
3889	// Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
3890	// Original version: NISHIO Hirokazu
3891	// Modifications: https://github.com/timo22345
3892	function curveBBox(x0, y0, x1, y1, x2, y2, x3, y3) {
3893	  var tvalues = [],
3894	      bounds = [[], []],
3895	      a, b, c, t, t1, t2, b2ac, sqrtb2ac;
3896
3897	  for (var i = 0; i < 2; ++i) {
3898
3899	    if (i == 0) {
3900	      b = 6 * x0 - 12 * x1 + 6 * x2;
3901	      a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
3902	      c = 3 * x1 - 3 * x0;
3903	    } else {
3904	      b = 6 * y0 - 12 * y1 + 6 * y2;
3905	      a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
3906	      c = 3 * y1 - 3 * y0;
3907	    }
3908
3909	    if (abs$7(a) < 1e-12) {
3910
3911	      if (abs$7(b) < 1e-12) {
3912	        continue;
3913	      }
3914
3915	      t = -c / b;
3916
3917	      if (0 < t && t < 1) {
3918	        tvalues.push(t);
3919	      }
3920
3921	      continue;
3922	    }
3923
3924	    b2ac = b * b - 4 * c * a;
3925	    sqrtb2ac = math.sqrt(b2ac);
3926
3927	    if (b2ac < 0) {
3928	      continue;
3929	    }
3930
3931	    t1 = (-b + sqrtb2ac) / (2 * a);
3932
3933	    if (0 < t1 && t1 < 1) {
3934	      tvalues.push(t1);
3935	    }
3936
3937	    t2 = (-b - sqrtb2ac) / (2 * a);
3938
3939	    if (0 < t2 && t2 < 1) {
3940	      tvalues.push(t2);
3941	    }
3942	  }
3943
3944	  var j = tvalues.length,
3945	      jlen = j,
3946	      mt;
3947
3948	  while (j--) {
3949	    t = tvalues[j];
3950	    mt = 1 - t;
3951	    bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
3952	    bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
3953	  }
3954
3955	  bounds[0][jlen] = x0;
3956	  bounds[1][jlen] = y0;
3957	  bounds[0][jlen + 1] = x3;
3958	  bounds[1][jlen + 1] = y3;
3959	  bounds[0].length = bounds[1].length = jlen + 2;
3960
3961	  return {
3962	    x0: mmin.apply(0, bounds[0]),
3963	    y0: mmin.apply(0, bounds[1]),
3964	    x1: mmax.apply(0, bounds[0]),
3965	    y1: mmax.apply(0, bounds[1])
3966	  };
3967	}
3968
3969	function pathToCurve(path) {
3970
3971	  var pth = paths(path);
3972
3973	  // return cached curve, if existing
3974	  if (pth.curve) {
3975	    return pathClone(pth.curve);
3976	  }
3977
3978	  var curvedPath = pathToAbsolute(path),
3979	      attrs = { x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null },
3980	      processPath = function(path, d, pathCommand) {
3981	        var nx, ny;
3982
3983	        if (!path) {
3984	          return ['C', d.x, d.y, d.x, d.y, d.x, d.y];
3985	        }
3986
3987	        !(path[0] in { T: 1, Q: 1 }) && (d.qx = d.qy = null);
3988
3989	        switch (path[0]) {
3990	        case 'M':
3991	          d.X = path[1];
3992	          d.Y = path[2];
3993	          break;
3994	        case 'A':
3995	          path = ['C'].concat(arcToCurve.apply(0, [d.x, d.y].concat(path.slice(1))));
3996	          break;
3997	        case 'S':
3998	          if (pathCommand == 'C' || pathCommand == 'S') {
3999
4000	            // In 'S' case we have to take into account, if the previous command is C/S.
4001	            nx = d.x * 2 - d.bx;
4002
4003	            // And reflect the previous
4004	            ny = d.y * 2 - d.by;
4005
4006	            // command's control point relative to the current point.
4007	          }
4008	          else {
4009
4010	            // or some else or nothing
4011	            nx = d.x;
4012	            ny = d.y;
4013	          }
4014	          path = ['C', nx, ny].concat(path.slice(1));
4015	          break;
4016	        case 'T':
4017	          if (pathCommand == 'Q' || pathCommand == 'T') {
4018
4019	            // In 'T' case we have to take into account, if the previous command is Q/T.
4020	            d.qx = d.x * 2 - d.qx;
4021
4022	            // And make a reflection similar
4023	            d.qy = d.y * 2 - d.qy;
4024
4025	            // to case 'S'.
4026	          }
4027	          else {
4028
4029	            // or something else or nothing
4030	            d.qx = d.x;
4031	            d.qy = d.y;
4032	          }
4033	          path = ['C'].concat(qubicToCurve(d.x, d.y, d.qx, d.qy, path[1], path[2]));
4034	          break;
4035	        case 'Q':
4036	          d.qx = path[1];
4037	          d.qy = path[2];
4038	          path = ['C'].concat(qubicToCurve(d.x, d.y, path[1], path[2], path[3], path[4]));
4039	          break;
4040	        case 'L':
4041	          path = ['C'].concat(lineToCurve(d.x, d.y, path[1], path[2]));
4042	          break;
4043	        case 'H':
4044	          path = ['C'].concat(lineToCurve(d.x, d.y, path[1], d.y));
4045	          break;
4046	        case 'V':
4047	          path = ['C'].concat(lineToCurve(d.x, d.y, d.x, path[1]));
4048	          break;
4049	        case 'Z':
4050	          path = ['C'].concat(lineToCurve(d.x, d.y, d.X, d.Y));
4051	          break;
4052	        }
4053
4054	        return path;
4055	      },
4056
4057	      fixArc = function(pp, i) {
4058
4059	        if (pp[i].length > 7) {
4060	          pp[i].shift();
4061	          var pi = pp[i];
4062
4063	          while (pi.length) {
4064	            pathCommands[i] = 'A'; // if created multiple C:s, their original seg is saved
4065	            pp.splice(i++, 0, ['C'].concat(pi.splice(0, 6)));
4066	          }
4067
4068	          pp.splice(i, 1);
4069	          ii = curvedPath.length;
4070	        }
4071	      },
4072
4073	      pathCommands = [], // path commands of original path p
4074	      pfirst = '', // temporary holder for original path command
4075	      pathCommand = ''; // holder for previous path command of original path
4076
4077	  for (var i = 0, ii = curvedPath.length; i < ii; i++) {
4078	    curvedPath[i] && (pfirst = curvedPath[i][0]); // save current path command
4079
4080	    if (pfirst != 'C') // C is not saved yet, because it may be result of conversion
4081	    {
4082	      pathCommands[i] = pfirst; // Save current path command
4083	      i && (pathCommand = pathCommands[i - 1]); // Get previous path command pathCommand
4084	    }
4085	    curvedPath[i] = processPath(curvedPath[i], attrs, pathCommand); // Previous path command is inputted to processPath
4086
4087	    if (pathCommands[i] != 'A' && pfirst == 'C') pathCommands[i] = 'C'; // A is the only command
4088	    // which may produce multiple C:s
4089	    // so we have to make sure that C is also C in original path
4090
4091	    fixArc(curvedPath, i); // fixArc adds also the right amount of A:s to pathCommands
4092
4093	    var seg = curvedPath[i],
4094	        seglen = seg.length;
4095
4096	    attrs.x = seg[seglen - 2];
4097	    attrs.y = seg[seglen - 1];
4098	    attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
4099	    attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
4100	  }
4101
4102	  // cache curve
4103	  pth.curve = pathClone(curvedPath);
4104
4105	  return curvedPath;
4106	}
4107
4108	var intersect = findPathIntersections;
4109
4110	function roundBounds(bounds) {
4111	  return {
4112	    x: Math.round(bounds.x),
4113	    y: Math.round(bounds.y),
4114	    width: Math.round(bounds.width),
4115	    height: Math.round(bounds.height)
4116	  };
4117	}
4118
4119
4120	function roundPoint(point) {
4121
4122	  return {
4123	    x: Math.round(point.x),
4124	    y: Math.round(point.y)
4125	  };
4126	}
4127
4128
4129	/**
4130	 * Convert the given bounds to a { top, left, bottom, right } descriptor.
4131	 *
4132	 * @param {Bounds|Point} bounds
4133	 *
4134	 * @return {Object}
4135	 */
4136	function asTRBL(bounds) {
4137	  return {
4138	    top: bounds.y,
4139	    right: bounds.x + (bounds.width || 0),
4140	    bottom: bounds.y + (bounds.height || 0),
4141	    left: bounds.x
4142	  };
4143	}
4144
4145
4146	/**
4147	 * Convert a { top, left, bottom, right } to an objects bounds.
4148	 *
4149	 * @param {Object} trbl
4150	 *
4151	 * @return {Bounds}
4152	 */
4153	function asBounds(trbl) {
4154	  return {
4155	    x: trbl.left,
4156	    y: trbl.top,
4157	    width: trbl.right - trbl.left,
4158	    height: trbl.bottom - trbl.top
4159	  };
4160	}
4161
4162
4163	/**
4164	 * Get the mid of the given bounds or point.
4165	 *
4166	 * @param {Bounds|Point} bounds
4167	 *
4168	 * @return {Point}
4169	 */
4170	function getMid(bounds) {
4171	  return roundPoint({
4172	    x: bounds.x + (bounds.width || 0) / 2,
4173	    y: bounds.y + (bounds.height || 0) / 2
4174	  });
4175	}
4176
4177
4178	// orientation utils //////////////////////
4179
4180	/**
4181	 * Get orientation of the given rectangle with respect to
4182	 * the reference rectangle.
4183	 *
4184	 * A padding (positive or negative) may be passed to influence
4185	 * horizontal / vertical orientation and intersection.
4186	 *
4187	 * @param {Bounds} rect
4188	 * @param {Bounds} reference
4189	 * @param {Point|number} padding
4190	 *
4191	 * @return {string} the orientation; one of top, top-left, left, ..., bottom, right or intersect.
4192	 */
4193	function getOrientation(rect, reference, padding) {
4194
4195	  padding = padding || 0;
4196
4197	  // make sure we can use an object, too
4198	  // for individual { x, y } padding
4199	  if (!isObject(padding)) {
4200	    padding = { x: padding, y: padding };
4201	  }
4202
4203
4204	  var rectOrientation = asTRBL(rect),
4205	      referenceOrientation = asTRBL(reference);
4206
4207	  var top = rectOrientation.bottom + padding.y <= referenceOrientation.top,
4208	      right = rectOrientation.left - padding.x >= referenceOrientation.right,
4209	      bottom = rectOrientation.top - padding.y >= referenceOrientation.bottom,
4210	      left = rectOrientation.right + padding.x <= referenceOrientation.left;
4211
4212	  var vertical = top ? 'top' : (bottom ? 'bottom' : null),
4213	      horizontal = left ? 'left' : (right ? 'right' : null);
4214
4215	  if (horizontal && vertical) {
4216	    return vertical + '-' + horizontal;
4217	  } else {
4218	    return horizontal || vertical || 'intersect';
4219	  }
4220	}
4221
4222
4223	// intersection utils //////////////////////
4224
4225	/**
4226	 * Get intersection between an element and a line path.
4227	 *
4228	 * @param {PathDef} elementPath
4229	 * @param {PathDef} linePath
4230	 * @param {boolean} cropStart crop from start or end
4231	 *
4232	 * @return {Point}
4233	 */
4234	function getElementLineIntersection(elementPath, linePath, cropStart) {
4235
4236	  var intersections = getIntersections(elementPath, linePath);
4237
4238	  // recognize intersections
4239	  // only one -> choose
4240	  // two close together -> choose first
4241	  // two or more distinct -> pull out appropriate one
4242	  // none -> ok (fallback to point itself)
4243	  if (intersections.length === 1) {
4244	    return roundPoint(intersections[0]);
4245	  } else if (intersections.length === 2 && pointDistance(intersections[0], intersections[1]) < 1) {
4246	    return roundPoint(intersections[0]);
4247	  } else if (intersections.length > 1) {
4248
4249	    // sort by intersections based on connection segment +
4250	    // distance from start
4251	    intersections = sortBy(intersections, function(i) {
4252	      var distance = Math.floor(i.t2 * 100) || 1;
4253
4254	      distance = 100 - distance;
4255
4256	      distance = (distance < 10 ? '0' : '') + distance;
4257
4258	      // create a sort string that makes sure we sort
4259	      // line segment ASC + line segment position DESC (for cropStart)
4260	      // line segment ASC + line segment position ASC (for cropEnd)
4261	      return i.segment2 + '#' + distance;
4262	    });
4263
4264	    return roundPoint(intersections[cropStart ? 0 : intersections.length - 1]);
4265	  }
4266
4267	  return null;
4268	}
4269
4270
4271	function getIntersections(a, b) {
4272	  return intersect(a, b);
4273	}
4274
4275
4276	function filterRedundantWaypoints(waypoints) {
4277
4278	  // alter copy of waypoints, not original
4279	  waypoints = waypoints.slice();
4280
4281	  var idx = 0,
4282	      point,
4283	      previousPoint,
4284	      nextPoint;
4285
4286	  while (waypoints[idx]) {
4287	    point = waypoints[idx];
4288	    previousPoint = waypoints[idx - 1];
4289	    nextPoint = waypoints[idx + 1];
4290
4291	    if (pointDistance(point, nextPoint) === 0 ||
4292	        pointsOnLine(previousPoint, nextPoint, point)) {
4293
4294	      // remove point, if overlapping with {nextPoint}
4295	      // or on line with {previousPoint} -> {point} -> {nextPoint}
4296	      waypoints.splice(idx, 1);
4297	    } else {
4298	      idx++;
4299	    }
4300	  }
4301
4302	  return waypoints;
4303	}
4304
4305	function round$b(number, resolution) {
4306	  return Math.round(number * resolution) / resolution;
4307	}
4308
4309	function ensurePx(number) {
4310	  return isNumber(number) ? number + 'px' : number;
4311	}
4312
4313	function findRoot(element) {
4314	  while (element.parent) {
4315	    element = element.parent;
4316	  }
4317
4318	  return element;
4319	}
4320
4321	/**
4322	 * Creates a HTML container element for a SVG element with
4323	 * the given configuration
4324	 *
4325	 * @param  {Object} options
4326	 * @return {HTMLElement} the container element
4327	 */
4328	function createContainer(options) {
4329
4330	  options = assign({}, { width: '100%', height: '100%' }, options);
4331
4332	  var container = options.container || document.body;
4333
4334	  // create a <div> around the svg element with the respective size
4335	  // this way we can always get the correct container size
4336	  // (this is impossible for <svg> elements at the moment)
4337	  var parent = document.createElement('div');
4338	  parent.setAttribute('class', 'djs-container');
4339
4340	  assign(parent.style, {
4341	    position: 'relative',
4342	    overflow: 'hidden',
4343	    width: ensurePx(options.width),
4344	    height: ensurePx(options.height)
4345	  });
4346
4347	  container.appendChild(parent);
4348
4349	  return parent;
4350	}
4351
4352	function createGroup(parent, cls, childIndex) {
4353	  var group = create$1('g');
4354	  classes(group).add(cls);
4355
4356	  var index = childIndex !== undefined ? childIndex : parent.childNodes.length - 1;
4357
4358	  // must ensure second argument is node or _null_
4359	  // cf. https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
4360	  parent.insertBefore(group, parent.childNodes[index] || null);
4361
4362	  return group;
4363	}
4364
4365	var BASE_LAYER = 'base';
4366	var HIDDEN_MARKER = 'djs-element-hidden';
4367
4368
4369	var REQUIRED_MODEL_ATTRS = {
4370	  shape: [ 'x', 'y', 'width', 'height' ],
4371	  connection: [ 'waypoints' ]
4372	};
4373
4374	/**
4375	 * The main drawing canvas.
4376	 *
4377	 * @class
4378	 * @constructor
4379	 *
4380	 * @emits Canvas#canvas.init
4381	 *
4382	 * @param {Object} config
4383	 * @param {EventBus} eventBus
4384	 * @param {GraphicsFactory} graphicsFactory
4385	 * @param {ElementRegistry} elementRegistry
4386	 */
4387	function Canvas(config, eventBus, graphicsFactory, elementRegistry) {
4388
4389	  this._eventBus = eventBus;
4390	  this._elementRegistry = elementRegistry;
4391	  this._graphicsFactory = graphicsFactory;
4392
4393	  this._init(config || {});
4394	}
4395
4396	Canvas.$inject = [
4397	  'config.canvas',
4398	  'eventBus',
4399	  'graphicsFactory',
4400	  'elementRegistry'
4401	];
4402
4403	/**
4404	 * Creates a <svg> element that is wrapped into a <div>.
4405	 * This way we are always able to correctly figure out the size of the svg element
4406	 * by querying the parent node.
4407
4408	 * (It is not possible to get the size of a svg element cross browser @ 2014-04-01)
4409
4410	 * <div class="djs-container" style="width: {desired-width}, height: {desired-height}">
4411	 *   <svg width="100%" height="100%">
4412	 *    ...
4413	 *   </svg>
4414	 * </div>
4415	 */
4416	Canvas.prototype._init = function(config) {
4417
4418	  var eventBus = this._eventBus;
4419
4420	  // html container
4421	  var container = this._container = createContainer(config);
4422
4423	  var svg = this._svg = create$1('svg');
4424	  attr(svg, { width: '100%', height: '100%' });
4425
4426	  append(container, svg);
4427
4428	  var viewport = this._viewport = createGroup(svg, 'viewport');
4429
4430	  this._layers = {};
4431	  this._planes = {};
4432
4433	  // debounce canvas.viewbox.changed events
4434	  // for smoother diagram interaction
4435	  if (config.deferUpdate !== false) {
4436	    this._viewboxChanged = debounce(bind$2(this._viewboxChanged, this), 300);
4437	  }
4438
4439	  eventBus.on('diagram.init', function() {
4440
4441	    /**
4442	     * An event indicating that the canvas is ready to be drawn on.
4443	     *
4444	     * @memberOf Canvas
4445	     *
4446	     * @event canvas.init
4447	     *
4448	     * @type {Object}
4449	     * @property {SVGElement} svg the created svg element
4450	     * @property {SVGElement} viewport the direct parent of diagram elements and shapes
4451	     */
4452	    eventBus.fire('canvas.init', {
4453	      svg: svg,
4454	      viewport: viewport
4455	    });
4456
4457	  }, this);
4458
4459	  // reset viewbox on shape changes to
4460	  // recompute the viewbox
4461	  eventBus.on([
4462	    'shape.added',
4463	    'connection.added',
4464	    'shape.removed',
4465	    'connection.removed',
4466	    'elements.changed'
4467	  ], function() {
4468	    delete this._cachedViewbox;
4469	  }, this);
4470
4471	  eventBus.on('diagram.destroy', 500, this._destroy, this);
4472	  eventBus.on('diagram.clear', 500, this._clear, this);
4473	};
4474
4475	Canvas.prototype._destroy = function(emit) {
4476	  this._eventBus.fire('canvas.destroy', {
4477	    svg: this._svg,
4478	    viewport: this._viewport
4479	  });
4480
4481	  var parent = this._container.parentNode;
4482
4483	  if (parent) {
4484	    parent.removeChild(this._container);
4485	  }
4486
4487	  delete this._svg;
4488	  delete this._container;
4489	  delete this._layers;
4490	  delete this._planes;
4491	  delete this._activePlane;
4492	  delete this._viewport;
4493	};
4494
4495	Canvas.prototype._clear = function() {
4496
4497	  var self = this;
4498
4499	  var allElements = this._elementRegistry.getAll();
4500
4501	  // remove all elements
4502	  allElements.forEach(function(element) {
4503	    var type = getType(element);
4504
4505	    if (type === 'root') {
4506	      self.setRootElementForPlane(null, self.findPlane(element), true);
4507	    } else {
4508	      self._removeElement(element, type);
4509	    }
4510	  });
4511
4512	  // remove all planes
4513	  this._activePlane = null;
4514	  this._planes = {};
4515
4516	  // force recomputation of view box
4517	  delete this._cachedViewbox;
4518	};
4519
4520	/**
4521	 * Returns the default layer on which
4522	 * all elements are drawn.
4523	 *
4524	 * @returns {SVGElement}
4525	 */
4526	Canvas.prototype.getDefaultLayer = function() {
4527	  return this.getLayer(BASE_LAYER);
4528	};
4529
4530	/**
4531	 * Returns a layer that is used to draw elements
4532	 * or annotations on it.
4533	 *
4534	 * Non-existing layers retrieved through this method
4535	 * will be created. During creation, the optional index
4536	 * may be used to create layers below or above existing layers.
4537	 * A layer with a certain index is always created above all
4538	 * existing layers with the same index.
4539	 *
4540	 * @param {string} name
4541	 * @param {number} index
4542	 *
4543	 * @returns {SVGElement}
4544	 */
4545	Canvas.prototype.getLayer = function(name, index) {
4546
4547	  if (!name) {
4548	    throw new Error('must specify a name');
4549	  }
4550
4551	  var layer = this._layers[name];
4552
4553	  if (!layer) {
4554	    layer = this._layers[name] = this._createLayer(name, index);
4555	  }
4556
4557	  // throw an error if layer creation / retrival is
4558	  // requested on different index
4559	  if (typeof index !== 'undefined' && layer.index !== index) {
4560	    throw new Error('layer <' + name + '> already created at index <' + index + '>');
4561	  }
4562
4563	  return layer.group;
4564	};
4565
4566	/**
4567	 * Creates a given layer and returns it.
4568	 *
4569	 * @param {string} name
4570	 * @param {number} [index=0]
4571	 *
4572	 * @return {Object} layer descriptor with { index, group: SVGGroup }
4573	 */
4574	Canvas.prototype._createLayer = function(name, index) {
4575
4576	  if (!index) {
4577	    index = 0;
4578	  }
4579
4580	  var childIndex = reduce(this._layers, function(childIndex, layer) {
4581	    if (index >= layer.index) {
4582	      childIndex++;
4583	    }
4584
4585	    return childIndex;
4586	  }, 0);
4587
4588	  return {
4589	    group: createGroup(this._viewport, 'layer-' + name, childIndex),
4590	    index: index
4591	  };
4592
4593	};
4594
4595	/**
4596	 * Returns a plane that is used to draw elements on it.
4597	 *
4598	 * @param {string} name
4599	 *
4600	 * @return {Object} plane descriptor with { layer, rootElement, name }
4601	 */
4602	Canvas.prototype.getPlane = function(name) {
4603	  if (!name) {
4604	    throw new Error('must specify a name');
4605	  }
4606
4607	  var plane = this._planes[name];
4608
4609	  return plane;
4610	};
4611
4612	/**
4613	 * Creates a plane that is used to draw elements on it. If no
4614	 * root element is provided, an implicit root will be used.
4615	 *
4616	 * @param {string} name
4617	 * @param {Object|djs.model.Root} [rootElement] optional root element
4618	 *
4619	 * @return {Object} plane descriptor with { layer, rootElement, name }
4620	 */
4621	Canvas.prototype.createPlane = function(name, rootElement) {
4622	  if (!name) {
4623	    throw new Error('must specify a name');
4624	  }
4625
4626	  if (this._planes[name]) {
4627	    throw new Error('plane ' + name + ' already exists');
4628	  }
4629
4630	  if (!rootElement) {
4631	    rootElement = {
4632	      id: '__implicitroot' + name,
4633	      children: [],
4634	      isImplicit: true
4635	    };
4636	  }
4637
4638	  var svgLayer = this.getLayer(name);
4639	  classes(svgLayer).add(HIDDEN_MARKER);
4640
4641	  var plane = this._planes[name] = {
4642	    layer: svgLayer,
4643	    name: name,
4644	    rootElement: null
4645	  };
4646
4647	  this.setRootElementForPlane(rootElement, plane);
4648
4649	  return plane;
4650	};
4651
4652	/**
4653	 * Sets the active plane and hides the previously active plane.
4654	 *
4655	 * @param {string|Object} plane
4656	 *
4657	 * @return {Object} plane descriptor with { layer, rootElement, name }
4658	 */
4659	Canvas.prototype.setActivePlane = function(plane) {
4660	  if (!plane) {
4661	    throw new Error('must specify a plane');
4662	  }
4663
4664	  if (typeof plane === 'string') {
4665	    plane = this.getPlane(plane);
4666	  }
4667
4668	  // hide previous Plane
4669	  if (this._activePlane) {
4670	    classes(this._activePlane.layer).add(HIDDEN_MARKER);
4671	  }
4672
4673	  this._activePlane = plane;
4674
4675	  // show current Plane
4676	  classes(plane.layer).remove(HIDDEN_MARKER);
4677
4678	  if (plane.rootElement) {
4679	    this._elementRegistry.updateGraphics(plane.rootElement, this._svg, true);
4680	  }
4681
4682	  this._eventBus.fire('plane.set', { plane: plane });
4683
4684	  return plane;
4685	};
4686
4687	/**
4688	 * Returns the currently active layer
4689	 *
4690	 * @returns {SVGElement}
4691	 */
4692
4693	Canvas.prototype.getActiveLayer = function() {
4694	  return this.getActivePlane().layer;
4695	};
4696
4697	/**
4698	 * Returns the currently active plane.
4699	 *
4700	 * @return {Object} plane descriptor with { layer, rootElement, name }
4701	 */
4702	Canvas.prototype.getActivePlane = function() {
4703	  var plane = this._activePlane;
4704	  if (!plane) {
4705	    plane = this.createPlane(BASE_LAYER);
4706	    this.setActivePlane(BASE_LAYER);
4707	  }
4708
4709	  return plane;
4710	};
4711
4712	/**
4713	 * Returns the plane which contains the given element.
4714	 *
4715	 * @param {string|djs.model.Base} element
4716	 *
4717	 * @return {Object} plane descriptor with { layer, rootElement, name }
4718	 */
4719	Canvas.prototype.findPlane = function(element) {
4720	  if (typeof element === 'string') {
4721	    element = this._elementRegistry.get(element);
4722	  }
4723
4724	  var root = findRoot(element);
4725
4726	  return find(this._planes, function(plane) {
4727	    return plane.rootElement === root;
4728	  });
4729	};
4730
4731	/**
4732	 * Returns the html element that encloses the
4733	 * drawing canvas.
4734	 *
4735	 * @return {DOMNode}
4736	 */
4737	Canvas.prototype.getContainer = function() {
4738	  return this._container;
4739	};
4740
4741
4742	// markers //////////////////////
4743
4744	Canvas.prototype._updateMarker = function(element, marker, add) {
4745	  var container;
4746
4747	  if (!element.id) {
4748	    element = this._elementRegistry.get(element);
4749	  }
4750
4751	  // we need to access all
4752	  container = this._elementRegistry._elements[element.id];
4753
4754	  if (!container) {
4755	    return;
4756	  }
4757
4758	  forEach([ container.gfx, container.secondaryGfx ], function(gfx) {
4759	    if (gfx) {
4760
4761	      // invoke either addClass or removeClass based on mode
4762	      if (add) {
4763	        classes(gfx).add(marker);
4764	      } else {
4765	        classes(gfx).remove(marker);
4766	      }
4767	    }
4768	  });
4769
4770	  /**
4771	   * An event indicating that a marker has been updated for an element
4772	   *
4773	   * @event element.marker.update
4774	   * @type {Object}
4775	   * @property {djs.model.Element} element the shape
4776	   * @property {Object} gfx the graphical representation of the shape
4777	   * @property {string} marker
4778	   * @property {boolean} add true if the marker was added, false if it got removed
4779	   */
4780	  this._eventBus.fire('element.marker.update', { element: element, gfx: container.gfx, marker: marker, add: !!add });
4781	};
4782
4783
4784	/**
4785	 * Adds a marker to an element (basically a css class).
4786	 *
4787	 * Fires the element.marker.update event, making it possible to
4788	 * integrate extension into the marker life-cycle, too.
4789	 *
4790	 * @example
4791	 * canvas.addMarker('foo', 'some-marker');
4792	 *
4793	 * var fooGfx = canvas.getGraphics('foo');
4794	 *
4795	 * fooGfx; // <g class="... some-marker"> ... </g>
4796	 *
4797	 * @param {string|djs.model.Base} element
4798	 * @param {string} marker
4799	 */
4800	Canvas.prototype.addMarker = function(element, marker) {
4801	  this._updateMarker(element, marker, true);
4802	};
4803
4804
4805	/**
4806	 * Remove a marker from an element.
4807	 *
4808	 * Fires the element.marker.update event, making it possible to
4809	 * integrate extension into the marker life-cycle, too.
4810	 *
4811	 * @param  {string|djs.model.Base} element
4812	 * @param  {string} marker
4813	 */
4814	Canvas.prototype.removeMarker = function(element, marker) {
4815	  this._updateMarker(element, marker, false);
4816	};
4817
4818	/**
4819	 * Check the existence of a marker on element.
4820	 *
4821	 * @param  {string|djs.model.Base} element
4822	 * @param  {string} marker
4823	 */
4824	Canvas.prototype.hasMarker = function(element, marker) {
4825	  if (!element.id) {
4826	    element = this._elementRegistry.get(element);
4827	  }
4828
4829	  var gfx = this.getGraphics(element);
4830
4831	  return classes(gfx).has(marker);
4832	};
4833
4834	/**
4835	 * Toggles a marker on an element.
4836	 *
4837	 * Fires the element.marker.update event, making it possible to
4838	 * integrate extension into the marker life-cycle, too.
4839	 *
4840	 * @param  {string|djs.model.Base} element
4841	 * @param  {string} marker
4842	 */
4843	Canvas.prototype.toggleMarker = function(element, marker) {
4844	  if (this.hasMarker(element, marker)) {
4845	    this.removeMarker(element, marker);
4846	  } else {
4847	    this.addMarker(element, marker);
4848	  }
4849	};
4850
4851	Canvas.prototype.getRootElement = function() {
4852	  var plane = this.getActivePlane();
4853
4854	  return plane.rootElement;
4855	};
4856
4857
4858
4859	// root element handling //////////////////////
4860
4861	/**
4862	 * Sets a given element as the new root element for the canvas
4863	 * and returns the new root element.
4864	 *
4865	 * @param {Object|djs.model.Root} element
4866	 * @param {boolean} [override] whether to override the current root element, if any
4867	 *
4868	 * @return {Object|djs.model.Root} new root element
4869	 */
4870	Canvas.prototype.setRootElement = function(element, override) {
4871	  var activePlane = this._activePlane;
4872
4873	  if (activePlane) {
4874	    return this.setRootElementForPlane(element, activePlane, override);
4875	  } else {
4876	    var basePlane = this.createPlane(BASE_LAYER, element);
4877
4878	    this.setActivePlane(basePlane);
4879
4880	    return basePlane.rootElement;
4881	  }
4882	};
4883
4884
4885	/**
4886	 * Sets a given element as the new root element for the canvas
4887	 * and returns the new root element.
4888	 *
4889	 * @param {Object|djs.model.Root} element
4890	 * @param {Object|djs.model.Root} plane
4891	 * @param {boolean} [override] whether to override the current root element, if any
4892	 *
4893	 * @return {Object|djs.model.Root} new root element
4894	 */
4895	Canvas.prototype.setRootElementForPlane = function(element, plane, override) {
4896
4897	  if (typeof plane === 'string') {
4898	    plane = this.getPlane(plane);
4899	  }
4900
4901	  if (element) {
4902	    this._ensureValid('root', element);
4903	  }
4904
4905	  var currentRoot = plane.rootElement,
4906	      elementRegistry = this._elementRegistry,
4907	      eventBus = this._eventBus;
4908
4909	  if (currentRoot) {
4910	    if (!override) {
4911	      throw new Error('rootElement already set, need to specify override');
4912	    }
4913
4914	    // simulate element remove event sequence
4915	    eventBus.fire('root.remove', { element: currentRoot });
4916	    eventBus.fire('root.removed', { element: currentRoot });
4917
4918	    elementRegistry.remove(currentRoot);
4919	  }
4920
4921	  if (element) {
4922	    var gfx = plane.layer;
4923
4924	    // resemble element add event sequence
4925	    eventBus.fire('root.add', { element: element });
4926
4927	    elementRegistry.add(element, gfx);
4928
4929	    eventBus.fire('root.added', { element: element, gfx: gfx });
4930
4931	    // associate SVG with root element when active
4932	    if (plane === this._activePlane) {
4933	      this._elementRegistry.updateGraphics(element, this._svg, true);
4934	    }
4935	  }
4936
4937	  plane.rootElement = element;
4938
4939	  return element;
4940	};
4941
4942	// add functionality //////////////////////
4943
4944	Canvas.prototype._ensureValid = function(type, element) {
4945	  if (!element.id) {
4946	    throw new Error('element must have an id');
4947	  }
4948
4949	  if (this._elementRegistry.get(element.id)) {
4950	    throw new Error('element with id ' + element.id + ' already exists');
4951	  }
4952
4953	  var requiredAttrs = REQUIRED_MODEL_ATTRS[type];
4954
4955	  var valid = every(requiredAttrs, function(attr) {
4956	    return typeof element[attr] !== 'undefined';
4957	  });
4958
4959	  if (!valid) {
4960	    throw new Error(
4961	      'must supply { ' + requiredAttrs.join(', ') + ' } with ' + type);
4962	  }
4963	};
4964
4965	Canvas.prototype._setParent = function(element, parent, parentIndex) {
4966	  add(parent.children, element, parentIndex);
4967	  element.parent = parent;
4968	};
4969
4970	/**
4971	 * Adds an element to the canvas.
4972	 *
4973	 * This wires the parent <-> child relationship between the element and
4974	 * a explicitly specified parent or an implicit root element.
4975	 *
4976	 * During add it emits the events
4977	 *
4978	 *  * <{type}.add> (element, parent)
4979	 *  * <{type}.added> (element, gfx)
4980	 *
4981	 * Extensions may hook into these events to perform their magic.
4982	 *
4983	 * @param {string} type
4984	 * @param {Object|djs.model.Base} element
4985	 * @param {Object|djs.model.Base} [parent]
4986	 * @param {number} [parentIndex]
4987	 *
4988	 * @return {Object|djs.model.Base} the added element
4989	 */
4990	Canvas.prototype._addElement = function(type, element, parent, parentIndex) {
4991
4992	  parent = parent || this.getRootElement();
4993
4994	  var eventBus = this._eventBus,
4995	      graphicsFactory = this._graphicsFactory;
4996
4997	  this._ensureValid(type, element);
4998
4999	  eventBus.fire(type + '.add', { element: element, parent: parent });
5000
5001	  this._setParent(element, parent, parentIndex);
5002
5003	  // create graphics
5004	  var gfx = graphicsFactory.create(type, element, parentIndex);
5005
5006	  this._elementRegistry.add(element, gfx);
5007
5008	  // update its visual
5009	  graphicsFactory.update(type, element, gfx);
5010
5011	  eventBus.fire(type + '.added', { element: element, gfx: gfx });
5012
5013	  return element;
5014	};
5015
5016	/**
5017	 * Adds a shape to the canvas
5018	 *
5019	 * @param {Object|djs.model.Shape} shape to add to the diagram
5020	 * @param {djs.model.Base} [parent]
5021	 * @param {number} [parentIndex]
5022	 *
5023	 * @return {djs.model.Shape} the added shape
5024	 */
5025	Canvas.prototype.addShape = function(shape, parent, parentIndex) {
5026	  return this._addElement('shape', shape, parent, parentIndex);
5027	};
5028
5029	/**
5030	 * Adds a connection to the canvas
5031	 *
5032	 * @param {Object|djs.model.Connection} connection to add to the diagram
5033	 * @param {djs.model.Base} [parent]
5034	 * @param {number} [parentIndex]
5035	 *
5036	 * @return {djs.model.Connection} the added connection
5037	 */
5038	Canvas.prototype.addConnection = function(connection, parent, parentIndex) {
5039	  return this._addElement('connection', connection, parent, parentIndex);
5040	};
5041
5042
5043	/**
5044	 * Internal remove element
5045	 */
5046	Canvas.prototype._removeElement = function(element, type) {
5047
5048	  var elementRegistry = this._elementRegistry,
5049	      graphicsFactory = this._graphicsFactory,
5050	      eventBus = this._eventBus;
5051
5052	  element = elementRegistry.get(element.id || element);
5053
5054	  if (!element) {
5055
5056	    // element was removed already
5057	    return;
5058	  }
5059
5060	  eventBus.fire(type + '.remove', { element: element });
5061
5062	  graphicsFactory.remove(element);
5063
5064	  // unset parent <-> child relationship
5065	  remove(element.parent && element.parent.children, element);
5066	  element.parent = null;
5067
5068	  eventBus.fire(type + '.removed', { element: element });
5069
5070	  elementRegistry.remove(element);
5071
5072	  return element;
5073	};
5074
5075
5076	/**
5077	 * Removes a shape from the canvas
5078	 *
5079	 * @param {string|djs.model.Shape} shape or shape id to be removed
5080	 *
5081	 * @return {djs.model.Shape} the removed shape
5082	 */
5083	Canvas.prototype.removeShape = function(shape) {
5084
5085	  /**
5086	   * An event indicating that a shape is about to be removed from the canvas.
5087	   *
5088	   * @memberOf Canvas
5089	   *
5090	   * @event shape.remove
5091	   * @type {Object}
5092	   * @property {djs.model.Shape} element the shape descriptor
5093	   * @property {Object} gfx the graphical representation of the shape
5094	   */
5095
5096	  /**
5097	   * An event indicating that a shape has been removed from the canvas.
5098	   *
5099	   * @memberOf Canvas
5100	   *
5101	   * @event shape.removed
5102	   * @type {Object}
5103	   * @property {djs.model.Shape} element the shape descriptor
5104	   * @property {Object} gfx the graphical representation of the shape
5105	   */
5106	  return this._removeElement(shape, 'shape');
5107	};
5108
5109
5110	/**
5111	 * Removes a connection from the canvas
5112	 *
5113	 * @param {string|djs.model.Connection} connection or connection id to be removed
5114	 *
5115	 * @return {djs.model.Connection} the removed connection
5116	 */
5117	Canvas.prototype.removeConnection = function(connection) {
5118
5119	  /**
5120	   * An event indicating that a connection is about to be removed from the canvas.
5121	   *
5122	   * @memberOf Canvas
5123	   *
5124	   * @event connection.remove
5125	   * @type {Object}
5126	   * @property {djs.model.Connection} element the connection descriptor
5127	   * @property {Object} gfx the graphical representation of the connection
5128	   */
5129
5130	  /**
5131	   * An event indicating that a connection has been removed from the canvas.
5132	   *
5133	   * @memberOf Canvas
5134	   *
5135	   * @event connection.removed
5136	   * @type {Object}
5137	   * @property {djs.model.Connection} element the connection descriptor
5138	   * @property {Object} gfx the graphical representation of the connection
5139	   */
5140	  return this._removeElement(connection, 'connection');
5141	};
5142
5143
5144	/**
5145	 * Return the graphical object underlaying a certain diagram element
5146	 *
5147	 * @param {string|djs.model.Base} element descriptor of the element
5148	 * @param {boolean} [secondary=false] whether to return the secondary connected element
5149	 *
5150	 * @return {SVGElement}
5151	 */
5152	Canvas.prototype.getGraphics = function(element, secondary) {
5153	  return this._elementRegistry.getGraphics(element, secondary);
5154	};
5155
5156
5157	/**
5158	 * Perform a viewbox update via a given change function.
5159	 *
5160	 * @param {Function} changeFn
5161	 */
5162	Canvas.prototype._changeViewbox = function(changeFn) {
5163
5164	  // notify others of the upcoming viewbox change
5165	  this._eventBus.fire('canvas.viewbox.changing');
5166
5167	  // perform actual change
5168	  changeFn.apply(this);
5169
5170	  // reset the cached viewbox so that
5171	  // a new get operation on viewbox or zoom
5172	  // triggers a viewbox re-computation
5173	  this._cachedViewbox = null;
5174
5175	  // notify others of the change; this step
5176	  // may or may not be debounced
5177	  this._viewboxChanged();
5178	};
5179
5180	Canvas.prototype._viewboxChanged = function() {
5181	  this._eventBus.fire('canvas.viewbox.changed', { viewbox: this.viewbox() });
5182	};
5183
5184
5185	/**
5186	 * Gets or sets the view box of the canvas, i.e. the
5187	 * area that is currently displayed.
5188	 *
5189	 * The getter may return a cached viewbox (if it is currently
5190	 * changing). To force a recomputation, pass `false` as the first argument.
5191	 *
5192	 * @example
5193	 *
5194	 * canvas.viewbox({ x: 100, y: 100, width: 500, height: 500 })
5195	 *
5196	 * // sets the visible area of the diagram to (100|100) -> (600|100)
5197	 * // and and scales it according to the diagram width
5198	 *
5199	 * var viewbox = canvas.viewbox(); // pass `false` to force recomputing the box.
5200	 *
5201	 * console.log(viewbox);
5202	 * // {
5203	 * //   inner: Dimensions,
5204	 * //   outer: Dimensions,
5205	 * //   scale,
5206	 * //   x, y,
5207	 * //   width, height
5208	 * // }
5209	 *
5210	 * // if the current diagram is zoomed and scrolled, you may reset it to the
5211	 * // default zoom via this method, too:
5212	 *
5213	 * var zoomedAndScrolledViewbox = canvas.viewbox();
5214	 *
5215	 * canvas.viewbox({
5216	 *   x: 0,
5217	 *   y: 0,
5218	 *   width: zoomedAndScrolledViewbox.outer.width,
5219	 *   height: zoomedAndScrolledViewbox.outer.height
5220	 * });
5221	 *
5222	 * @param  {Object} [box] the new view box to set
5223	 * @param  {number} box.x the top left X coordinate of the canvas visible in view box
5224	 * @param  {number} box.y the top left Y coordinate of the canvas visible in view box
5225	 * @param  {number} box.width the visible width
5226	 * @param  {number} box.height
5227	 *
5228	 * @return {Object} the current view box
5229	 */
5230	Canvas.prototype.viewbox = function(box) {
5231
5232	  if (box === undefined && this._cachedViewbox) {
5233	    return this._cachedViewbox;
5234	  }
5235
5236	  var viewport = this._viewport,
5237	      innerBox,
5238	      outerBox = this.getSize(),
5239	      matrix,
5240	      transform,
5241	      scale,
5242	      x, y;
5243
5244	  if (!box) {
5245
5246	    // compute the inner box based on the
5247	    // diagrams default layer. This allows us to exclude
5248	    // external components, such as overlays
5249	    innerBox = this.getDefaultLayer().getBBox();
5250
5251	    transform = transform$1(viewport);
5252	    matrix = transform ? transform.matrix : createMatrix();
5253	    scale = round$b(matrix.a, 1000);
5254
5255	    x = round$b(-matrix.e || 0, 1000);
5256	    y = round$b(-matrix.f || 0, 1000);
5257
5258	    box = this._cachedViewbox = {
5259	      x: x ? x / scale : 0,
5260	      y: y ? y / scale : 0,
5261	      width: outerBox.width / scale,
5262	      height: outerBox.height / scale,
5263	      scale: scale,
5264	      inner: {
5265	        width: innerBox.width,
5266	        height: innerBox.height,
5267	        x: innerBox.x,
5268	        y: innerBox.y
5269	      },
5270	      outer: outerBox
5271	    };
5272
5273	    return box;
5274	  } else {
5275
5276	    this._changeViewbox(function() {
5277	      scale = Math.min(outerBox.width / box.width, outerBox.height / box.height);
5278
5279	      var matrix = this._svg.createSVGMatrix()
5280	        .scale(scale)
5281	        .translate(-box.x, -box.y);
5282
5283	      transform$1(viewport, matrix);
5284	    });
5285	  }
5286
5287	  return box;
5288	};
5289
5290
5291	/**
5292	 * Gets or sets the scroll of the canvas.
5293	 *
5294	 * @param {Object} [delta] the new scroll to apply.
5295	 *
5296	 * @param {number} [delta.dx]
5297	 * @param {number} [delta.dy]
5298	 */
5299	Canvas.prototype.scroll = function(delta) {
5300
5301	  var node = this._viewport;
5302	  var matrix = node.getCTM();
5303
5304	  if (delta) {
5305	    this._changeViewbox(function() {
5306	      delta = assign({ dx: 0, dy: 0 }, delta || {});
5307
5308	      matrix = this._svg.createSVGMatrix().translate(delta.dx, delta.dy).multiply(matrix);
5309
5310	      setCTM(node, matrix);
5311	    });
5312	  }
5313
5314	  return { x: matrix.e, y: matrix.f };
5315	};
5316
5317	/**
5318	 * Scrolls the viewbox to contain the given element.
5319	 * Optionally specify a padding to be applied to the edges.
5320	 *
5321	 * @param {Object} [element] the element to scroll to.
5322	 * @param {Object|Number} [padding=100] the padding to be applied. Can also specify top, bottom, left and right.
5323	 *
5324	 */
5325	Canvas.prototype.scrollToElement = function(element, padding) {
5326	  var defaultPadding = 100;
5327
5328	  // switch to correct Plane
5329	  var targetPlane = this.findPlane(element);
5330	  if (targetPlane !== this._activePlane) {
5331	    this.setActivePlane(targetPlane);
5332	  }
5333
5334	  if (!padding) {
5335	    padding = {};
5336	  }
5337	  if (typeof padding === 'number') {
5338	    defaultPadding = padding;
5339	  }
5340
5341	  padding = {
5342	    top: padding.top || defaultPadding,
5343	    right: padding.right || defaultPadding,
5344	    bottom: padding.bottom || defaultPadding,
5345	    left: padding.left || defaultPadding
5346	  };
5347
5348	  var elementBounds = getBBox(element),
5349	      elementTrbl = asTRBL(elementBounds),
5350	      viewboxBounds = this.viewbox(),
5351	      zoom = this.zoom(),
5352	      dx, dy;
5353
5354	  // shrink viewboxBounds with padding
5355	  viewboxBounds.y += padding.top / zoom;
5356	  viewboxBounds.x += padding.left / zoom;
5357	  viewboxBounds.width -= (padding.right + padding.left) / zoom;
5358	  viewboxBounds.height -= (padding.bottom + padding.top) / zoom;
5359
5360	  var viewboxTrbl = asTRBL(viewboxBounds);
5361
5362	  var canFit = elementBounds.width < viewboxBounds.width && elementBounds.height < viewboxBounds.height;
5363
5364	  if (!canFit) {
5365
5366	    // top-left when element can't fit
5367	    dx = elementBounds.x - viewboxBounds.x;
5368	    dy = elementBounds.y - viewboxBounds.y;
5369
5370	  } else {
5371
5372	    var dRight = Math.max(0, elementTrbl.right - viewboxTrbl.right),
5373	        dLeft = Math.min(0, elementTrbl.left - viewboxTrbl.left),
5374	        dBottom = Math.max(0, elementTrbl.bottom - viewboxTrbl.bottom),
5375	        dTop = Math.min(0, elementTrbl.top - viewboxTrbl.top);
5376
5377	    dx = dRight || dLeft;
5378	    dy = dBottom || dTop;
5379
5380	  }
5381
5382	  this.scroll({ dx: -dx * zoom, dy: -dy * zoom });
5383	};
5384
5385	/**
5386	 * Gets or sets the current zoom of the canvas, optionally zooming
5387	 * to the specified position.
5388	 *
5389	 * The getter may return a cached zoom level. Call it with `false` as
5390	 * the first argument to force recomputation of the current level.
5391	 *
5392	 * @param {string|number} [newScale] the new zoom level, either a number, i.e. 0.9,
5393	 *                                   or `fit-viewport` to adjust the size to fit the current viewport
5394	 * @param {string|Point} [center] the reference point { x: .., y: ..} to zoom to, 'auto' to zoom into mid or null
5395	 *
5396	 * @return {number} the current scale
5397	 */
5398	Canvas.prototype.zoom = function(newScale, center) {
5399
5400	  if (!newScale) {
5401	    return this.viewbox(newScale).scale;
5402	  }
5403
5404	  if (newScale === 'fit-viewport') {
5405	    return this._fitViewport(center);
5406	  }
5407
5408	  var outer,
5409	      matrix;
5410
5411	  this._changeViewbox(function() {
5412
5413	    if (typeof center !== 'object') {
5414	      outer = this.viewbox().outer;
5415
5416	      center = {
5417	        x: outer.width / 2,
5418	        y: outer.height / 2
5419	      };
5420	    }
5421
5422	    matrix = this._setZoom(newScale, center);
5423	  });
5424
5425	  return round$b(matrix.a, 1000);
5426	};
5427
5428	function setCTM(node, m) {
5429	  var mstr = 'matrix(' + m.a + ',' + m.b + ',' + m.c + ',' + m.d + ',' + m.e + ',' + m.f + ')';
5430	  node.setAttribute('transform', mstr);
5431	}
5432
5433	Canvas.prototype._fitViewport = function(center) {
5434
5435	  var vbox = this.viewbox(),
5436	      outer = vbox.outer,
5437	      inner = vbox.inner,
5438	      newScale,
5439	      newViewbox;
5440
5441	  // display the complete diagram without zooming in.
5442	  // instead of relying on internal zoom, we perform a
5443	  // hard reset on the canvas viewbox to realize this
5444	  //
5445	  // if diagram does not need to be zoomed in, we focus it around
5446	  // the diagram origin instead
5447
5448	  if (inner.x >= 0 &&
5449	      inner.y >= 0 &&
5450	      inner.x + inner.width <= outer.width &&
5451	      inner.y + inner.height <= outer.height &&
5452	      !center) {
5453
5454	    newViewbox = {
5455	      x: 0,
5456	      y: 0,
5457	      width: Math.max(inner.width + inner.x, outer.width),
5458	      height: Math.max(inner.height + inner.y, outer.height)
5459	    };
5460	  } else {
5461
5462	    newScale = Math.min(1, outer.width / inner.width, outer.height / inner.height);
5463	    newViewbox = {
5464	      x: inner.x + (center ? inner.width / 2 - outer.width / newScale / 2 : 0),
5465	      y: inner.y + (center ? inner.height / 2 - outer.height / newScale / 2 : 0),
5466	      width: outer.width / newScale,
5467	      height: outer.height / newScale
5468	    };
5469	  }
5470
5471	  this.viewbox(newViewbox);
5472
5473	  return this.viewbox(false).scale;
5474	};
5475
5476
5477	Canvas.prototype._setZoom = function(scale, center) {
5478
5479	  var svg = this._svg,
5480	      viewport = this._viewport;
5481
5482	  var matrix = svg.createSVGMatrix();
5483	  var point = svg.createSVGPoint();
5484
5485	  var centerPoint,
5486	      originalPoint,
5487	      currentMatrix,
5488	      scaleMatrix,
5489	      newMatrix;
5490
5491	  currentMatrix = viewport.getCTM();
5492
5493	  var currentScale = currentMatrix.a;
5494
5495	  if (center) {
5496	    centerPoint = assign(point, center);
5497
5498	    // revert applied viewport transformations
5499	    originalPoint = centerPoint.matrixTransform(currentMatrix.inverse());
5500
5501	    // create scale matrix
5502	    scaleMatrix = matrix
5503	      .translate(originalPoint.x, originalPoint.y)
5504	      .scale(1 / currentScale * scale)
5505	      .translate(-originalPoint.x, -originalPoint.y);
5506
5507	    newMatrix = currentMatrix.multiply(scaleMatrix);
5508	  } else {
5509	    newMatrix = matrix.scale(scale);
5510	  }
5511
5512	  setCTM(this._viewport, newMatrix);
5513
5514	  return newMatrix;
5515	};
5516
5517
5518	/**
5519	 * Returns the size of the canvas
5520	 *
5521	 * @return {Dimensions}
5522	 */
5523	Canvas.prototype.getSize = function() {
5524	  return {
5525	    width: this._container.clientWidth,
5526	    height: this._container.clientHeight
5527	  };
5528	};
5529
5530
5531	/**
5532	 * Return the absolute bounding box for the given element
5533	 *
5534	 * The absolute bounding box may be used to display overlays in the
5535	 * callers (browser) coordinate system rather than the zoomed in/out
5536	 * canvas coordinates.
5537	 *
5538	 * @param  {ElementDescriptor} element
5539	 * @return {Bounds} the absolute bounding box
5540	 */
5541	Canvas.prototype.getAbsoluteBBox = function(element) {
5542	  var vbox = this.viewbox();
5543	  var bbox;
5544
5545	  // connection
5546	  // use svg bbox
5547	  if (element.waypoints) {
5548	    var gfx = this.getGraphics(element);
5549
5550	    bbox = gfx.getBBox();
5551	  }
5552
5553	  // shapes
5554	  // use data
5555	  else {
5556	    bbox = element;
5557	  }
5558
5559	  var x = bbox.x * vbox.scale - vbox.x * vbox.scale;
5560	  var y = bbox.y * vbox.scale - vbox.y * vbox.scale;
5561
5562	  var width = bbox.width * vbox.scale;
5563	  var height = bbox.height * vbox.scale;
5564
5565	  return {
5566	    x: x,
5567	    y: y,
5568	    width: width,
5569	    height: height
5570	  };
5571	};
5572
5573	/**
5574	 * Fires an event in order other modules can react to the
5575	 * canvas resizing
5576	 */
5577	Canvas.prototype.resized = function() {
5578
5579	  // force recomputation of view box
5580	  delete this._cachedViewbox;
5581
5582	  this._eventBus.fire('canvas.resized');
5583	};
5584
5585	var ELEMENT_ID = 'data-element-id';
5586
5587
5588	/**
5589	 * @class
5590	 *
5591	 * A registry that keeps track of all shapes in the diagram.
5592	 */
5593	function ElementRegistry(eventBus) {
5594	  this._elements = {};
5595
5596	  this._eventBus = eventBus;
5597	}
5598
5599	ElementRegistry.$inject = [ 'eventBus' ];
5600
5601	/**
5602	 * Register a pair of (element, gfx, (secondaryGfx)).
5603	 *
5604	 * @param {djs.model.Base} element
5605	 * @param {SVGElement} gfx
5606	 * @param {SVGElement} [secondaryGfx] optional other element to register, too
5607	 */
5608	ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
5609
5610	  var id = element.id;
5611
5612	  this._validateId(id);
5613
5614	  // associate dom node with element
5615	  attr(gfx, ELEMENT_ID, id);
5616
5617	  if (secondaryGfx) {
5618	    attr(secondaryGfx, ELEMENT_ID, id);
5619	  }
5620
5621	  this._elements[id] = { element: element, gfx: gfx, secondaryGfx: secondaryGfx };
5622	};
5623
5624	/**
5625	 * Removes an element from the registry.
5626	 *
5627	 * @param {djs.model.Base} element
5628	 */
5629	ElementRegistry.prototype.remove = function(element) {
5630	  var elements = this._elements,
5631	      id = element.id || element,
5632	      container = id && elements[id];
5633
5634	  if (container) {
5635
5636	    // unset element id on gfx
5637	    attr(container.gfx, ELEMENT_ID, '');
5638
5639	    if (container.secondaryGfx) {
5640	      attr(container.secondaryGfx, ELEMENT_ID, '');
5641	    }
5642
5643	    delete elements[id];
5644	  }
5645	};
5646
5647	/**
5648	 * Update the id of an element
5649	 *
5650	 * @param {djs.model.Base} element
5651	 * @param {string} newId
5652	 */
5653	ElementRegistry.prototype.updateId = function(element, newId) {
5654
5655	  this._validateId(newId);
5656
5657	  if (typeof element === 'string') {
5658	    element = this.get(element);
5659	  }
5660
5661	  this._eventBus.fire('element.updateId', {
5662	    element: element,
5663	    newId: newId
5664	  });
5665
5666	  var gfx = this.getGraphics(element),
5667	      secondaryGfx = this.getGraphics(element, true);
5668
5669	  this.remove(element);
5670
5671	  element.id = newId;
5672
5673	  this.add(element, gfx, secondaryGfx);
5674	};
5675
5676	/**
5677	 * Update the graphics of an element
5678	 *
5679	 * @param {djs.model.Base} element
5680	 * @param {SVGElement} gfx
5681	 * @param {boolean} [secondary=false] whether to update the secondary connected element
5682	 */
5683	ElementRegistry.prototype.updateGraphics = function(filter, gfx, secondary) {
5684	  var id = filter.id || filter;
5685
5686	  var container = this._elements[id];
5687
5688	  if (secondary) {
5689	    container.secondaryGfx = gfx;
5690	  } else {
5691	    container.gfx = gfx;
5692	  }
5693
5694	  attr(gfx, ELEMENT_ID, id);
5695
5696	  return gfx;
5697	};
5698
5699	/**
5700	 * Return the model element for a given id or graphics.
5701	 *
5702	 * @example
5703	 *
5704	 * elementRegistry.get('SomeElementId_1');
5705	 * elementRegistry.get(gfx);
5706	 *
5707	 *
5708	 * @param {string|SVGElement} filter for selecting the element
5709	 *
5710	 * @return {djs.model.Base}
5711	 */
5712	ElementRegistry.prototype.get = function(filter) {
5713	  var id;
5714
5715	  if (typeof filter === 'string') {
5716	    id = filter;
5717	  } else {
5718	    id = filter && attr(filter, ELEMENT_ID);
5719	  }
5720
5721	  var container = this._elements[id];
5722	  return container && container.element;
5723	};
5724
5725	/**
5726	 * Return all elements that match a given filter function.
5727	 *
5728	 * @param {Function} fn
5729	 *
5730	 * @return {Array<djs.model.Base>}
5731	 */
5732	ElementRegistry.prototype.filter = function(fn) {
5733
5734	  var filtered = [];
5735
5736	  this.forEach(function(element, gfx) {
5737	    if (fn(element, gfx)) {
5738	      filtered.push(element);
5739	    }
5740	  });
5741
5742	  return filtered;
5743	};
5744
5745	/**
5746	 * Return the first element that satisfies the provided testing function.
5747	 *
5748	 * @param {Function} fn
5749	 *
5750	 * @return {djs.model.Base}
5751	 */
5752	ElementRegistry.prototype.find = function(fn) {
5753	  var map = this._elements,
5754	      keys = Object.keys(map);
5755
5756	  for (var i = 0; i < keys.length; i++) {
5757	    var id = keys[i],
5758	        container = map[id],
5759	        element = container.element,
5760	        gfx = container.gfx;
5761
5762	    if (fn(element, gfx)) {
5763	      return element;
5764	    }
5765	  }
5766	};
5767
5768	/**
5769	 * Return all rendered model elements.
5770	 *
5771	 * @return {Array<djs.model.Base>}
5772	 */
5773	ElementRegistry.prototype.getAll = function() {
5774	  return this.filter(function(e) { return e; });
5775	};
5776
5777	/**
5778	 * Iterate over all diagram elements.
5779	 *
5780	 * @param {Function} fn
5781	 */
5782	ElementRegistry.prototype.forEach = function(fn) {
5783
5784	  var map = this._elements;
5785
5786	  Object.keys(map).forEach(function(id) {
5787	    var container = map[id],
5788	        element = container.element,
5789	        gfx = container.gfx;
5790
5791	    return fn(element, gfx);
5792	  });
5793	};
5794
5795	/**
5796	 * Return the graphical representation of an element or its id.
5797	 *
5798	 * @example
5799	 * elementRegistry.getGraphics('SomeElementId_1');
5800	 * elementRegistry.getGraphics(rootElement); // <g ...>
5801	 *
5802	 * elementRegistry.getGraphics(rootElement, true); // <svg ...>
5803	 *
5804	 *
5805	 * @param {string|djs.model.Base} filter
5806	 * @param {boolean} [secondary=false] whether to return the secondary connected element
5807	 *
5808	 * @return {SVGElement}
5809	 */
5810	ElementRegistry.prototype.getGraphics = function(filter, secondary) {
5811	  var id = filter.id || filter;
5812
5813	  var container = this._elements[id];
5814	  return container && (secondary ? container.secondaryGfx : container.gfx);
5815	};
5816
5817	/**
5818	 * Validate the suitability of the given id and signals a problem
5819	 * with an exception.
5820	 *
5821	 * @param {string} id
5822	 *
5823	 * @throws {Error} if id is empty or already assigned
5824	 */
5825	ElementRegistry.prototype._validateId = function(id) {
5826	  if (!id) {
5827	    throw new Error('element must have an id');
5828	  }
5829
5830	  if (this._elements[id]) {
5831	    throw new Error('element with id ' + id + ' already added');
5832	  }
5833	};
5834
5835	var objectRefs = {exports: {}};
5836
5837	var collection = {};
5838
5839	/**
5840	 * An empty collection stub. Use {@link RefsCollection.extend} to extend a
5841	 * collection with ref semantics.
5842	 *
5843	 * @class RefsCollection
5844	 */
5845
5846	/**
5847	 * Extends a collection with {@link Refs} aware methods
5848	 *
5849	 * @memberof RefsCollection
5850	 * @static
5851	 *
5852	 * @param  {Array<Object>} collection
5853	 * @param  {Refs} refs instance
5854	 * @param  {Object} property represented by the collection
5855	 * @param  {Object} target object the collection is attached to
5856	 *
5857	 * @return {RefsCollection<Object>} the extended array
5858	 */
5859	function extend(collection, refs, property, target) {
5860
5861	  var inverseProperty = property.inverse;
5862
5863	  /**
5864	   * Removes the given element from the array and returns it.
5865	   *
5866	   * @method RefsCollection#remove
5867	   *
5868	   * @param {Object} element the element to remove
5869	   */
5870	  Object.defineProperty(collection, 'remove', {
5871	    value: function(element) {
5872	      var idx = this.indexOf(element);
5873	      if (idx !== -1) {
5874	        this.splice(idx, 1);
5875
5876	        // unset inverse
5877	        refs.unset(element, inverseProperty, target);
5878	      }
5879
5880	      return element;
5881	    }
5882	  });
5883
5884	  /**
5885	   * Returns true if the collection contains the given element
5886	   *
5887	   * @method RefsCollection#contains
5888	   *
5889	   * @param {Object} element the element to check for
5890	   */
5891	  Object.defineProperty(collection, 'contains', {
5892	    value: function(element) {
5893	      return this.indexOf(element) !== -1;
5894	    }
5895	  });
5896
5897	  /**
5898	   * Adds an element to the array, unless it exists already (set semantics).
5899	   *
5900	   * @method RefsCollection#add
5901	   *
5902	   * @param {Object} element the element to add
5903	   * @param {Number} optional index to add element to
5904	   *                 (possibly moving other elements around)
5905	   */
5906	  Object.defineProperty(collection, 'add', {
5907	    value: function(element, idx) {
5908
5909	      var currentIdx = this.indexOf(element);
5910
5911	      if (typeof idx === 'undefined') {
5912
5913	        if (currentIdx !== -1) {
5914	          // element already in collection (!)
5915	          return;
5916	        }
5917
5918	        // add to end of array, as no idx is specified
5919	        idx = this.length;
5920	      }
5921
5922	      // handle already in collection
5923	      if (currentIdx !== -1) {
5924
5925	        // remove element from currentIdx
5926	        this.splice(currentIdx, 1);
5927	      }
5928
5929	      // add element at idx
5930	      this.splice(idx, 0, element);
5931
5932	      if (currentIdx === -1) {
5933	        // set inverse, unless element was
5934	        // in collection already
5935	        refs.set(element, inverseProperty, target);
5936	      }
5937	    }
5938	  });
5939
5940	  // a simple marker, identifying this element
5941	  // as being a refs collection
5942	  Object.defineProperty(collection, '__refs_collection', {
5943	    value: true
5944	  });
5945
5946	  return collection;
5947	}
5948
5949
5950	function isExtended(collection) {
5951	  return collection.__refs_collection === true;
5952	}
5953
5954	collection.extend = extend;
5955
5956	collection.isExtended = isExtended;
5957
5958	var Collection = collection;
5959
5960	function hasOwnProperty$1(e, property) {
5961	  return Object.prototype.hasOwnProperty.call(e, property.name || property);
5962	}
5963
5964	function defineCollectionProperty(ref, property, target) {
5965
5966	  var collection = Collection.extend(target[property.name] || [], ref, property, target);
5967
5968	  Object.defineProperty(target, property.name, {
5969	    enumerable: property.enumerable,
5970	    value: collection
5971	  });
5972
5973	  if (collection.length) {
5974
5975	    collection.forEach(function(o) {
5976	      ref.set(o, property.inverse, target);
5977	    });
5978	  }
5979	}
5980
5981
5982	function defineProperty$1(ref, property, target) {
5983
5984	  var inverseProperty = property.inverse;
5985
5986	  var _value = target[property.name];
5987
5988	  Object.defineProperty(target, property.name, {
5989	    configurable: property.configurable,
5990	    enumerable: property.enumerable,
5991
5992	    get: function() {
5993	      return _value;
5994	    },
5995
5996	    set: function(value) {
5997
5998	      // return if we already performed all changes
5999	      if (value === _value) {
6000	        return;
6001	      }
6002
6003	      var old = _value;
6004
6005	      // temporary set null
6006	      _value = null;
6007
6008	      if (old) {
6009	        ref.unset(old, inverseProperty, target);
6010	      }
6011
6012	      // set new value
6013	      _value = value;
6014
6015	      // set inverse value
6016	      ref.set(_value, inverseProperty, target);
6017	    }
6018	  });
6019
6020	}
6021
6022	/**
6023	 * Creates a new references object defining two inversly related
6024	 * attribute descriptors a and b.
6025	 *
6026	 * <p>
6027	 *   When bound to an object using {@link Refs#bind} the references
6028	 *   get activated and ensure that add and remove operations are applied
6029	 *   reversely, too.
6030	 * </p>
6031	 *
6032	 * <p>
6033	 *   For attributes represented as collections {@link Refs} provides the
6034	 *   {@link RefsCollection#add}, {@link RefsCollection#remove} and {@link RefsCollection#contains} extensions
6035	 *   that must be used to properly hook into the inverse change mechanism.
6036	 * </p>
6037	 *
6038	 * @class Refs
6039	 *
6040	 * @classdesc A bi-directional reference between two attributes.
6041	 *
6042	 * @param {Refs.AttributeDescriptor} a property descriptor
6043	 * @param {Refs.AttributeDescriptor} b property descriptor
6044	 *
6045	 * @example
6046	 *
6047	 * var refs = Refs({ name: 'wheels', collection: true, enumerable: true }, { name: 'car' });
6048	 *
6049	 * var car = { name: 'toyota' };
6050	 * var wheels = [{ pos: 'front-left' }, { pos: 'front-right' }];
6051	 *
6052	 * refs.bind(car, 'wheels');
6053	 *
6054	 * car.wheels // []
6055	 * car.wheels.add(wheels[0]);
6056	 * car.wheels.add(wheels[1]);
6057	 *
6058	 * car.wheels // [{ pos: 'front-left' }, { pos: 'front-right' }]
6059	 *
6060	 * wheels[0].car // { name: 'toyota' };
6061	 * car.wheels.remove(wheels[0]);
6062	 *
6063	 * wheels[0].car // undefined
6064	 */
6065	function Refs$1(a, b) {
6066
6067	  if (!(this instanceof Refs$1)) {
6068	    return new Refs$1(a, b);
6069	  }
6070
6071	  // link
6072	  a.inverse = b;
6073	  b.inverse = a;
6074
6075	  this.props = {};
6076	  this.props[a.name] = a;
6077	  this.props[b.name] = b;
6078	}
6079
6080	/**
6081	 * Binds one side of a bi-directional reference to a
6082	 * target object.
6083	 *
6084	 * @memberOf Refs
6085	 *
6086	 * @param  {Object} target
6087	 * @param  {String} property
6088	 */
6089	Refs$1.prototype.bind = function(target, property) {
6090	  if (typeof property === 'string') {
6091	    if (!this.props[property]) {
6092	      throw new Error('no property <' + property + '> in ref');
6093	    }
6094	    property = this.props[property];
6095	  }
6096
6097	  if (property.collection) {
6098	    defineCollectionProperty(this, property, target);
6099	  } else {
6100	    defineProperty$1(this, property, target);
6101	  }
6102	};
6103
6104	Refs$1.prototype.ensureRefsCollection = function(target, property) {
6105
6106	  var collection = target[property.name];
6107
6108	  if (!Collection.isExtended(collection)) {
6109	    defineCollectionProperty(this, property, target);
6110	  }
6111
6112	  return collection;
6113	};
6114
6115	Refs$1.prototype.ensureBound = function(target, property) {
6116	  if (!hasOwnProperty$1(target, property)) {
6117	    this.bind(target, property);
6118	  }
6119	};
6120
6121	Refs$1.prototype.unset = function(target, property, value) {
6122
6123	  if (target) {
6124	    this.ensureBound(target, property);
6125
6126	    if (property.collection) {
6127	      this.ensureRefsCollection(target, property).remove(value);
6128	    } else {
6129	      target[property.name] = undefined;
6130	    }
6131	  }
6132	};
6133
6134	Refs$1.prototype.set = function(target, property, value) {
6135
6136	  if (target) {
6137	    this.ensureBound(target, property);
6138
6139	    if (property.collection) {
6140	      this.ensureRefsCollection(target, property).add(value);
6141	    } else {
6142	      target[property.name] = value;
6143	    }
6144	  }
6145	};
6146
6147	var refs = Refs$1;
6148
6149	objectRefs.exports = refs;
6150
6151	objectRefs.exports.Collection = collection;
6152
6153	var Refs = objectRefs.exports;
6154
6155	var parentRefs = new Refs({ name: 'children', enumerable: true, collection: true }, { name: 'parent' }),
6156	    labelRefs = new Refs({ name: 'labels', enumerable: true, collection: true }, { name: 'labelTarget' }),
6157	    attacherRefs = new Refs({ name: 'attachers', collection: true }, { name: 'host' }),
6158	    outgoingRefs = new Refs({ name: 'outgoing', collection: true }, { name: 'source' }),
6159	    incomingRefs = new Refs({ name: 'incoming', collection: true }, { name: 'target' });
6160
6161	/**
6162	 * @namespace djs.model
6163	 */
6164
6165	/**
6166	 * @memberOf djs.model
6167	 */
6168
6169	/**
6170	 * The basic graphical representation
6171	 *
6172	 * @class
6173	 *
6174	 * @abstract
6175	 */
6176	function Base$1() {
6177
6178	  /**
6179	   * The object that backs up the shape
6180	   *
6181	   * @name Base#businessObject
6182	   * @type Object
6183	   */
6184	  Object.defineProperty(this, 'businessObject', {
6185	    writable: true
6186	  });
6187
6188
6189	  /**
6190	   * Single label support, will mapped to multi label array
6191	   *
6192	   * @name Base#label
6193	   * @type Object
6194	   */
6195	  Object.defineProperty(this, 'label', {
6196	    get: function() {
6197	      return this.labels[0];
6198	    },
6199	    set: function(newLabel) {
6200
6201	      var label = this.label,
6202	          labels = this.labels;
6203
6204	      if (!newLabel && label) {
6205	        labels.remove(label);
6206	      } else {
6207	        labels.add(newLabel, 0);
6208	      }
6209	    }
6210	  });
6211
6212	  /**
6213	   * The parent shape
6214	   *
6215	   * @name Base#parent
6216	   * @type Shape
6217	   */
6218	  parentRefs.bind(this, 'parent');
6219
6220	  /**
6221	   * The list of labels
6222	   *
6223	   * @name Base#labels
6224	   * @type Label
6225	   */
6226	  labelRefs.bind(this, 'labels');
6227
6228	  /**
6229	   * The list of outgoing connections
6230	   *
6231	   * @name Base#outgoing
6232	   * @type Array<Connection>
6233	   */
6234	  outgoingRefs.bind(this, 'outgoing');
6235
6236	  /**
6237	   * The list of incoming connections
6238	   *
6239	   * @name Base#incoming
6240	   * @type Array<Connection>
6241	   */
6242	  incomingRefs.bind(this, 'incoming');
6243	}
6244
6245
6246	/**
6247	 * A graphical object
6248	 *
6249	 * @class
6250	 * @constructor
6251	 *
6252	 * @extends Base
6253	 */
6254	function Shape() {
6255	  Base$1.call(this);
6256
6257	  /**
6258	   * Indicates frame shapes
6259	   *
6260	   * @name Shape#isFrame
6261	   * @type boolean
6262	   */
6263
6264	  /**
6265	   * The list of children
6266	   *
6267	   * @name Shape#children
6268	   * @type Array<Base>
6269	   */
6270	  parentRefs.bind(this, 'children');
6271
6272	  /**
6273	   * @name Shape#host
6274	   * @type Shape
6275	   */
6276	  attacherRefs.bind(this, 'host');
6277
6278	  /**
6279	   * @name Shape#attachers
6280	   * @type Shape
6281	   */
6282	  attacherRefs.bind(this, 'attachers');
6283	}
6284
6285	inherits$1(Shape, Base$1);
6286
6287
6288	/**
6289	 * A root graphical object
6290	 *
6291	 * @class
6292	 * @constructor
6293	 *
6294	 * @extends Shape
6295	 */
6296	function Root() {
6297	  Shape.call(this);
6298	}
6299
6300	inherits$1(Root, Shape);
6301
6302
6303	/**
6304	 * A label for an element
6305	 *
6306	 * @class
6307	 * @constructor
6308	 *
6309	 * @extends Shape
6310	 */
6311	function Label() {
6312	  Shape.call(this);
6313
6314	  /**
6315	   * The labeled element
6316	   *
6317	   * @name Label#labelTarget
6318	   * @type Base
6319	   */
6320	  labelRefs.bind(this, 'labelTarget');
6321	}
6322
6323	inherits$1(Label, Shape);
6324
6325
6326	/**
6327	 * A connection between two elements
6328	 *
6329	 * @class
6330	 * @constructor
6331	 *
6332	 * @extends Base
6333	 */
6334	function Connection() {
6335	  Base$1.call(this);
6336
6337	  /**
6338	   * The element this connection originates from
6339	   *
6340	   * @name Connection#source
6341	   * @type Base
6342	   */
6343	  outgoingRefs.bind(this, 'source');
6344
6345	  /**
6346	   * The element this connection points to
6347	   *
6348	   * @name Connection#target
6349	   * @type Base
6350	   */
6351	  incomingRefs.bind(this, 'target');
6352	}
6353
6354	inherits$1(Connection, Base$1);
6355
6356
6357	var types$6 = {
6358	  connection: Connection,
6359	  shape: Shape,
6360	  label: Label,
6361	  root: Root
6362	};
6363
6364	/**
6365	 * Creates a new model element of the specified type
6366	 *
6367	 * @method create
6368	 *
6369	 * @example
6370	 *
6371	 * var shape1 = Model.create('shape', { x: 10, y: 10, width: 100, height: 100 });
6372	 * var shape2 = Model.create('shape', { x: 210, y: 210, width: 100, height: 100 });
6373	 *
6374	 * var connection = Model.create('connection', { waypoints: [ { x: 110, y: 55 }, {x: 210, y: 55 } ] });
6375	 *
6376	 * @param  {string} type lower-cased model name
6377	 * @param  {Object} attrs attributes to initialize the new model instance with
6378	 *
6379	 * @return {Base} the new model instance
6380	 */
6381	function create(type, attrs) {
6382	  var Type = types$6[type];
6383	  if (!Type) {
6384	    throw new Error('unknown type: <' + type + '>');
6385	  }
6386	  return assign(new Type(), attrs);
6387	}
6388
6389	/**
6390	 * A factory for diagram-js shapes
6391	 */
6392	function ElementFactory$1() {
6393	  this._uid = 12;
6394	}
6395
6396
6397	ElementFactory$1.prototype.createRoot = function(attrs) {
6398	  return this.create('root', attrs);
6399	};
6400
6401	ElementFactory$1.prototype.createLabel = function(attrs) {
6402	  return this.create('label', attrs);
6403	};
6404
6405	ElementFactory$1.prototype.createShape = function(attrs) {
6406	  return this.create('shape', attrs);
6407	};
6408
6409	ElementFactory$1.prototype.createConnection = function(attrs) {
6410	  return this.create('connection', attrs);
6411	};
6412
6413	/**
6414	 * Create a model element with the given type and
6415	 * a number of pre-set attributes.
6416	 *
6417	 * @param  {string} type
6418	 * @param  {Object} attrs
6419	 * @return {djs.model.Base} the newly created model instance
6420	 */
6421	ElementFactory$1.prototype.create = function(type, attrs) {
6422
6423	  attrs = assign({}, attrs || {});
6424
6425	  if (!attrs.id) {
6426	    attrs.id = type + '_' + (this._uid++);
6427	  }
6428
6429	  return create(type, attrs);
6430	};
6431
6432	var FN_REF = '__fn';
6433
6434	var DEFAULT_PRIORITY$5 = 1000;
6435
6436	var slice = Array.prototype.slice;
6437
6438	/**
6439	 * A general purpose event bus.
6440	 *
6441	 * This component is used to communicate across a diagram instance.
6442	 * Other parts of a diagram can use it to listen to and broadcast events.
6443	 *
6444	 *
6445	 * ## Registering for Events
6446	 *
6447	 * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
6448	 * methods to register for events. {@link EventBus#off} can be used to
6449	 * remove event registrations. Listeners receive an instance of {@link Event}
6450	 * as the first argument. It allows them to hook into the event execution.
6451	 *
6452	 * ```javascript
6453	 *
6454	 * // listen for event
6455	 * eventBus.on('foo', function(event) {
6456	 *
6457	 *   // access event type
6458	 *   event.type; // 'foo'
6459	 *
6460	 *   // stop propagation to other listeners
6461	 *   event.stopPropagation();
6462	 *
6463	 *   // prevent event default
6464	 *   event.preventDefault();
6465	 * });
6466	 *
6467	 * // listen for event with custom payload
6468	 * eventBus.on('bar', function(event, payload) {
6469	 *   console.log(payload);
6470	 * });
6471	 *
6472	 * // listen for event returning value
6473	 * eventBus.on('foobar', function(event) {
6474	 *
6475	 *   // stop event propagation + prevent default
6476	 *   return false;
6477	 *
6478	 *   // stop event propagation + return custom result
6479	 *   return {
6480	 *     complex: 'listening result'
6481	 *   };
6482	 * });
6483	 *
6484	 *
6485	 * // listen with custom priority (default=1000, higher is better)
6486	 * eventBus.on('priorityfoo', 1500, function(event) {
6487	 *   console.log('invoked first!');
6488	 * });
6489	 *
6490	 *
6491	 * // listen for event and pass the context (`this`)
6492	 * eventBus.on('foobar', function(event) {
6493	 *   this.foo();
6494	 * }, this);
6495	 * ```
6496	 *
6497	 *
6498	 * ## Emitting Events
6499	 *
6500	 * Events can be emitted via the event bus using {@link EventBus#fire}.
6501	 *
6502	 * ```javascript
6503	 *
6504	 * // false indicates that the default action
6505	 * // was prevented by listeners
6506	 * if (eventBus.fire('foo') === false) {
6507	 *   console.log('default has been prevented!');
6508	 * };
6509	 *
6510	 *
6511	 * // custom args + return value listener
6512	 * eventBus.on('sum', function(event, a, b) {
6513	 *   return a + b;
6514	 * });
6515	 *
6516	 * // you can pass custom arguments + retrieve result values.
6517	 * var sum = eventBus.fire('sum', 1, 2);
6518	 * console.log(sum); // 3
6519	 * ```
6520	 */
6521	function EventBus() {
6522	  this._listeners = {};
6523
6524	  // cleanup on destroy on lowest priority to allow
6525	  // message passing until the bitter end
6526	  this.on('diagram.destroy', 1, this._destroy, this);
6527	}
6528
6529
6530	/**
6531	 * Register an event listener for events with the given name.
6532	 *
6533	 * The callback will be invoked with `event, ...additionalArguments`
6534	 * that have been passed to {@link EventBus#fire}.
6535	 *
6536	 * Returning false from a listener will prevent the events default action
6537	 * (if any is specified). To stop an event from being processed further in
6538	 * other listeners execute {@link Event#stopPropagation}.
6539	 *
6540	 * Returning anything but `undefined` from a listener will stop the listener propagation.
6541	 *
6542	 * @param {string|Array<string>} events
6543	 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
6544	 * @param {Function} callback
6545	 * @param {Object} [that] Pass context (`this`) to the callback
6546	 */
6547	EventBus.prototype.on = function(events, priority, callback, that) {
6548
6549	  events = isArray$2(events) ? events : [ events ];
6550
6551	  if (isFunction(priority)) {
6552	    that = callback;
6553	    callback = priority;
6554	    priority = DEFAULT_PRIORITY$5;
6555	  }
6556
6557	  if (!isNumber(priority)) {
6558	    throw new Error('priority must be a number');
6559	  }
6560
6561	  var actualCallback = callback;
6562
6563	  if (that) {
6564	    actualCallback = bind$2(callback, that);
6565
6566	    // make sure we remember and are able to remove
6567	    // bound callbacks via {@link #off} using the original
6568	    // callback
6569	    actualCallback[FN_REF] = callback[FN_REF] || callback;
6570	  }
6571
6572	  var self = this;
6573
6574	  events.forEach(function(e) {
6575	    self._addListener(e, {
6576	      priority: priority,
6577	      callback: actualCallback,
6578	      next: null
6579	    });
6580	  });
6581	};
6582
6583
6584	/**
6585	 * Register an event listener that is executed only once.
6586	 *
6587	 * @param {string} event the event name to register for
6588	 * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
6589	 * @param {Function} callback the callback to execute
6590	 * @param {Object} [that] Pass context (`this`) to the callback
6591	 */
6592	EventBus.prototype.once = function(event, priority, callback, that) {
6593	  var self = this;
6594
6595	  if (isFunction(priority)) {
6596	    that = callback;
6597	    callback = priority;
6598	    priority = DEFAULT_PRIORITY$5;
6599	  }
6600
6601	  if (!isNumber(priority)) {
6602	    throw new Error('priority must be a number');
6603	  }
6604
6605	  function wrappedCallback() {
6606	    wrappedCallback.__isTomb = true;
6607
6608	    var result = callback.apply(that, arguments);
6609
6610	    self.off(event, wrappedCallback);
6611
6612	    return result;
6613	  }
6614
6615	  // make sure we remember and are able to remove
6616	  // bound callbacks via {@link #off} using the original
6617	  // callback
6618	  wrappedCallback[FN_REF] = callback;
6619
6620	  this.on(event, priority, wrappedCallback);
6621	};
6622
6623
6624	/**
6625	 * Removes event listeners by event and callback.
6626	 *
6627	 * If no callback is given, all listeners for a given event name are being removed.
6628	 *
6629	 * @param {string|Array<string>} events
6630	 * @param {Function} [callback]
6631	 */
6632	EventBus.prototype.off = function(events, callback) {
6633
6634	  events = isArray$2(events) ? events : [ events ];
6635
6636	  var self = this;
6637
6638	  events.forEach(function(event) {
6639	    self._removeListener(event, callback);
6640	  });
6641
6642	};
6643
6644
6645	/**
6646	 * Create an EventBus event.
6647	 *
6648	 * @param {Object} data
6649	 *
6650	 * @return {Object} event, recognized by the eventBus
6651	 */
6652	EventBus.prototype.createEvent = function(data) {
6653	  var event = new InternalEvent();
6654
6655	  event.init(data);
6656
6657	  return event;
6658	};
6659
6660
6661	/**
6662	 * Fires a named event.
6663	 *
6664	 * @example
6665	 *
6666	 * // fire event by name
6667	 * events.fire('foo');
6668	 *
6669	 * // fire event object with nested type
6670	 * var event = { type: 'foo' };
6671	 * events.fire(event);
6672	 *
6673	 * // fire event with explicit type
6674	 * var event = { x: 10, y: 20 };
6675	 * events.fire('element.moved', event);
6676	 *
6677	 * // pass additional arguments to the event
6678	 * events.on('foo', function(event, bar) {
6679	 *   alert(bar);
6680	 * });
6681	 *
6682	 * events.fire({ type: 'foo' }, 'I am bar!');
6683	 *
6684	 * @param {string} [name] the optional event name
6685	 * @param {Object} [event] the event object
6686	 * @param {...Object} additional arguments to be passed to the callback functions
6687	 *
6688	 * @return {boolean} the events return value, if specified or false if the
6689	 *                   default action was prevented by listeners
6690	 */
6691	EventBus.prototype.fire = function(type, data) {
6692	  var event,
6693	      firstListener,
6694	      returnValue,
6695	      args;
6696
6697	  args = slice.call(arguments);
6698
6699	  if (typeof type === 'object') {
6700	    data = type;
6701	    type = data.type;
6702	  }
6703
6704	  if (!type) {
6705	    throw new Error('no event type specified');
6706	  }
6707
6708	  firstListener = this._listeners[type];
6709
6710	  if (!firstListener) {
6711	    return;
6712	  }
6713
6714	  // we make sure we fire instances of our home made
6715	  // events here. We wrap them only once, though
6716	  if (data instanceof InternalEvent) {
6717
6718	    // we are fine, we alread have an event
6719	    event = data;
6720	  } else {
6721	    event = this.createEvent(data);
6722	  }
6723
6724	  // ensure we pass the event as the first parameter
6725	  args[0] = event;
6726
6727	  // original event type (in case we delegate)
6728	  var originalType = event.type;
6729
6730	  // update event type before delegation
6731	  if (type !== originalType) {
6732	    event.type = type;
6733	  }
6734
6735	  try {
6736	    returnValue = this._invokeListeners(event, args, firstListener);
6737	  } finally {
6738
6739	    // reset event type after delegation
6740	    if (type !== originalType) {
6741	      event.type = originalType;
6742	    }
6743	  }
6744
6745	  // set the return value to false if the event default
6746	  // got prevented and no other return value exists
6747	  if (returnValue === undefined && event.defaultPrevented) {
6748	    returnValue = false;
6749	  }
6750
6751	  return returnValue;
6752	};
6753
6754
6755	EventBus.prototype.handleError = function(error) {
6756	  return this.fire('error', { error: error }) === false;
6757	};
6758
6759
6760	EventBus.prototype._destroy = function() {
6761	  this._listeners = {};
6762	};
6763
6764	EventBus.prototype._invokeListeners = function(event, args, listener) {
6765
6766	  var returnValue;
6767
6768	  while (listener) {
6769
6770	    // handle stopped propagation
6771	    if (event.cancelBubble) {
6772	      break;
6773	    }
6774
6775	    returnValue = this._invokeListener(event, args, listener);
6776
6777	    listener = listener.next;
6778	  }
6779
6780	  return returnValue;
6781	};
6782
6783	EventBus.prototype._invokeListener = function(event, args, listener) {
6784
6785	  var returnValue;
6786
6787	  if (listener.callback.__isTomb) {
6788	    return returnValue;
6789	  }
6790
6791	  try {
6792
6793	    // returning false prevents the default action
6794	    returnValue = invokeFunction(listener.callback, args);
6795
6796	    // stop propagation on return value
6797	    if (returnValue !== undefined) {
6798	      event.returnValue = returnValue;
6799	      event.stopPropagation();
6800	    }
6801
6802	    // prevent default on return false
6803	    if (returnValue === false) {
6804	      event.preventDefault();
6805	    }
6806	  } catch (error) {
6807	    if (!this.handleError(error)) {
6808	      console.error('unhandled error in event listener', error);
6809
6810	      throw error;
6811	    }
6812	  }
6813
6814	  return returnValue;
6815	};
6816
6817	/*
6818	 * Add new listener with a certain priority to the list
6819	 * of listeners (for the given event).
6820	 *
6821	 * The semantics of listener registration / listener execution are
6822	 * first register, first serve: New listeners will always be inserted
6823	 * after existing listeners with the same priority.
6824	 *
6825	 * Example: Inserting two listeners with priority 1000 and 1300
6826	 *
6827	 *    * before: [ 1500, 1500, 1000, 1000 ]
6828	 *    * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
6829	 *
6830	 * @param {string} event
6831	 * @param {Object} listener { priority, callback }
6832	 */
6833	EventBus.prototype._addListener = function(event, newListener) {
6834
6835	  var listener = this._getListeners(event),
6836	      previousListener;
6837
6838	  // no prior listeners
6839	  if (!listener) {
6840	    this._setListeners(event, newListener);
6841
6842	    return;
6843	  }
6844
6845	  // ensure we order listeners by priority from
6846	  // 0 (high) to n > 0 (low)
6847	  while (listener) {
6848
6849	    if (listener.priority < newListener.priority) {
6850
6851	      newListener.next = listener;
6852
6853	      if (previousListener) {
6854	        previousListener.next = newListener;
6855	      } else {
6856	        this._setListeners(event, newListener);
6857	      }
6858
6859	      return;
6860	    }
6861
6862	    previousListener = listener;
6863	    listener = listener.next;
6864	  }
6865
6866	  // add new listener to back
6867	  previousListener.next = newListener;
6868	};
6869
6870
6871	EventBus.prototype._getListeners = function(name) {
6872	  return this._listeners[name];
6873	};
6874
6875	EventBus.prototype._setListeners = function(name, listener) {
6876	  this._listeners[name] = listener;
6877	};
6878
6879	EventBus.prototype._removeListener = function(event, callback) {
6880
6881	  var listener = this._getListeners(event),
6882	      nextListener,
6883	      previousListener,
6884	      listenerCallback;
6885
6886	  if (!callback) {
6887
6888	    // clear listeners
6889	    this._setListeners(event, null);
6890
6891	    return;
6892	  }
6893
6894	  while (listener) {
6895
6896	    nextListener = listener.next;
6897
6898	    listenerCallback = listener.callback;
6899
6900	    if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
6901	      if (previousListener) {
6902	        previousListener.next = nextListener;
6903	      } else {
6904
6905	        // new first listener
6906	        this._setListeners(event, nextListener);
6907	      }
6908	    }
6909
6910	    previousListener = listener;
6911	    listener = nextListener;
6912	  }
6913	};
6914
6915	/**
6916	 * A event that is emitted via the event bus.
6917	 */
6918	function InternalEvent() { }
6919
6920	InternalEvent.prototype.stopPropagation = function() {
6921	  this.cancelBubble = true;
6922	};
6923
6924	InternalEvent.prototype.preventDefault = function() {
6925	  this.defaultPrevented = true;
6926	};
6927
6928	InternalEvent.prototype.init = function(data) {
6929	  assign(this, data || {});
6930	};
6931
6932
6933	/**
6934	 * Invoke function. Be fast...
6935	 *
6936	 * @param {Function} fn
6937	 * @param {Array<Object>} args
6938	 *
6939	 * @return {Any}
6940	 */
6941	function invokeFunction(fn, args) {
6942	  return fn.apply(null, args);
6943	}
6944
6945	/**
6946	 * SVGs for elements are generated by the {@link GraphicsFactory}.
6947	 *
6948	 * This utility gives quick access to the important semantic
6949	 * parts of an element.
6950	 */
6951
6952	/**
6953	 * Returns the visual part of a diagram element
6954	 *
6955	 * @param {Snap<SVGElement>} gfx
6956	 *
6957	 * @return {Snap<SVGElement>}
6958	 */
6959	function getVisual(gfx) {
6960	  return gfx.childNodes[0];
6961	}
6962
6963	/**
6964	 * Returns the children for a given diagram element.
6965	 *
6966	 * @param {Snap<SVGElement>} gfx
6967	 * @return {Snap<SVGElement>}
6968	 */
6969	function getChildren$1(gfx) {
6970	  return gfx.parentNode.childNodes[1];
6971	}
6972
6973	/**
6974	 * @param {<SVGElement>} element
6975	 * @param {number} x
6976	 * @param {number} y
6977	 * @param {number} angle
6978	 * @param {number} amount
6979	 */
6980	function transform(gfx, x, y, angle, amount) {
6981	  var translate = createTransform();
6982	  translate.setTranslate(x, y);
6983
6984	  var rotate = createTransform();
6985	  rotate.setRotate(angle || 0, 0, 0);
6986
6987	  var scale = createTransform();
6988	  scale.setScale(amount || 1, amount || 1);
6989
6990	  transform$1(gfx, [ translate, rotate, scale ]);
6991	}
6992
6993
6994	/**
6995	 * @param {SVGElement} element
6996	 * @param {number} x
6997	 * @param {number} y
6998	 */
6999	function translate$2(gfx, x, y) {
7000	  var translate = createTransform();
7001	  translate.setTranslate(x, y);
7002
7003	  transform$1(gfx, translate);
7004	}
7005
7006
7007	/**
7008	 * @param {SVGElement} element
7009	 * @param {number} angle
7010	 */
7011	function rotate(gfx, angle) {
7012	  var rotate = createTransform();
7013	  rotate.setRotate(angle, 0, 0);
7014
7015	  transform$1(gfx, rotate);
7016	}
7017
7018	/**
7019	 * A factory that creates graphical elements
7020	 *
7021	 * @param {EventBus} eventBus
7022	 * @param {ElementRegistry} elementRegistry
7023	 */
7024	function GraphicsFactory(eventBus, elementRegistry) {
7025	  this._eventBus = eventBus;
7026	  this._elementRegistry = elementRegistry;
7027	}
7028
7029	GraphicsFactory.$inject = [ 'eventBus' , 'elementRegistry' ];
7030
7031
7032	GraphicsFactory.prototype._getChildrenContainer = function(element) {
7033
7034	  var gfx = this._elementRegistry.getGraphics(element);
7035
7036	  var childrenGfx;
7037
7038	  // root element
7039	  if (!element.parent) {
7040	    childrenGfx = gfx;
7041	  } else {
7042	    childrenGfx = getChildren$1(gfx);
7043	    if (!childrenGfx) {
7044	      childrenGfx = create$1('g');
7045	      classes(childrenGfx).add('djs-children');
7046
7047	      append(gfx.parentNode, childrenGfx);
7048	    }
7049	  }
7050
7051	  return childrenGfx;
7052	};
7053
7054	/**
7055	 * Clears the graphical representation of the element and returns the
7056	 * cleared visual (the <g class="djs-visual" /> element).
7057	 */
7058	GraphicsFactory.prototype._clear = function(gfx) {
7059	  var visual = getVisual(gfx);
7060
7061	  clear$1(visual);
7062
7063	  return visual;
7064	};
7065
7066	/**
7067	 * Creates a gfx container for shapes and connections
7068	 *
7069	 * The layout is as follows:
7070	 *
7071	 * <g class="djs-group">
7072	 *
7073	 *   <!-- the gfx -->
7074	 *   <g class="djs-element djs-(shape|connection|frame)">
7075	 *     <g class="djs-visual">
7076	 *       <!-- the renderer draws in here -->
7077	 *     </g>
7078	 *
7079	 *     <!-- extensions (overlays, click box, ...) goes here
7080	 *   </g>
7081	 *
7082	 *   <!-- the gfx child nodes -->
7083	 *   <g class="djs-children"></g>
7084	 * </g>
7085	 *
7086	 * @param {string} type the type of the element, i.e. shape | connection
7087	 * @param {SVGElement} [childrenGfx]
7088	 * @param {number} [parentIndex] position to create container in parent
7089	 * @param {boolean} [isFrame] is frame element
7090	 *
7091	 * @return {SVGElement}
7092	 */
7093	GraphicsFactory.prototype._createContainer = function(
7094	    type, childrenGfx, parentIndex, isFrame
7095	) {
7096	  var outerGfx = create$1('g');
7097	  classes(outerGfx).add('djs-group');
7098
7099	  // insert node at position
7100	  if (typeof parentIndex !== 'undefined') {
7101	    prependTo(outerGfx, childrenGfx, childrenGfx.childNodes[parentIndex]);
7102	  } else {
7103	    append(childrenGfx, outerGfx);
7104	  }
7105
7106	  var gfx = create$1('g');
7107	  classes(gfx).add('djs-element');
7108	  classes(gfx).add('djs-' + type);
7109
7110	  if (isFrame) {
7111	    classes(gfx).add('djs-frame');
7112	  }
7113
7114	  append(outerGfx, gfx);
7115
7116	  // create visual
7117	  var visual = create$1('g');
7118	  classes(visual).add('djs-visual');
7119
7120	  append(gfx, visual);
7121
7122	  return gfx;
7123	};
7124
7125	GraphicsFactory.prototype.create = function(type, element, parentIndex) {
7126	  var childrenGfx = this._getChildrenContainer(element.parent);
7127	  return this._createContainer(type, childrenGfx, parentIndex, isFrameElement$1(element));
7128	};
7129
7130	GraphicsFactory.prototype.updateContainments = function(elements) {
7131
7132	  var self = this,
7133	      elementRegistry = this._elementRegistry,
7134	      parents;
7135
7136	  parents = reduce(elements, function(map, e) {
7137
7138	    if (e.parent) {
7139	      map[e.parent.id] = e.parent;
7140	    }
7141
7142	    return map;
7143	  }, {});
7144
7145	  // update all parents of changed and reorganized their children
7146	  // in the correct order (as indicated in our model)
7147	  forEach(parents, function(parent) {
7148
7149	    var children = parent.children;
7150
7151	    if (!children) {
7152	      return;
7153	    }
7154
7155	    var childrenGfx = self._getChildrenContainer(parent);
7156
7157	    forEach(children.slice().reverse(), function(child) {
7158	      var childGfx = elementRegistry.getGraphics(child);
7159
7160	      prependTo(childGfx.parentNode, childrenGfx);
7161	    });
7162	  });
7163	};
7164
7165	GraphicsFactory.prototype.drawShape = function(visual, element) {
7166	  var eventBus = this._eventBus;
7167
7168	  return eventBus.fire('render.shape', { gfx: visual, element: element });
7169	};
7170
7171	GraphicsFactory.prototype.getShapePath = function(element) {
7172	  var eventBus = this._eventBus;
7173
7174	  return eventBus.fire('render.getShapePath', element);
7175	};
7176
7177	GraphicsFactory.prototype.drawConnection = function(visual, element) {
7178	  var eventBus = this._eventBus;
7179
7180	  return eventBus.fire('render.connection', { gfx: visual, element: element });
7181	};
7182
7183	GraphicsFactory.prototype.getConnectionPath = function(waypoints) {
7184	  var eventBus = this._eventBus;
7185
7186	  return eventBus.fire('render.getConnectionPath', waypoints);
7187	};
7188
7189	GraphicsFactory.prototype.update = function(type, element, gfx) {
7190
7191	  // do NOT update root element
7192	  if (!element.parent) {
7193	    return;
7194	  }
7195
7196	  var visual = this._clear(gfx);
7197
7198	  // redraw
7199	  if (type === 'shape') {
7200	    this.drawShape(visual, element);
7201
7202	    // update positioning
7203	    translate$2(gfx, element.x, element.y);
7204	  } else
7205	  if (type === 'connection') {
7206	    this.drawConnection(visual, element);
7207	  } else {
7208	    throw new Error('unknown type: ' + type);
7209	  }
7210
7211	  if (element.hidden) {
7212	    attr(gfx, 'display', 'none');
7213	  } else {
7214	    attr(gfx, 'display', 'block');
7215	  }
7216	};
7217
7218	GraphicsFactory.prototype.remove = function(element) {
7219	  var gfx = this._elementRegistry.getGraphics(element);
7220
7221	  // remove
7222	  remove$1(gfx.parentNode);
7223	};
7224
7225
7226	// helpers //////////
7227
7228	function prependTo(newNode, parentNode, siblingNode) {
7229	  var node = siblingNode || parentNode.firstChild;
7230
7231	  // do not prepend node to itself to prevent IE from crashing
7232	  // https://github.com/bpmn-io/bpmn-js/issues/746
7233	  if (newNode === node) {
7234	    return;
7235	  }
7236
7237	  parentNode.insertBefore(newNode, node);
7238	}
7239
7240	var CoreModule$1 = {
7241	  __depends__: [ DrawModule$1 ],
7242	  __init__: [ 'canvas' ],
7243	  canvas: [ 'type', Canvas ],
7244	  elementRegistry: [ 'type', ElementRegistry ],
7245	  elementFactory: [ 'type', ElementFactory$1 ],
7246	  eventBus: [ 'type', EventBus ],
7247	  graphicsFactory: [ 'type', GraphicsFactory ]
7248	};
7249
7250	/**
7251	 * Bootstrap an injector from a list of modules, instantiating a number of default components
7252	 *
7253	 * @ignore
7254	 * @param {Array<didi.Module>} bootstrapModules
7255	 *
7256	 * @return {didi.Injector} a injector to use to access the components
7257	 */
7258	function bootstrap(bootstrapModules) {
7259
7260	  var modules = [],
7261	      components = [];
7262
7263	  function hasModule(m) {
7264	    return modules.indexOf(m) >= 0;
7265	  }
7266
7267	  function addModule(m) {
7268	    modules.push(m);
7269	  }
7270
7271	  function visit(m) {
7272	    if (hasModule(m)) {
7273	      return;
7274	    }
7275
7276	    (m.__depends__ || []).forEach(visit);
7277
7278	    if (hasModule(m)) {
7279	      return;
7280	    }
7281
7282	    addModule(m);
7283
7284	    (m.__init__ || []).forEach(function(c) {
7285	      components.push(c);
7286	    });
7287	  }
7288
7289	  bootstrapModules.forEach(visit);
7290
7291	  var injector = new Injector(modules);
7292
7293	  components.forEach(function(c) {
7294
7295	    try {
7296
7297	      // eagerly resolve component (fn or string)
7298	      injector[typeof c === 'string' ? 'get' : 'invoke'](c);
7299	    } catch (e) {
7300	      console.error('Failed to instantiate component');
7301	      console.error(e.stack);
7302
7303	      throw e;
7304	    }
7305	  });
7306
7307	  return injector;
7308	}
7309
7310	/**
7311	 * Creates an injector from passed options.
7312	 *
7313	 * @ignore
7314	 * @param  {Object} options
7315	 * @return {didi.Injector}
7316	 */
7317	function createInjector(options) {
7318
7319	  options = options || {};
7320
7321	  var configModule = {
7322	    'config': ['value', options]
7323	  };
7324
7325	  var modules = [ configModule, CoreModule$1 ].concat(options.modules || []);
7326
7327	  return bootstrap(modules);
7328	}
7329
7330
7331	/**
7332	 * The main diagram-js entry point that bootstraps the diagram with the given
7333	 * configuration.
7334	 *
7335	 * To register extensions with the diagram, pass them as Array<didi.Module> to the constructor.
7336	 *
7337	 * @class djs.Diagram
7338	 * @memberOf djs
7339	 * @constructor
7340	 *
7341	 * @example
7342	 *
7343	 * <caption>Creating a plug-in that logs whenever a shape is added to the canvas.</caption>
7344	 *
7345	 * // plug-in implemenentation
7346	 * function MyLoggingPlugin(eventBus) {
7347	 *   eventBus.on('shape.added', function(event) {
7348	 *     console.log('shape ', event.shape, ' was added to the diagram');
7349	 *   });
7350	 * }
7351	 *
7352	 * // export as module
7353	 * export default {
7354	 *   __init__: [ 'myLoggingPlugin' ],
7355	 *     myLoggingPlugin: [ 'type', MyLoggingPlugin ]
7356	 * };
7357	 *
7358	 *
7359	 * // instantiate the diagram with the new plug-in
7360	 *
7361	 * import MyLoggingModule from 'path-to-my-logging-plugin';
7362	 *
7363	 * var diagram = new Diagram({
7364	 *   modules: [
7365	 *     MyLoggingModule
7366	 *   ]
7367	 * });
7368	 *
7369	 * diagram.invoke([ 'canvas', function(canvas) {
7370	 *   // add shape to drawing canvas
7371	 *   canvas.addShape({ x: 10, y: 10 });
7372	 * });
7373	 *
7374	 * // 'shape ... was added to the diagram' logged to console
7375	 *
7376	 * @param {Object} options
7377	 * @param {Array<didi.Module>} [options.modules] external modules to instantiate with the diagram
7378	 * @param {didi.Injector} [injector] an (optional) injector to bootstrap the diagram with
7379	 */
7380	function Diagram(options, injector) {
7381
7382	  // create injector unless explicitly specified
7383	  this.injector = injector = injector || createInjector(options);
7384
7385	  // API
7386
7387	  /**
7388	   * Resolves a diagram service
7389	   *
7390	   * @method Diagram#get
7391	   *
7392	   * @param {string} name the name of the diagram service to be retrieved
7393	   * @param {boolean} [strict=true] if false, resolve missing services to null
7394	   */
7395	  this.get = injector.get;
7396
7397	  /**
7398	   * Executes a function into which diagram services are injected
7399	   *
7400	   * @method Diagram#invoke
7401	   *
7402	   * @param {Function|Object[]} fn the function to resolve
7403	   * @param {Object} locals a number of locals to use to resolve certain dependencies
7404	   */
7405	  this.invoke = injector.invoke;
7406
7407	  // init
7408
7409	  // indicate via event
7410
7411
7412	  /**
7413	   * An event indicating that all plug-ins are loaded.
7414	   *
7415	   * Use this event to fire other events to interested plug-ins
7416	   *
7417	   * @memberOf Diagram
7418	   *
7419	   * @event diagram.init
7420	   *
7421	   * @example
7422	   *
7423	   * eventBus.on('diagram.init', function() {
7424	   *   eventBus.fire('my-custom-event', { foo: 'BAR' });
7425	   * });
7426	   *
7427	   * @type {Object}
7428	   */
7429	  this.get('eventBus').fire('diagram.init');
7430	}
7431
7432
7433	/**
7434	 * Destroys the diagram
7435	 *
7436	 * @method  Diagram#destroy
7437	 */
7438	Diagram.prototype.destroy = function() {
7439	  this.get('eventBus').fire('diagram.destroy');
7440	};
7441
7442	/**
7443	 * Clear the diagram, removing all contents.
7444	 */
7445	Diagram.prototype.clear = function() {
7446	  this.get('eventBus').fire('diagram.clear');
7447	};
7448
7449	/**
7450	 * Moddle base element.
7451	 */
7452	function Base() { }
7453
7454	Base.prototype.get = function(name) {
7455	  return this.$model.properties.get(this, name);
7456	};
7457
7458	Base.prototype.set = function(name, value) {
7459	  this.$model.properties.set(this, name, value);
7460	};
7461
7462	/**
7463	 * A model element factory.
7464	 *
7465	 * @param {Moddle} model
7466	 * @param {Properties} properties
7467	 */
7468	function Factory(model, properties) {
7469	  this.model = model;
7470	  this.properties = properties;
7471	}
7472
7473
7474	Factory.prototype.createType = function(descriptor) {
7475
7476	  var model = this.model;
7477
7478	  var props = this.properties,
7479	      prototype = Object.create(Base.prototype);
7480
7481	  // initialize default values
7482	  forEach(descriptor.properties, function(p) {
7483	    if (!p.isMany && p.default !== undefined) {
7484	      prototype[p.name] = p.default;
7485	    }
7486	  });
7487
7488	  props.defineModel(prototype, model);
7489	  props.defineDescriptor(prototype, descriptor);
7490
7491	  var name = descriptor.ns.name;
7492
7493	  /**
7494	   * The new type constructor
7495	   */
7496	  function ModdleElement(attrs) {
7497	    props.define(this, '$type', { value: name, enumerable: true });
7498	    props.define(this, '$attrs', { value: {} });
7499	    props.define(this, '$parent', { writable: true });
7500
7501	    forEach(attrs, bind$2(function(val, key) {
7502	      this.set(key, val);
7503	    }, this));
7504	  }
7505
7506	  ModdleElement.prototype = prototype;
7507
7508	  ModdleElement.hasType = prototype.$instanceOf = this.model.hasType;
7509
7510	  // static links
7511	  props.defineModel(ModdleElement, model);
7512	  props.defineDescriptor(ModdleElement, descriptor);
7513
7514	  return ModdleElement;
7515	};
7516
7517	/**
7518	 * Built-in moddle types
7519	 */
7520	var BUILTINS = {
7521	  String: true,
7522	  Boolean: true,
7523	  Integer: true,
7524	  Real: true,
7525	  Element: true
7526	};
7527
7528	/**
7529	 * Converters for built in types from string representations
7530	 */
7531	var TYPE_CONVERTERS = {
7532	  String: function(s) { return s; },
7533	  Boolean: function(s) { return s === 'true'; },
7534	  Integer: function(s) { return parseInt(s, 10); },
7535	  Real: function(s) { return parseFloat(s); }
7536	};
7537
7538	/**
7539	 * Convert a type to its real representation
7540	 */
7541	function coerceType(type, value) {
7542
7543	  var converter = TYPE_CONVERTERS[type];
7544
7545	  if (converter) {
7546	    return converter(value);
7547	  } else {
7548	    return value;
7549	  }
7550	}
7551
7552	/**
7553	 * Return whether the given type is built-in
7554	 */
7555	function isBuiltIn(type) {
7556	  return !!BUILTINS[type];
7557	}
7558
7559	/**
7560	 * Return whether the given type is simple
7561	 */
7562	function isSimple(type) {
7563	  return !!TYPE_CONVERTERS[type];
7564	}
7565
7566	/**
7567	 * Parses a namespaced attribute name of the form (ns:)localName to an object,
7568	 * given a default prefix to assume in case no explicit namespace is given.
7569	 *
7570	 * @param {String} name
7571	 * @param {String} [defaultPrefix] the default prefix to take, if none is present.
7572	 *
7573	 * @return {Object} the parsed name
7574	 */
7575	function parseName(name, defaultPrefix) {
7576	  var parts = name.split(/:/),
7577	      localName, prefix;
7578
7579	  // no prefix (i.e. only local name)
7580	  if (parts.length === 1) {
7581	    localName = name;
7582	    prefix = defaultPrefix;
7583	  } else
7584	  // prefix + local name
7585	  if (parts.length === 2) {
7586	    localName = parts[1];
7587	    prefix = parts[0];
7588	  } else {
7589	    throw new Error('expected <prefix:localName> or <localName>, got ' + name);
7590	  }
7591
7592	  name = (prefix ? prefix + ':' : '') + localName;
7593
7594	  return {
7595	    name: name,
7596	    prefix: prefix,
7597	    localName: localName
7598	  };
7599	}
7600
7601	/**
7602	 * A utility to build element descriptors.
7603	 */
7604	function DescriptorBuilder(nameNs) {
7605	  this.ns = nameNs;
7606	  this.name = nameNs.name;
7607	  this.allTypes = [];
7608	  this.allTypesByName = {};
7609	  this.properties = [];
7610	  this.propertiesByName = {};
7611	}
7612
7613
7614	DescriptorBuilder.prototype.build = function() {
7615	  return pick(this, [
7616	    'ns',
7617	    'name',
7618	    'allTypes',
7619	    'allTypesByName',
7620	    'properties',
7621	    'propertiesByName',
7622	    'bodyProperty',
7623	    'idProperty'
7624	  ]);
7625	};
7626
7627	/**
7628	 * Add property at given index.
7629	 *
7630	 * @param {Object} p
7631	 * @param {Number} [idx]
7632	 * @param {Boolean} [validate=true]
7633	 */
7634	DescriptorBuilder.prototype.addProperty = function(p, idx, validate) {
7635
7636	  if (typeof idx === 'boolean') {
7637	    validate = idx;
7638	    idx = undefined;
7639	  }
7640
7641	  this.addNamedProperty(p, validate !== false);
7642
7643	  var properties = this.properties;
7644
7645	  if (idx !== undefined) {
7646	    properties.splice(idx, 0, p);
7647	  } else {
7648	    properties.push(p);
7649	  }
7650	};
7651
7652
7653	DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
7654	  var oldNameNs = oldProperty.ns;
7655
7656	  var props = this.properties,
7657	      propertiesByName = this.propertiesByName,
7658	      rename = oldProperty.name !== newProperty.name;
7659
7660	  if (oldProperty.isId) {
7661	    if (!newProperty.isId) {
7662	      throw new Error(
7663	        'property <' + newProperty.ns.name + '> must be id property ' +
7664	        'to refine <' + oldProperty.ns.name + '>');
7665	    }
7666
7667	    this.setIdProperty(newProperty, false);
7668	  }
7669
7670	  if (oldProperty.isBody) {
7671
7672	    if (!newProperty.isBody) {
7673	      throw new Error(
7674	        'property <' + newProperty.ns.name + '> must be body property ' +
7675	        'to refine <' + oldProperty.ns.name + '>');
7676	    }
7677
7678	    // TODO: Check compatibility
7679	    this.setBodyProperty(newProperty, false);
7680	  }
7681
7682	  // validate existence and get location of old property
7683	  var idx = props.indexOf(oldProperty);
7684	  if (idx === -1) {
7685	    throw new Error('property <' + oldNameNs.name + '> not found in property list');
7686	  }
7687
7688	  // remove old property
7689	  props.splice(idx, 1);
7690
7691	  // replacing the named property is intentional
7692	  //
7693	  //  * validate only if this is a "rename" operation
7694	  //  * add at specific index unless we "replace"
7695	  //
7696	  this.addProperty(newProperty, replace ? undefined : idx, rename);
7697
7698	  // make new property available under old name
7699	  propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
7700	};
7701
7702
7703	DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
7704
7705	  var nsPrefix = p.ns.prefix;
7706	  var parts = targetPropertyName.split('#');
7707
7708	  var name = parseName(parts[0], nsPrefix);
7709	  var attrName = parseName(parts[1], name.prefix).name;
7710
7711	  var redefinedProperty = this.propertiesByName[attrName];
7712	  if (!redefinedProperty) {
7713	    throw new Error('refined property <' + attrName + '> not found');
7714	  } else {
7715	    this.replaceProperty(redefinedProperty, p, replace);
7716	  }
7717
7718	  delete p.redefines;
7719	};
7720
7721	DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
7722	  var ns = p.ns,
7723	      propsByName = this.propertiesByName;
7724
7725	  if (validate) {
7726	    this.assertNotDefined(p, ns.name);
7727	    this.assertNotDefined(p, ns.localName);
7728	  }
7729
7730	  propsByName[ns.name] = propsByName[ns.localName] = p;
7731	};
7732
7733	DescriptorBuilder.prototype.removeNamedProperty = function(p) {
7734	  var ns = p.ns,
7735	      propsByName = this.propertiesByName;
7736
7737	  delete propsByName[ns.name];
7738	  delete propsByName[ns.localName];
7739	};
7740
7741	DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
7742
7743	  if (validate && this.bodyProperty) {
7744	    throw new Error(
7745	      'body property defined multiple times ' +
7746	      '(<' + this.bodyProperty.ns.name + '>, <' + p.ns.name + '>)');
7747	  }
7748
7749	  this.bodyProperty = p;
7750	};
7751
7752	DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
7753
7754	  if (validate && this.idProperty) {
7755	    throw new Error(
7756	      'id property defined multiple times ' +
7757	      '(<' + this.idProperty.ns.name + '>, <' + p.ns.name + '>)');
7758	  }
7759
7760	  this.idProperty = p;
7761	};
7762
7763	DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
7764	  var propertyName = p.name,
7765	      definedProperty = this.propertiesByName[propertyName];
7766
7767	  if (definedProperty) {
7768	    throw new Error(
7769	      'property <' + propertyName + '> already defined; ' +
7770	      'override of <' + definedProperty.definedBy.ns.name + '#' + definedProperty.ns.name + '> by ' +
7771	      '<' + p.definedBy.ns.name + '#' + p.ns.name + '> not allowed without redefines');
7772	  }
7773	};
7774
7775	DescriptorBuilder.prototype.hasProperty = function(name) {
7776	  return this.propertiesByName[name];
7777	};
7778
7779	DescriptorBuilder.prototype.addTrait = function(t, inherited) {
7780
7781	  var typesByName = this.allTypesByName,
7782	      types = this.allTypes;
7783
7784	  var typeName = t.name;
7785
7786	  if (typeName in typesByName) {
7787	    return;
7788	  }
7789
7790	  forEach(t.properties, bind$2(function(p) {
7791
7792	    // clone property to allow extensions
7793	    p = assign({}, p, {
7794	      name: p.ns.localName,
7795	      inherited: inherited
7796	    });
7797
7798	    Object.defineProperty(p, 'definedBy', {
7799	      value: t
7800	    });
7801
7802	    var replaces = p.replaces,
7803	        redefines = p.redefines;
7804
7805	    // add replace/redefine support
7806	    if (replaces || redefines) {
7807	      this.redefineProperty(p, replaces || redefines, replaces);
7808	    } else {
7809	      if (p.isBody) {
7810	        this.setBodyProperty(p);
7811	      }
7812	      if (p.isId) {
7813	        this.setIdProperty(p);
7814	      }
7815	      this.addProperty(p);
7816	    }
7817	  }, this));
7818
7819	  types.push(t);
7820	  typesByName[typeName] = t;
7821	};
7822
7823	/**
7824	 * A registry of Moddle packages.
7825	 *
7826	 * @param {Array<Package>} packages
7827	 * @param {Properties} properties
7828	 */
7829	function Registry(packages, properties) {
7830	  this.packageMap = {};
7831	  this.typeMap = {};
7832
7833	  this.packages = [];
7834
7835	  this.properties = properties;
7836
7837	  forEach(packages, bind$2(this.registerPackage, this));
7838	}
7839
7840
7841	Registry.prototype.getPackage = function(uriOrPrefix) {
7842	  return this.packageMap[uriOrPrefix];
7843	};
7844
7845	Registry.prototype.getPackages = function() {
7846	  return this.packages;
7847	};
7848
7849
7850	Registry.prototype.registerPackage = function(pkg) {
7851
7852	  // copy package
7853	  pkg = assign({}, pkg);
7854
7855	  var pkgMap = this.packageMap;
7856
7857	  ensureAvailable(pkgMap, pkg, 'prefix');
7858	  ensureAvailable(pkgMap, pkg, 'uri');
7859
7860	  // register types
7861	  forEach(pkg.types, bind$2(function(descriptor) {
7862	    this.registerType(descriptor, pkg);
7863	  }, this));
7864
7865	  pkgMap[pkg.uri] = pkgMap[pkg.prefix] = pkg;
7866	  this.packages.push(pkg);
7867	};
7868
7869
7870	/**
7871	 * Register a type from a specific package with us
7872	 */
7873	Registry.prototype.registerType = function(type, pkg) {
7874
7875	  type = assign({}, type, {
7876	    superClass: (type.superClass || []).slice(),
7877	    extends: (type.extends || []).slice(),
7878	    properties: (type.properties || []).slice(),
7879	    meta: assign((type.meta || {}))
7880	  });
7881
7882	  var ns = parseName(type.name, pkg.prefix),
7883	      name = ns.name,
7884	      propertiesByName = {};
7885
7886	  // parse properties
7887	  forEach(type.properties, bind$2(function(p) {
7888
7889	    // namespace property names
7890	    var propertyNs = parseName(p.name, ns.prefix),
7891	        propertyName = propertyNs.name;
7892
7893	    // namespace property types
7894	    if (!isBuiltIn(p.type)) {
7895	      p.type = parseName(p.type, propertyNs.prefix).name;
7896	    }
7897
7898	    assign(p, {
7899	      ns: propertyNs,
7900	      name: propertyName
7901	    });
7902
7903	    propertiesByName[propertyName] = p;
7904	  }, this));
7905
7906	  // update ns + name
7907	  assign(type, {
7908	    ns: ns,
7909	    name: name,
7910	    propertiesByName: propertiesByName
7911	  });
7912
7913	  forEach(type.extends, bind$2(function(extendsName) {
7914	    var extended = this.typeMap[extendsName];
7915
7916	    extended.traits = extended.traits || [];
7917	    extended.traits.push(name);
7918	  }, this));
7919
7920	  // link to package
7921	  this.definePackage(type, pkg);
7922
7923	  // register
7924	  this.typeMap[name] = type;
7925	};
7926
7927
7928	/**
7929	 * Traverse the type hierarchy from bottom to top,
7930	 * calling iterator with (type, inherited) for all elements in
7931	 * the inheritance chain.
7932	 *
7933	 * @param {Object} nsName
7934	 * @param {Function} iterator
7935	 * @param {Boolean} [trait=false]
7936	 */
7937	Registry.prototype.mapTypes = function(nsName, iterator, trait) {
7938
7939	  var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
7940
7941	  var self = this;
7942
7943	  /**
7944	   * Traverse the selected trait.
7945	   *
7946	   * @param {String} cls
7947	   */
7948	  function traverseTrait(cls) {
7949	    return traverseSuper(cls, true);
7950	  }
7951
7952	  /**
7953	   * Traverse the selected super type or trait
7954	   *
7955	   * @param {String} cls
7956	   * @param {Boolean} [trait=false]
7957	   */
7958	  function traverseSuper(cls, trait) {
7959	    var parentNs = parseName(cls, isBuiltIn(cls) ? '' : nsName.prefix);
7960	    self.mapTypes(parentNs, iterator, trait);
7961	  }
7962
7963	  if (!type) {
7964	    throw new Error('unknown type <' + nsName.name + '>');
7965	  }
7966
7967	  forEach(type.superClass, trait ? traverseTrait : traverseSuper);
7968
7969	  // call iterator with (type, inherited=!trait)
7970	  iterator(type, !trait);
7971
7972	  forEach(type.traits, traverseTrait);
7973	};
7974
7975
7976	/**
7977	 * Returns the effective descriptor for a type.
7978	 *
7979	 * @param  {String} type the namespaced name (ns:localName) of the type
7980	 *
7981	 * @return {Descriptor} the resulting effective descriptor
7982	 */
7983	Registry.prototype.getEffectiveDescriptor = function(name) {
7984
7985	  var nsName = parseName(name);
7986
7987	  var builder = new DescriptorBuilder(nsName);
7988
7989	  this.mapTypes(nsName, function(type, inherited) {
7990	    builder.addTrait(type, inherited);
7991	  });
7992
7993	  var descriptor = builder.build();
7994
7995	  // define package link
7996	  this.definePackage(descriptor, descriptor.allTypes[descriptor.allTypes.length - 1].$pkg);
7997
7998	  return descriptor;
7999	};
8000
8001
8002	Registry.prototype.definePackage = function(target, pkg) {
8003	  this.properties.define(target, '$pkg', { value: pkg });
8004	};
8005
8006
8007
8008	///////// helpers ////////////////////////////
8009
8010	function ensureAvailable(packageMap, pkg, identifierKey) {
8011
8012	  var value = pkg[identifierKey];
8013
8014	  if (value in packageMap) {
8015	    throw new Error('package with ' + identifierKey + ' <' + value + '> already defined');
8016	  }
8017	}
8018
8019	/**
8020	 * A utility that gets and sets properties of model elements.
8021	 *
8022	 * @param {Model} model
8023	 */
8024	function Properties(model) {
8025	  this.model = model;
8026	}
8027
8028
8029	/**
8030	 * Sets a named property on the target element.
8031	 * If the value is undefined, the property gets deleted.
8032	 *
8033	 * @param {Object} target
8034	 * @param {String} name
8035	 * @param {Object} value
8036	 */
8037	Properties.prototype.set = function(target, name, value) {
8038
8039	  var property = this.model.getPropertyDescriptor(target, name);
8040
8041	  var propertyName = property && property.name;
8042
8043	  if (isUndefined(value)) {
8044	    // unset the property, if the specified value is undefined;
8045	    // delete from $attrs (for extensions) or the target itself
8046	    if (property) {
8047	      delete target[propertyName];
8048	    } else {
8049	      delete target.$attrs[name];
8050	    }
8051	  } else {
8052	    // set the property, defining well defined properties on the fly
8053	    // or simply updating them in target.$attrs (for extensions)
8054	    if (property) {
8055	      if (propertyName in target) {
8056	        target[propertyName] = value;
8057	      } else {
8058	        defineProperty(target, property, value);
8059	      }
8060	    } else {
8061	      target.$attrs[name] = value;
8062	    }
8063	  }
8064	};
8065
8066	/**
8067	 * Returns the named property of the given element
8068	 *
8069	 * @param  {Object} target
8070	 * @param  {String} name
8071	 *
8072	 * @return {Object}
8073	 */
8074	Properties.prototype.get = function(target, name) {
8075
8076	  var property = this.model.getPropertyDescriptor(target, name);
8077
8078	  if (!property) {
8079	    return target.$attrs[name];
8080	  }
8081
8082	  var propertyName = property.name;
8083
8084	  // check if access to collection property and lazily initialize it
8085	  if (!target[propertyName] && property.isMany) {
8086	    defineProperty(target, property, []);
8087	  }
8088
8089	  return target[propertyName];
8090	};
8091
8092
8093	/**
8094	 * Define a property on the target element
8095	 *
8096	 * @param  {Object} target
8097	 * @param  {String} name
8098	 * @param  {Object} options
8099	 */
8100	Properties.prototype.define = function(target, name, options) {
8101	  Object.defineProperty(target, name, options);
8102	};
8103
8104
8105	/**
8106	 * Define the descriptor for an element
8107	 */
8108	Properties.prototype.defineDescriptor = function(target, descriptor) {
8109	  this.define(target, '$descriptor', { value: descriptor });
8110	};
8111
8112	/**
8113	 * Define the model for an element
8114	 */
8115	Properties.prototype.defineModel = function(target, model) {
8116	  this.define(target, '$model', { value: model });
8117	};
8118
8119
8120	function isUndefined(val) {
8121	  return typeof val === 'undefined';
8122	}
8123
8124	function defineProperty(target, property, value) {
8125	  Object.defineProperty(target, property.name, {
8126	    enumerable: !property.isReference,
8127	    writable: true,
8128	    value: value,
8129	    configurable: true
8130	  });
8131	}
8132
8133	//// Moddle implementation /////////////////////////////////////////////////
8134
8135	/**
8136	 * @class Moddle
8137	 *
8138	 * A model that can be used to create elements of a specific type.
8139	 *
8140	 * @example
8141	 *
8142	 * var Moddle = require('moddle');
8143	 *
8144	 * var pkg = {
8145	 *   name: 'mypackage',
8146	 *   prefix: 'my',
8147	 *   types: [
8148	 *     { name: 'Root' }
8149	 *   ]
8150	 * };
8151	 *
8152	 * var moddle = new Moddle([pkg]);
8153	 *
8154	 * @param {Array<Package>} packages the packages to contain
8155	 */
8156	function Moddle(packages) {
8157
8158	  this.properties = new Properties(this);
8159
8160	  this.factory = new Factory(this, this.properties);
8161	  this.registry = new Registry(packages, this.properties);
8162
8163	  this.typeCache = {};
8164	}
8165
8166
8167	/**
8168	 * Create an instance of the specified type.
8169	 *
8170	 * @method Moddle#create
8171	 *
8172	 * @example
8173	 *
8174	 * var foo = moddle.create('my:Foo');
8175	 * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
8176	 *
8177	 * @param  {String|Object} descriptor the type descriptor or name know to the model
8178	 * @param  {Object} attrs   a number of attributes to initialize the model instance with
8179	 * @return {Object}         model instance
8180	 */
8181	Moddle.prototype.create = function(descriptor, attrs) {
8182	  var Type = this.getType(descriptor);
8183
8184	  if (!Type) {
8185	    throw new Error('unknown type <' + descriptor + '>');
8186	  }
8187
8188	  return new Type(attrs);
8189	};
8190
8191
8192	/**
8193	 * Returns the type representing a given descriptor
8194	 *
8195	 * @method Moddle#getType
8196	 *
8197	 * @example
8198	 *
8199	 * var Foo = moddle.getType('my:Foo');
8200	 * var foo = new Foo({ 'id' : 'FOO_1' });
8201	 *
8202	 * @param  {String|Object} descriptor the type descriptor or name know to the model
8203	 * @return {Object}         the type representing the descriptor
8204	 */
8205	Moddle.prototype.getType = function(descriptor) {
8206
8207	  var cache = this.typeCache;
8208
8209	  var name = isString(descriptor) ? descriptor : descriptor.ns.name;
8210
8211	  var type = cache[name];
8212
8213	  if (!type) {
8214	    descriptor = this.registry.getEffectiveDescriptor(name);
8215	    type = cache[name] = this.factory.createType(descriptor);
8216	  }
8217
8218	  return type;
8219	};
8220
8221
8222	/**
8223	 * Creates an any-element type to be used within model instances.
8224	 *
8225	 * This can be used to create custom elements that lie outside the meta-model.
8226	 * The created element contains all the meta-data required to serialize it
8227	 * as part of meta-model elements.
8228	 *
8229	 * @method Moddle#createAny
8230	 *
8231	 * @example
8232	 *
8233	 * var foo = moddle.createAny('vendor:Foo', 'http://vendor', {
8234	 *   value: 'bar'
8235	 * });
8236	 *
8237	 * var container = moddle.create('my:Container', 'http://my', {
8238	 *   any: [ foo ]
8239	 * });
8240	 *
8241	 * // go ahead and serialize the stuff
8242	 *
8243	 *
8244	 * @param  {String} name  the name of the element
8245	 * @param  {String} nsUri the namespace uri of the element
8246	 * @param  {Object} [properties] a map of properties to initialize the instance with
8247	 * @return {Object} the any type instance
8248	 */
8249	Moddle.prototype.createAny = function(name, nsUri, properties) {
8250
8251	  var nameNs = parseName(name);
8252
8253	  var element = {
8254	    $type: name,
8255	    $instanceOf: function(type) {
8256	      return type === this.$type;
8257	    }
8258	  };
8259
8260	  var descriptor = {
8261	    name: name,
8262	    isGeneric: true,
8263	    ns: {
8264	      prefix: nameNs.prefix,
8265	      localName: nameNs.localName,
8266	      uri: nsUri
8267	    }
8268	  };
8269
8270	  this.properties.defineDescriptor(element, descriptor);
8271	  this.properties.defineModel(element, this);
8272	  this.properties.define(element, '$parent', { enumerable: false, writable: true });
8273	  this.properties.define(element, '$instanceOf', { enumerable: false, writable: true });
8274
8275	  forEach(properties, function(a, key) {
8276	    if (isObject(a) && a.value !== undefined) {
8277	      element[a.name] = a.value;
8278	    } else {
8279	      element[key] = a;
8280	    }
8281	  });
8282
8283	  return element;
8284	};
8285
8286	/**
8287	 * Returns a registered package by uri or prefix
8288	 *
8289	 * @return {Object} the package
8290	 */
8291	Moddle.prototype.getPackage = function(uriOrPrefix) {
8292	  return this.registry.getPackage(uriOrPrefix);
8293	};
8294
8295	/**
8296	 * Returns a snapshot of all known packages
8297	 *
8298	 * @return {Object} the package
8299	 */
8300	Moddle.prototype.getPackages = function() {
8301	  return this.registry.getPackages();
8302	};
8303
8304	/**
8305	 * Returns the descriptor for an element
8306	 */
8307	Moddle.prototype.getElementDescriptor = function(element) {
8308	  return element.$descriptor;
8309	};
8310
8311	/**
8312	 * Returns true if the given descriptor or instance
8313	 * represents the given type.
8314	 *
8315	 * May be applied to this, if element is omitted.
8316	 */
8317	Moddle.prototype.hasType = function(element, type) {
8318	  if (type === undefined) {
8319	    type = element;
8320	    element = this;
8321	  }
8322
8323	  var descriptor = element.$model.getElementDescriptor(element);
8324
8325	  return (type in descriptor.allTypesByName);
8326	};
8327
8328	/**
8329	 * Returns the descriptor of an elements named property
8330	 */
8331	Moddle.prototype.getPropertyDescriptor = function(element, property) {
8332	  return this.getElementDescriptor(element).propertiesByName[property];
8333	};
8334
8335	/**
8336	 * Returns a mapped type's descriptor
8337	 */
8338	Moddle.prototype.getTypeDescriptor = function(type) {
8339	  return this.registry.typeMap[type];
8340	};
8341
8342	var fromCharCode = String.fromCharCode;
8343
8344	var hasOwnProperty = Object.prototype.hasOwnProperty;
8345
8346	var ENTITY_PATTERN = /&#(\d+);|&#x([0-9a-f]+);|&(\w+);/ig;
8347
8348	var ENTITY_MAPPING = {
8349	  'amp': '&',
8350	  'apos': '\'',
8351	  'gt': '>',
8352	  'lt': '<',
8353	  'quot': '"'
8354	};
8355
8356	// map UPPERCASE variants of supported special chars
8357	Object.keys(ENTITY_MAPPING).forEach(function(k) {
8358	  ENTITY_MAPPING[k.toUpperCase()] = ENTITY_MAPPING[k];
8359	});
8360
8361
8362	function replaceEntities(_, d, x, z) {
8363
8364	  // reserved names, i.e. &nbsp;
8365	  if (z) {
8366	    if (hasOwnProperty.call(ENTITY_MAPPING, z)) {
8367	      return ENTITY_MAPPING[z];
8368	    } else {
8369
8370	      // fall back to original value
8371	      return '&' + z + ';';
8372	    }
8373	  }
8374
8375	  // decimal encoded char
8376	  if (d) {
8377	    return fromCharCode(d);
8378	  }
8379
8380	  // hex encoded char
8381	  return fromCharCode(parseInt(x, 16));
8382	}
8383
8384
8385	/**
8386	 * A basic entity decoder that can decode a minimal
8387	 * sub-set of reserved names (&amp;) as well as
8388	 * hex (&#xaaf;) and decimal (&#1231;) encoded characters.
8389	 *
8390	 * @param {string} str
8391	 *
8392	 * @return {string} decoded string
8393	 */
8394	function decodeEntities(s) {
8395	  if (s.length > 3 && s.indexOf('&') !== -1) {
8396	    return s.replace(ENTITY_PATTERN, replaceEntities);
8397	  }
8398
8399	  return s;
8400	}
8401
8402	var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance';
8403	var XSI_PREFIX = 'xsi';
8404	var XSI_TYPE$1 = 'xsi:type';
8405
8406	var NON_WHITESPACE_OUTSIDE_ROOT_NODE = 'non-whitespace outside of root node';
8407
8408	function error$2(msg) {
8409	  return new Error(msg);
8410	}
8411
8412	function missingNamespaceForPrefix(prefix) {
8413	  return 'missing namespace for prefix <' + prefix + '>';
8414	}
8415
8416	function getter(getFn) {
8417	  return {
8418	    'get': getFn,
8419	    'enumerable': true
8420	  };
8421	}
8422
8423	function cloneNsMatrix(nsMatrix) {
8424	  var clone = {}, key;
8425	  for (key in nsMatrix) {
8426	    clone[key] = nsMatrix[key];
8427	  }
8428	  return clone;
8429	}
8430
8431	function uriPrefix(prefix) {
8432	  return prefix + '$uri';
8433	}
8434
8435	function buildNsMatrix(nsUriToPrefix) {
8436	  var nsMatrix = {},
8437	      uri,
8438	      prefix;
8439
8440	  for (uri in nsUriToPrefix) {
8441	    prefix = nsUriToPrefix[uri];
8442	    nsMatrix[prefix] = prefix;
8443	    nsMatrix[uriPrefix(prefix)] = uri;
8444	  }
8445
8446	  return nsMatrix;
8447	}
8448
8449	function noopGetContext() {
8450	  return { 'line': 0, 'column': 0 };
8451	}
8452
8453	function throwFunc(err) {
8454	  throw err;
8455	}
8456
8457	/**
8458	 * Creates a new parser with the given options.
8459	 *
8460	 * @constructor
8461	 *
8462	 * @param  {!Object<string, ?>=} options
8463	 */
8464	function Parser(options) {
8465
8466	  if (!this) {
8467	    return new Parser(options);
8468	  }
8469
8470	  var proxy = options && options['proxy'];
8471
8472	  var onText,
8473	      onOpenTag,
8474	      onCloseTag,
8475	      onCDATA,
8476	      onError = throwFunc,
8477	      onWarning,
8478	      onComment,
8479	      onQuestion,
8480	      onAttention;
8481
8482	  var getContext = noopGetContext;
8483
8484	  /**
8485	   * Do we need to parse the current elements attributes for namespaces?
8486	   *
8487	   * @type {boolean}
8488	   */
8489	  var maybeNS = false;
8490
8491	  /**
8492	   * Do we process namespaces at all?
8493	   *
8494	   * @type {boolean}
8495	   */
8496	  var isNamespace = false;
8497
8498	  /**
8499	   * The caught error returned on parse end
8500	   *
8501	   * @type {Error}
8502	   */
8503	  var returnError = null;
8504
8505	  /**
8506	   * Should we stop parsing?
8507	   *
8508	   * @type {boolean}
8509	   */
8510	  var parseStop = false;
8511
8512	  /**
8513	   * A map of { uri: prefix } used by the parser.
8514	   *
8515	   * This map will ensure we can normalize prefixes during processing;
8516	   * for each uri, only one prefix will be exposed to the handlers.
8517	   *
8518	   * @type {!Object<string, string>}}
8519	   */
8520	  var nsUriToPrefix;
8521
8522	  /**
8523	   * Handle parse error.
8524	   *
8525	   * @param  {string|Error} err
8526	   */
8527	  function handleError(err) {
8528	    if (!(err instanceof Error)) {
8529	      err = error$2(err);
8530	    }
8531
8532	    returnError = err;
8533
8534	    onError(err, getContext);
8535	  }
8536
8537	  /**
8538	   * Handle parse error.
8539	   *
8540	   * @param  {string|Error} err
8541	   */
8542	  function handleWarning(err) {
8543
8544	    if (!onWarning) {
8545	      return;
8546	    }
8547
8548	    if (!(err instanceof Error)) {
8549	      err = error$2(err);
8550	    }
8551
8552	    onWarning(err, getContext);
8553	  }
8554
8555	  /**
8556	   * Register parse listener.
8557	   *
8558	   * @param  {string}   name
8559	   * @param  {Function} cb
8560	   *
8561	   * @return {Parser}
8562	   */
8563	  this['on'] = function(name, cb) {
8564
8565	    if (typeof cb !== 'function') {
8566	      throw error$2('required args <name, cb>');
8567	    }
8568
8569	    switch (name) {
8570	    case 'openTag': onOpenTag = cb; break;
8571	    case 'text': onText = cb; break;
8572	    case 'closeTag': onCloseTag = cb; break;
8573	    case 'error': onError = cb; break;
8574	    case 'warn': onWarning = cb; break;
8575	    case 'cdata': onCDATA = cb; break;
8576	    case 'attention': onAttention = cb; break; // <!XXXXX zzzz="eeee">
8577	    case 'question': onQuestion = cb; break; // <? ....  ?>
8578	    case 'comment': onComment = cb; break;
8579	    default:
8580	      throw error$2('unsupported event: ' + name);
8581	    }
8582
8583	    return this;
8584	  };
8585
8586	  /**
8587	   * Set the namespace to prefix mapping.
8588	   *
8589	   * @example
8590	   *
8591	   * parser.ns({
8592	   *   'http://foo': 'foo',
8593	   *   'http://bar': 'bar'
8594	   * });
8595	   *
8596	   * @param  {!Object<string, string>} nsMap
8597	   *
8598	   * @return {Parser}
8599	   */
8600	  this['ns'] = function(nsMap) {
8601
8602	    if (typeof nsMap === 'undefined') {
8603	      nsMap = {};
8604	    }
8605
8606	    if (typeof nsMap !== 'object') {
8607	      throw error$2('required args <nsMap={}>');
8608	    }
8609
8610	    var _nsUriToPrefix = {}, k;
8611
8612	    for (k in nsMap) {
8613	      _nsUriToPrefix[k] = nsMap[k];
8614	    }
8615
8616	    // FORCE default mapping for schema instance
8617	    _nsUriToPrefix[XSI_URI] = XSI_PREFIX;
8618
8619	    isNamespace = true;
8620	    nsUriToPrefix = _nsUriToPrefix;
8621
8622	    return this;
8623	  };
8624
8625	  /**
8626	   * Parse xml string.
8627	   *
8628	   * @param  {string} xml
8629	   *
8630	   * @return {Error} returnError, if not thrown
8631	   */
8632	  this['parse'] = function(xml) {
8633	    if (typeof xml !== 'string') {
8634	      throw error$2('required args <xml=string>');
8635	    }
8636
8637	    returnError = null;
8638
8639	    parse(xml);
8640
8641	    getContext = noopGetContext;
8642	    parseStop = false;
8643
8644	    return returnError;
8645	  };
8646
8647	  /**
8648	   * Stop parsing.
8649	   */
8650	  this['stop'] = function() {
8651	    parseStop = true;
8652	  };
8653
8654	  /**
8655	   * Parse string, invoking configured listeners on element.
8656	   *
8657	   * @param  {string} xml
8658	   */
8659	  function parse(xml) {
8660	    var nsMatrixStack = isNamespace ? [] : null,
8661	        nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
8662	        _nsMatrix,
8663	        nodeStack = [],
8664	        anonymousNsCount = 0,
8665	        tagStart = false,
8666	        tagEnd = false,
8667	        i = 0, j = 0,
8668	        x, y, q, w, v,
8669	        xmlns,
8670	        elementName,
8671	        _elementName,
8672	        elementProxy
8673	        ;
8674
8675	    var attrsString = '',
8676	        attrsStart = 0,
8677	        cachedAttrs // false = parsed with errors, null = needs parsing
8678	        ;
8679
8680	    /**
8681	     * Parse attributes on demand and returns the parsed attributes.
8682	     *
8683	     * Return semantics: (1) `false` on attribute parse error,
8684	     * (2) object hash on extracted attrs.
8685	     *
8686	     * @return {boolean|Object}
8687	     */
8688	    function getAttrs() {
8689	      if (cachedAttrs !== null) {
8690	        return cachedAttrs;
8691	      }
8692
8693	      var nsUri,
8694	          nsUriPrefix,
8695	          nsName,
8696	          defaultAlias = isNamespace && nsMatrix['xmlns'],
8697	          attrList = isNamespace && maybeNS ? [] : null,
8698	          i = attrsStart,
8699	          s = attrsString,
8700	          l = s.length,
8701	          hasNewMatrix,
8702	          newalias,
8703	          value,
8704	          alias,
8705	          name,
8706	          attrs = {},
8707	          seenAttrs = {},
8708	          skipAttr,
8709	          w,
8710	          j;
8711
8712	      parseAttr:
8713	      for (; i < l; i++) {
8714	        skipAttr = false;
8715	        w = s.charCodeAt(i);
8716
8717	        if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE={ \f\n\r\t\v}
8718	          continue;
8719	        }
8720
8721	        // wait for non whitespace character
8722	        if (w < 65 || w > 122 || (w > 90 && w < 97)) {
8723	          if (w !== 95 && w !== 58) { // char 95"_" 58":"
8724	            handleWarning('illegal first char attribute name');
8725	            skipAttr = true;
8726	          }
8727	        }
8728
8729	        // parse attribute name
8730	        for (j = i + 1; j < l; j++) {
8731	          w = s.charCodeAt(j);
8732
8733	          if (
8734	            w > 96 && w < 123 ||
8735	            w > 64 && w < 91 ||
8736	            w > 47 && w < 59 ||
8737	            w === 46 || // '.'
8738	            w === 45 || // '-'
8739	            w === 95 // '_'
8740	          ) {
8741	            continue;
8742	          }
8743
8744	          // unexpected whitespace
8745	          if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
8746	            handleWarning('missing attribute value');
8747	            i = j;
8748
8749	            continue parseAttr;
8750	          }
8751
8752	          // expected "="
8753	          if (w === 61) { // "=" == 61
8754	            break;
8755	          }
8756
8757	          handleWarning('illegal attribute name char');
8758	          skipAttr = true;
8759	        }
8760
8761	        name = s.substring(i, j);
8762
8763	        if (name === 'xmlns:xmlns') {
8764	          handleWarning('illegal declaration of xmlns');
8765	          skipAttr = true;
8766	        }
8767
8768	        w = s.charCodeAt(j + 1);
8769
8770	        if (w === 34) { // '"'
8771	          j = s.indexOf('"', i = j + 2);
8772
8773	          if (j === -1) {
8774	            j = s.indexOf('\'', i);
8775
8776	            if (j !== -1) {
8777	              handleWarning('attribute value quote missmatch');
8778	              skipAttr = true;
8779	            }
8780	          }
8781
8782	        } else if (w === 39) { // "'"
8783	          j = s.indexOf('\'', i = j + 2);
8784
8785	          if (j === -1) {
8786	            j = s.indexOf('"', i);
8787
8788	            if (j !== -1) {
8789	              handleWarning('attribute value quote missmatch');
8790	              skipAttr = true;
8791	            }
8792	          }
8793
8794	        } else {
8795	          handleWarning('missing attribute value quotes');
8796	          skipAttr = true;
8797
8798	          // skip to next space
8799	          for (j = j + 1; j < l; j++) {
8800	            w = s.charCodeAt(j + 1);
8801
8802	            if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
8803	              break;
8804	            }
8805	          }
8806
8807	        }
8808
8809	        if (j === -1) {
8810	          handleWarning('missing closing quotes');
8811
8812	          j = l;
8813	          skipAttr = true;
8814	        }
8815
8816	        if (!skipAttr) {
8817	          value = s.substring(i, j);
8818	        }
8819
8820	        i = j;
8821
8822	        // ensure SPACE follows attribute
8823	        // skip illegal content otherwise
8824	        // example a="b"c
8825	        for (; j + 1 < l; j++) {
8826	          w = s.charCodeAt(j + 1);
8827
8828	          if (w === 32 || (w < 14 && w > 8)) { // WHITESPACE
8829	            break;
8830	          }
8831
8832	          // FIRST ILLEGAL CHAR
8833	          if (i === j) {
8834	            handleWarning('illegal character after attribute end');
8835	            skipAttr = true;
8836	          }
8837	        }
8838
8839	        // advance cursor to next attribute
8840	        i = j + 1;
8841
8842	        if (skipAttr) {
8843	          continue parseAttr;
8844	        }
8845
8846	        // check attribute re-declaration
8847	        if (name in seenAttrs) {
8848	          handleWarning('attribute <' + name + '> already defined');
8849	          continue;
8850	        }
8851
8852	        seenAttrs[name] = true;
8853
8854	        if (!isNamespace) {
8855	          attrs[name] = value;
8856	          continue;
8857	        }
8858
8859	        // try to extract namespace information
8860	        if (maybeNS) {
8861	          newalias = (
8862	            name === 'xmlns'
8863	              ? 'xmlns'
8864	              : (name.charCodeAt(0) === 120 && name.substr(0, 6) === 'xmlns:')
8865	                ? name.substr(6)
8866	                : null
8867	          );
8868
8869	          // handle xmlns(:alias) assignment
8870	          if (newalias !== null) {
8871	            nsUri = decodeEntities(value);
8872	            nsUriPrefix = uriPrefix(newalias);
8873
8874	            alias = nsUriToPrefix[nsUri];
8875
8876	            if (!alias) {
8877
8878	              // no prefix defined or prefix collision
8879	              if (
8880	                (newalias === 'xmlns') ||
8881	                (nsUriPrefix in nsMatrix && nsMatrix[nsUriPrefix] !== nsUri)
8882	              ) {
8883
8884	                // alocate free ns prefix
8885	                do {
8886	                  alias = 'ns' + (anonymousNsCount++);
8887	                } while (typeof nsMatrix[alias] !== 'undefined');
8888	              } else {
8889	                alias = newalias;
8890	              }
8891
8892	              nsUriToPrefix[nsUri] = alias;
8893	            }
8894
8895	            if (nsMatrix[newalias] !== alias) {
8896	              if (!hasNewMatrix) {
8897	                nsMatrix = cloneNsMatrix(nsMatrix);
8898	                hasNewMatrix = true;
8899	              }
8900
8901	              nsMatrix[newalias] = alias;
8902	              if (newalias === 'xmlns') {
8903	                nsMatrix[uriPrefix(alias)] = nsUri;
8904	                defaultAlias = alias;
8905	              }
8906
8907	              nsMatrix[nsUriPrefix] = nsUri;
8908	            }
8909
8910	            // expose xmlns(:asd)="..." in attributes
8911	            attrs[name] = value;
8912	            continue;
8913	          }
8914
8915	          // collect attributes until all namespace
8916	          // declarations are processed
8917	          attrList.push(name, value);
8918	          continue;
8919
8920	        } /** end if (maybeNs) */
8921
8922	        // handle attributes on element without
8923	        // namespace declarations
8924	        w = name.indexOf(':');
8925	        if (w === -1) {
8926	          attrs[name] = value;
8927	          continue;
8928	        }
8929
8930	        // normalize ns attribute name
8931	        if (!(nsName = nsMatrix[name.substring(0, w)])) {
8932	          handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
8933	          continue;
8934	        }
8935
8936	        name = defaultAlias === nsName
8937	          ? name.substr(w + 1)
8938	          : nsName + name.substr(w);
8939
8940	        // end: normalize ns attribute name
8941
8942	        // normalize xsi:type ns attribute value
8943	        if (name === XSI_TYPE$1) {
8944	          w = value.indexOf(':');
8945
8946	          if (w !== -1) {
8947	            nsName = value.substring(0, w);
8948
8949	            // handle default prefixes, i.e. xs:String gracefully
8950	            nsName = nsMatrix[nsName] || nsName;
8951	            value = nsName + value.substring(w);
8952	          } else {
8953	            value = defaultAlias + ':' + value;
8954	          }
8955	        }
8956
8957	        // end: normalize xsi:type ns attribute value
8958
8959	        attrs[name] = value;
8960	      }
8961
8962
8963	      // handle deferred, possibly namespaced attributes
8964	      if (maybeNS) {
8965
8966	        // normalize captured attributes
8967	        for (i = 0, l = attrList.length; i < l; i++) {
8968
8969	          name = attrList[i++];
8970	          value = attrList[i];
8971
8972	          w = name.indexOf(':');
8973
8974	          if (w !== -1) {
8975
8976	            // normalize ns attribute name
8977	            if (!(nsName = nsMatrix[name.substring(0, w)])) {
8978	              handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
8979	              continue;
8980	            }
8981
8982	            name = defaultAlias === nsName
8983	              ? name.substr(w + 1)
8984	              : nsName + name.substr(w);
8985
8986	            // end: normalize ns attribute name
8987
8988	            // normalize xsi:type ns attribute value
8989	            if (name === XSI_TYPE$1) {
8990	              w = value.indexOf(':');
8991
8992	              if (w !== -1) {
8993	                nsName = value.substring(0, w);
8994
8995	                // handle default prefixes, i.e. xs:String gracefully
8996	                nsName = nsMatrix[nsName] || nsName;
8997	                value = nsName + value.substring(w);
8998	              } else {
8999	                value = defaultAlias + ':' + value;
9000	              }
9001	            }
9002
9003	            // end: normalize xsi:type ns attribute value
9004	          }
9005
9006	          attrs[name] = value;
9007	        }
9008
9009	        // end: normalize captured attributes
9010	      }
9011
9012	      return cachedAttrs = attrs;
9013	    }
9014
9015	    /**
9016	     * Extract the parse context { line, column, part }
9017	     * from the current parser position.
9018	     *
9019	     * @return {Object} parse context
9020	     */
9021	    function getParseContext() {
9022	      var splitsRe = /(\r\n|\r|\n)/g;
9023
9024	      var line = 0;
9025	      var column = 0;
9026	      var startOfLine = 0;
9027	      var endOfLine = j;
9028	      var match;
9029	      var data;
9030
9031	      while (i >= startOfLine) {
9032
9033	        match = splitsRe.exec(xml);
9034
9035	        if (!match) {
9036	          break;
9037	        }
9038
9039	        // end of line = (break idx + break chars)
9040	        endOfLine = match[0].length + match.index;
9041
9042	        if (endOfLine > i) {
9043	          break;
9044	        }
9045
9046	        // advance to next line
9047	        line += 1;
9048
9049	        startOfLine = endOfLine;
9050	      }
9051
9052	      // EOF errors
9053	      if (i == -1) {
9054	        column = endOfLine;
9055	        data = xml.substring(j);
9056	      } else
9057
9058	      // start errors
9059	      if (j === 0) {
9060	        data = xml.substring(j, i);
9061	      }
9062
9063	      // other errors
9064	      else {
9065	        column = i - startOfLine;
9066	        data = (j == -1 ? xml.substring(i) : xml.substring(i, j + 1));
9067	      }
9068
9069	      return {
9070	        'data': data,
9071	        'line': line,
9072	        'column': column
9073	      };
9074	    }
9075
9076	    getContext = getParseContext;
9077
9078
9079	    if (proxy) {
9080	      elementProxy = Object.create({}, {
9081	        'name': getter(function() {
9082	          return elementName;
9083	        }),
9084	        'originalName': getter(function() {
9085	          return _elementName;
9086	        }),
9087	        'attrs': getter(getAttrs),
9088	        'ns': getter(function() {
9089	          return nsMatrix;
9090	        })
9091	      });
9092	    }
9093
9094	    // actual parse logic
9095	    while (j !== -1) {
9096
9097	      if (xml.charCodeAt(j) === 60) { // "<"
9098	        i = j;
9099	      } else {
9100	        i = xml.indexOf('<', j);
9101	      }
9102
9103	      // parse end
9104	      if (i === -1) {
9105	        if (nodeStack.length) {
9106	          return handleError('unexpected end of file');
9107	        }
9108
9109	        if (j === 0) {
9110	          return handleError('missing start tag');
9111	        }
9112
9113	        if (j < xml.length) {
9114	          if (xml.substring(j).trim()) {
9115	            handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
9116	          }
9117	        }
9118
9119	        return;
9120	      }
9121
9122	      // parse text
9123	      if (j !== i) {
9124
9125	        if (nodeStack.length) {
9126	          if (onText) {
9127	            onText(xml.substring(j, i), decodeEntities, getContext);
9128
9129	            if (parseStop) {
9130	              return;
9131	            }
9132	          }
9133	        } else {
9134	          if (xml.substring(j, i).trim()) {
9135	            handleWarning(NON_WHITESPACE_OUTSIDE_ROOT_NODE);
9136
9137	            if (parseStop) {
9138	              return;
9139	            }
9140	          }
9141	        }
9142	      }
9143
9144	      w = xml.charCodeAt(i+1);
9145
9146	      // parse comments + CDATA
9147	      if (w === 33) { // "!"
9148	        q = xml.charCodeAt(i+2);
9149
9150	        // CDATA section
9151	        if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
9152	          j = xml.indexOf(']]>', i);
9153	          if (j === -1) {
9154	            return handleError('unclosed cdata');
9155	          }
9156
9157	          if (onCDATA) {
9158	            onCDATA(xml.substring(i + 9, j), getContext);
9159	            if (parseStop) {
9160	              return;
9161	            }
9162	          }
9163
9164	          j += 3;
9165	          continue;
9166	        }
9167
9168	        // comment
9169	        if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
9170	          j = xml.indexOf('-->', i);
9171	          if (j === -1) {
9172	            return handleError('unclosed comment');
9173	          }
9174
9175
9176	          if (onComment) {
9177	            onComment(xml.substring(i + 4, j), decodeEntities, getContext);
9178	            if (parseStop) {
9179	              return;
9180	            }
9181	          }
9182
9183	          j += 3;
9184	          continue;
9185	        }
9186	      }
9187
9188	      // parse question <? ... ?>
9189	      if (w === 63) { // "?"
9190	        j = xml.indexOf('?>', i);
9191	        if (j === -1) {
9192	          return handleError('unclosed question');
9193	        }
9194
9195	        if (onQuestion) {
9196	          onQuestion(xml.substring(i, j + 2), getContext);
9197	          if (parseStop) {
9198	            return;
9199	          }
9200	        }
9201
9202	        j += 2;
9203	        continue;
9204	      }
9205
9206	      // find matching closing tag for attention or standard tags
9207	      // for that we must skip through attribute values
9208	      // (enclosed in single or double quotes)
9209	      for (x = i + 1; ; x++) {
9210	        v = xml.charCodeAt(x);
9211	        if (isNaN(v)) {
9212	          j = -1;
9213	          return handleError('unclosed tag');
9214	        }
9215
9216	        // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
9217	        // skips the quoted string
9218	        // (double quotes) does not appear in a literal enclosed by (double quotes)
9219	        // (single quote) does not appear in a literal enclosed by (single quote)
9220	        if (v === 34) { //  '"'
9221	          q = xml.indexOf('"', x + 1);
9222	          x = q !== -1 ? q : x;
9223	        } else if (v === 39) { // "'"
9224	          q = xml.indexOf("'", x + 1);
9225	          x = q !== -1 ? q : x;
9226	        } else if (v === 62) { // '>'
9227	          j = x;
9228	          break;
9229	        }
9230	      }
9231
9232
9233	      // parse attention <! ...>
9234	      // previously comment and CDATA have already been parsed
9235	      if (w === 33) { // "!"
9236
9237	        if (onAttention) {
9238	          onAttention(xml.substring(i, j + 1), decodeEntities, getContext);
9239	          if (parseStop) {
9240	            return;
9241	          }
9242	        }
9243
9244	        j += 1;
9245	        continue;
9246	      }
9247
9248	      // don't process attributes;
9249	      // there are none
9250	      cachedAttrs = {};
9251
9252	      // if (xml.charCodeAt(i+1) === 47) { // </...
9253	      if (w === 47) { // </...
9254	        tagStart = false;
9255	        tagEnd = true;
9256
9257	        if (!nodeStack.length) {
9258	          return handleError('missing open tag');
9259	        }
9260
9261	        // verify open <-> close tag match
9262	        x = elementName = nodeStack.pop();
9263	        q = i + 2 + x.length;
9264
9265	        if (xml.substring(i + 2, q) !== x) {
9266	          return handleError('closing tag mismatch');
9267	        }
9268
9269	        // verify chars in close tag
9270	        for (; q < j; q++) {
9271	          w = xml.charCodeAt(q);
9272
9273	          if (w === 32 || (w > 8 && w < 14)) { // \f\n\r\t\v space
9274	            continue;
9275	          }
9276
9277	          return handleError('close tag');
9278	        }
9279
9280	      } else {
9281	        if (xml.charCodeAt(j - 1) === 47) { // .../>
9282	          x = elementName = xml.substring(i + 1, j - 1);
9283
9284	          tagStart = true;
9285	          tagEnd = true;
9286
9287	        } else {
9288	          x = elementName = xml.substring(i + 1, j);
9289
9290	          tagStart = true;
9291	          tagEnd = false;
9292	        }
9293
9294	        if (!(w > 96 && w < 123 || w > 64 && w < 91 || w === 95 || w === 58)) { // char 95"_" 58":"
9295	          return handleError('illegal first char nodeName');
9296	        }
9297
9298	        for (q = 1, y = x.length; q < y; q++) {
9299	          w = x.charCodeAt(q);
9300
9301	          if (w > 96 && w < 123 || w > 64 && w < 91 || w > 47 && w < 59 || w === 45 || w === 95 || w == 46) {
9302	            continue;
9303	          }
9304
9305	          if (w === 32 || (w < 14 && w > 8)) { // \f\n\r\t\v space
9306	            elementName = x.substring(0, q);
9307
9308	            // maybe there are attributes
9309	            cachedAttrs = null;
9310	            break;
9311	          }
9312
9313	          return handleError('invalid nodeName');
9314	        }
9315
9316	        if (!tagEnd) {
9317	          nodeStack.push(elementName);
9318	        }
9319	      }
9320
9321	      if (isNamespace) {
9322
9323	        _nsMatrix = nsMatrix;
9324
9325	        if (tagStart) {
9326
9327	          // remember old namespace
9328	          // unless we're self-closing
9329	          if (!tagEnd) {
9330	            nsMatrixStack.push(_nsMatrix);
9331	          }
9332
9333	          if (cachedAttrs === null) {
9334
9335	            // quick check, whether there may be namespace
9336	            // declarations on the node; if that is the case
9337	            // we need to eagerly parse the node attributes
9338	            if ((maybeNS = x.indexOf('xmlns', q) !== -1)) {
9339	              attrsStart = q;
9340	              attrsString = x;
9341
9342	              getAttrs();
9343
9344	              maybeNS = false;
9345	            }
9346	          }
9347	        }
9348
9349	        _elementName = elementName;
9350
9351	        w = elementName.indexOf(':');
9352	        if (w !== -1) {
9353	          xmlns = nsMatrix[elementName.substring(0, w)];
9354
9355	          // prefix given; namespace must exist
9356	          if (!xmlns) {
9357	            return handleError('missing namespace on <' + _elementName + '>');
9358	          }
9359
9360	          elementName = elementName.substr(w + 1);
9361	        } else {
9362	          xmlns = nsMatrix['xmlns'];
9363
9364	          // if no default namespace is defined,
9365	          // we'll import the element as anonymous.
9366	          //
9367	          // it is up to users to correct that to the document defined
9368	          // targetNamespace, or whatever their undersanding of the
9369	          // XML spec mandates.
9370	        }
9371
9372	        // adjust namespace prefixs as configured
9373	        if (xmlns) {
9374	          elementName = xmlns + ':' + elementName;
9375	        }
9376
9377	      }
9378
9379	      if (tagStart) {
9380	        attrsStart = q;
9381	        attrsString = x;
9382
9383	        if (onOpenTag) {
9384	          if (proxy) {
9385	            onOpenTag(elementProxy, decodeEntities, tagEnd, getContext);
9386	          } else {
9387	            onOpenTag(elementName, getAttrs, decodeEntities, tagEnd, getContext);
9388	          }
9389
9390	          if (parseStop) {
9391	            return;
9392	          }
9393	        }
9394
9395	      }
9396
9397	      if (tagEnd) {
9398
9399	        if (onCloseTag) {
9400	          onCloseTag(proxy ? elementProxy : elementName, decodeEntities, tagStart, getContext);
9401
9402	          if (parseStop) {
9403	            return;
9404	          }
9405	        }
9406
9407	        // restore old namespace
9408	        if (isNamespace) {
9409	          if (!tagStart) {
9410	            nsMatrix = nsMatrixStack.pop();
9411	          } else {
9412	            nsMatrix = _nsMatrix;
9413	          }
9414	        }
9415	      }
9416
9417	      j += 1;
9418	    }
9419	  } /** end parse */
9420
9421	}
9422
9423	function hasLowerCaseAlias(pkg) {
9424	  return pkg.xml && pkg.xml.tagAlias === 'lowerCase';
9425	}
9426
9427	var DEFAULT_NS_MAP = {
9428	  'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
9429	  'xml': 'http://www.w3.org/XML/1998/namespace'
9430	};
9431
9432	var XSI_TYPE = 'xsi:type';
9433
9434	function serializeFormat(element) {
9435	  return element.xml && element.xml.serialize;
9436	}
9437
9438	function serializeAsType(element) {
9439	  return serializeFormat(element) === XSI_TYPE;
9440	}
9441
9442	function serializeAsProperty(element) {
9443	  return serializeFormat(element) === 'property';
9444	}
9445
9446	function capitalize(str) {
9447	  return str.charAt(0).toUpperCase() + str.slice(1);
9448	}
9449
9450	function aliasToName(aliasNs, pkg) {
9451
9452	  if (!hasLowerCaseAlias(pkg)) {
9453	    return aliasNs.name;
9454	  }
9455
9456	  return aliasNs.prefix + ':' + capitalize(aliasNs.localName);
9457	}
9458
9459	function prefixedToName(nameNs, pkg) {
9460
9461	  var name = nameNs.name,
9462	      localName = nameNs.localName;
9463
9464	  var typePrefix = pkg.xml && pkg.xml.typePrefix;
9465
9466	  if (typePrefix && localName.indexOf(typePrefix) === 0) {
9467	    return nameNs.prefix + ':' + localName.slice(typePrefix.length);
9468	  } else {
9469	    return name;
9470	  }
9471	}
9472
9473	function normalizeXsiTypeName(name, model) {
9474
9475	  var nameNs = parseName(name);
9476	  var pkg = model.getPackage(nameNs.prefix);
9477
9478	  return prefixedToName(nameNs, pkg);
9479	}
9480
9481	function error$1(message) {
9482	  return new Error(message);
9483	}
9484
9485	/**
9486	 * Get the moddle descriptor for a given instance or type.
9487	 *
9488	 * @param  {ModdleElement|Function} element
9489	 *
9490	 * @return {Object} the moddle descriptor
9491	 */
9492	function getModdleDescriptor(element) {
9493	  return element.$descriptor;
9494	}
9495
9496
9497	/**
9498	 * A parse context.
9499	 *
9500	 * @class
9501	 *
9502	 * @param {Object} options
9503	 * @param {ElementHandler} options.rootHandler the root handler for parsing a document
9504	 * @param {boolean} [options.lax=false] whether or not to ignore invalid elements
9505	 */
9506	function Context(options) {
9507
9508	  /**
9509	   * @property {ElementHandler} rootHandler
9510	   */
9511
9512	  /**
9513	   * @property {Boolean} lax
9514	   */
9515
9516	  assign(this, options);
9517
9518	  this.elementsById = {};
9519	  this.references = [];
9520	  this.warnings = [];
9521
9522	  /**
9523	   * Add an unresolved reference.
9524	   *
9525	   * @param {Object} reference
9526	   */
9527	  this.addReference = function(reference) {
9528	    this.references.push(reference);
9529	  };
9530
9531	  /**
9532	   * Add a processed element.
9533	   *
9534	   * @param {ModdleElement} element
9535	   */
9536	  this.addElement = function(element) {
9537
9538	    if (!element) {
9539	      throw error$1('expected element');
9540	    }
9541
9542	    var elementsById = this.elementsById;
9543
9544	    var descriptor = getModdleDescriptor(element);
9545
9546	    var idProperty = descriptor.idProperty,
9547	        id;
9548
9549	    if (idProperty) {
9550	      id = element.get(idProperty.name);
9551
9552	      if (id) {
9553
9554	        // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
9555	        if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(id)) {
9556	          throw new Error('illegal ID <' + id + '>');
9557	        }
9558
9559	        if (elementsById[id]) {
9560	          throw error$1('duplicate ID <' + id + '>');
9561	        }
9562
9563	        elementsById[id] = element;
9564	      }
9565	    }
9566	  };
9567
9568	  /**
9569	   * Add an import warning.
9570	   *
9571	   * @param {Object} warning
9572	   * @param {String} warning.message
9573	   * @param {Error} [warning.error]
9574	   */
9575	  this.addWarning = function(warning) {
9576	    this.warnings.push(warning);
9577	  };
9578	}
9579
9580	function BaseHandler() {}
9581
9582	BaseHandler.prototype.handleEnd = function() {};
9583	BaseHandler.prototype.handleText = function() {};
9584	BaseHandler.prototype.handleNode = function() {};
9585
9586
9587	/**
9588	 * A simple pass through handler that does nothing except for
9589	 * ignoring all input it receives.
9590	 *
9591	 * This is used to ignore unknown elements and
9592	 * attributes.
9593	 */
9594	function NoopHandler() { }
9595
9596	NoopHandler.prototype = Object.create(BaseHandler.prototype);
9597
9598	NoopHandler.prototype.handleNode = function() {
9599	  return this;
9600	};
9601
9602	function BodyHandler() {}
9603
9604	BodyHandler.prototype = Object.create(BaseHandler.prototype);
9605
9606	BodyHandler.prototype.handleText = function(text) {
9607	  this.body = (this.body || '') + text;
9608	};
9609
9610	function ReferenceHandler(property, context) {
9611	  this.property = property;
9612	  this.context = context;
9613	}
9614
9615	ReferenceHandler.prototype = Object.create(BodyHandler.prototype);
9616
9617	ReferenceHandler.prototype.handleNode = function(node) {
9618
9619	  if (this.element) {
9620	    throw error$1('expected no sub nodes');
9621	  } else {
9622	    this.element = this.createReference(node);
9623	  }
9624
9625	  return this;
9626	};
9627
9628	ReferenceHandler.prototype.handleEnd = function() {
9629	  this.element.id = this.body;
9630	};
9631
9632	ReferenceHandler.prototype.createReference = function(node) {
9633	  return {
9634	    property: this.property.ns.name,
9635	    id: ''
9636	  };
9637	};
9638
9639	function ValueHandler(propertyDesc, element) {
9640	  this.element = element;
9641	  this.propertyDesc = propertyDesc;
9642	}
9643
9644	ValueHandler.prototype = Object.create(BodyHandler.prototype);
9645
9646	ValueHandler.prototype.handleEnd = function() {
9647
9648	  var value = this.body || '',
9649	      element = this.element,
9650	      propertyDesc = this.propertyDesc;
9651
9652	  value = coerceType(propertyDesc.type, value);
9653
9654	  if (propertyDesc.isMany) {
9655	    element.get(propertyDesc.name).push(value);
9656	  } else {
9657	    element.set(propertyDesc.name, value);
9658	  }
9659	};
9660
9661
9662	function BaseElementHandler() {}
9663
9664	BaseElementHandler.prototype = Object.create(BodyHandler.prototype);
9665
9666	BaseElementHandler.prototype.handleNode = function(node) {
9667	  var parser = this,
9668	      element = this.element;
9669
9670	  if (!element) {
9671	    element = this.element = this.createElement(node);
9672
9673	    this.context.addElement(element);
9674	  } else {
9675	    parser = this.handleChild(node);
9676	  }
9677
9678	  return parser;
9679	};
9680
9681	/**
9682	 * @class Reader.ElementHandler
9683	 *
9684	 */
9685	function ElementHandler(model, typeName, context) {
9686	  this.model = model;
9687	  this.type = model.getType(typeName);
9688	  this.context = context;
9689	}
9690
9691	ElementHandler.prototype = Object.create(BaseElementHandler.prototype);
9692
9693	ElementHandler.prototype.addReference = function(reference) {
9694	  this.context.addReference(reference);
9695	};
9696
9697	ElementHandler.prototype.handleText = function(text) {
9698
9699	  var element = this.element,
9700	      descriptor = getModdleDescriptor(element),
9701	      bodyProperty = descriptor.bodyProperty;
9702
9703	  if (!bodyProperty) {
9704	    throw error$1('unexpected body text <' + text + '>');
9705	  }
9706
9707	  BodyHandler.prototype.handleText.call(this, text);
9708	};
9709
9710	ElementHandler.prototype.handleEnd = function() {
9711
9712	  var value = this.body,
9713	      element = this.element,
9714	      descriptor = getModdleDescriptor(element),
9715	      bodyProperty = descriptor.bodyProperty;
9716
9717	  if (bodyProperty && value !== undefined) {
9718	    value = coerceType(bodyProperty.type, value);
9719	    element.set(bodyProperty.name, value);
9720	  }
9721	};
9722
9723	/**
9724	 * Create an instance of the model from the given node.
9725	 *
9726	 * @param  {Element} node the xml node
9727	 */
9728	ElementHandler.prototype.createElement = function(node) {
9729	  var attributes = node.attributes,
9730	      Type = this.type,
9731	      descriptor = getModdleDescriptor(Type),
9732	      context = this.context,
9733	      instance = new Type({}),
9734	      model = this.model,
9735	      propNameNs;
9736
9737	  forEach(attributes, function(value, name) {
9738
9739	    var prop = descriptor.propertiesByName[name],
9740	        values;
9741
9742	    if (prop && prop.isReference) {
9743
9744	      if (!prop.isMany) {
9745	        context.addReference({
9746	          element: instance,
9747	          property: prop.ns.name,
9748	          id: value
9749	        });
9750	      } else {
9751
9752	        // IDREFS: parse references as whitespace-separated list
9753	        values = value.split(' ');
9754
9755	        forEach(values, function(v) {
9756	          context.addReference({
9757	            element: instance,
9758	            property: prop.ns.name,
9759	            id: v
9760	          });
9761	        });
9762	      }
9763
9764	    } else {
9765	      if (prop) {
9766	        value = coerceType(prop.type, value);
9767	      } else
9768	      if (name !== 'xmlns') {
9769	        propNameNs = parseName(name, descriptor.ns.prefix);
9770
9771	        // check whether attribute is defined in a well-known namespace
9772	        // if that is the case we emit a warning to indicate potential misuse
9773	        if (model.getPackage(propNameNs.prefix)) {
9774
9775	          context.addWarning({
9776	            message: 'unknown attribute <' + name + '>',
9777	            element: instance,
9778	            property: name,
9779	            value: value
9780	          });
9781	        }
9782	      }
9783
9784	      instance.set(name, value);
9785	    }
9786	  });
9787
9788	  return instance;
9789	};
9790
9791	ElementHandler.prototype.getPropertyForNode = function(node) {
9792
9793	  var name = node.name;
9794	  var nameNs = parseName(name);
9795
9796	  var type = this.type,
9797	      model = this.model,
9798	      descriptor = getModdleDescriptor(type);
9799
9800	  var propertyName = nameNs.name,
9801	      property = descriptor.propertiesByName[propertyName],
9802	      elementTypeName,
9803	      elementType;
9804
9805	  // search for properties by name first
9806
9807	  if (property && !property.isAttr) {
9808
9809	    if (serializeAsType(property)) {
9810	      elementTypeName = node.attributes[XSI_TYPE];
9811
9812	      // xsi type is optional, if it does not exists the
9813	      // default type is assumed
9814	      if (elementTypeName) {
9815
9816	        // take possible type prefixes from XML
9817	        // into account, i.e.: xsi:type="t{ActualType}"
9818	        elementTypeName = normalizeXsiTypeName(elementTypeName, model);
9819
9820	        elementType = model.getType(elementTypeName);
9821
9822	        return assign({}, property, {
9823	          effectiveType: getModdleDescriptor(elementType).name
9824	        });
9825	      }
9826	    }
9827
9828	    // search for properties by name first
9829	    return property;
9830	  }
9831
9832	  var pkg = model.getPackage(nameNs.prefix);
9833
9834	  if (pkg) {
9835	    elementTypeName = aliasToName(nameNs, pkg);
9836	    elementType = model.getType(elementTypeName);
9837
9838	    // search for collection members later
9839	    property = find(descriptor.properties, function(p) {
9840	      return !p.isVirtual && !p.isReference && !p.isAttribute && elementType.hasType(p.type);
9841	    });
9842
9843	    if (property) {
9844	      return assign({}, property, {
9845	        effectiveType: getModdleDescriptor(elementType).name
9846	      });
9847	    }
9848	  } else {
9849
9850	    // parse unknown element (maybe extension)
9851	    property = find(descriptor.properties, function(p) {
9852	      return !p.isReference && !p.isAttribute && p.type === 'Element';
9853	    });
9854
9855	    if (property) {
9856	      return property;
9857	    }
9858	  }
9859
9860	  throw error$1('unrecognized element <' + nameNs.name + '>');
9861	};
9862
9863	ElementHandler.prototype.toString = function() {
9864	  return 'ElementDescriptor[' + getModdleDescriptor(this.type).name + ']';
9865	};
9866
9867	ElementHandler.prototype.valueHandler = function(propertyDesc, element) {
9868	  return new ValueHandler(propertyDesc, element);
9869	};
9870
9871	ElementHandler.prototype.referenceHandler = function(propertyDesc) {
9872	  return new ReferenceHandler(propertyDesc, this.context);
9873	};
9874
9875	ElementHandler.prototype.handler = function(type) {
9876	  if (type === 'Element') {
9877	    return new GenericElementHandler(this.model, type, this.context);
9878	  } else {
9879	    return new ElementHandler(this.model, type, this.context);
9880	  }
9881	};
9882
9883	/**
9884	 * Handle the child element parsing
9885	 *
9886	 * @param  {Element} node the xml node
9887	 */
9888	ElementHandler.prototype.handleChild = function(node) {
9889	  var propertyDesc, type, element, childHandler;
9890
9891	  propertyDesc = this.getPropertyForNode(node);
9892	  element = this.element;
9893
9894	  type = propertyDesc.effectiveType || propertyDesc.type;
9895
9896	  if (isSimple(type)) {
9897	    return this.valueHandler(propertyDesc, element);
9898	  }
9899
9900	  if (propertyDesc.isReference) {
9901	    childHandler = this.referenceHandler(propertyDesc).handleNode(node);
9902	  } else {
9903	    childHandler = this.handler(type).handleNode(node);
9904	  }
9905
9906	  var newElement = childHandler.element;
9907
9908	  // child handles may decide to skip elements
9909	  // by not returning anything
9910	  if (newElement !== undefined) {
9911
9912	    if (propertyDesc.isMany) {
9913	      element.get(propertyDesc.name).push(newElement);
9914	    } else {
9915	      element.set(propertyDesc.name, newElement);
9916	    }
9917
9918	    if (propertyDesc.isReference) {
9919	      assign(newElement, {
9920	        element: element
9921	      });
9922
9923	      this.context.addReference(newElement);
9924	    } else {
9925
9926	      // establish child -> parent relationship
9927	      newElement.$parent = element;
9928	    }
9929	  }
9930
9931	  return childHandler;
9932	};
9933
9934	/**
9935	 * An element handler that performs special validation
9936	 * to ensure the node it gets initialized with matches
9937	 * the handlers type (namespace wise).
9938	 *
9939	 * @param {Moddle} model
9940	 * @param {String} typeName
9941	 * @param {Context} context
9942	 */
9943	function RootElementHandler(model, typeName, context) {
9944	  ElementHandler.call(this, model, typeName, context);
9945	}
9946
9947	RootElementHandler.prototype = Object.create(ElementHandler.prototype);
9948
9949	RootElementHandler.prototype.createElement = function(node) {
9950
9951	  var name = node.name,
9952	      nameNs = parseName(name),
9953	      model = this.model,
9954	      type = this.type,
9955	      pkg = model.getPackage(nameNs.prefix),
9956	      typeName = pkg && aliasToName(nameNs, pkg) || name;
9957
9958	  // verify the correct namespace if we parse
9959	  // the first element in the handler tree
9960	  //
9961	  // this ensures we don't mistakenly import wrong namespace elements
9962	  if (!type.hasType(typeName)) {
9963	    throw error$1('unexpected element <' + node.originalName + '>');
9964	  }
9965
9966	  return ElementHandler.prototype.createElement.call(this, node);
9967	};
9968
9969
9970	function GenericElementHandler(model, typeName, context) {
9971	  this.model = model;
9972	  this.context = context;
9973	}
9974
9975	GenericElementHandler.prototype = Object.create(BaseElementHandler.prototype);
9976
9977	GenericElementHandler.prototype.createElement = function(node) {
9978
9979	  var name = node.name,
9980	      ns = parseName(name),
9981	      prefix = ns.prefix,
9982	      uri = node.ns[prefix + '$uri'],
9983	      attributes = node.attributes;
9984
9985	  return this.model.createAny(name, uri, attributes);
9986	};
9987
9988	GenericElementHandler.prototype.handleChild = function(node) {
9989
9990	  var handler = new GenericElementHandler(this.model, 'Element', this.context).handleNode(node),
9991	      element = this.element;
9992
9993	  var newElement = handler.element,
9994	      children;
9995
9996	  if (newElement !== undefined) {
9997	    children = element.$children = element.$children || [];
9998	    children.push(newElement);
9999
10000	    // establish child -> parent relationship
10001	    newElement.$parent = element;
10002	  }
10003
10004	  return handler;
10005	};
10006
10007	GenericElementHandler.prototype.handleEnd = function() {
10008	  if (this.body) {
10009	    this.element.$body = this.body;
10010	  }
10011	};
10012
10013	/**
10014	 * A reader for a meta-model
10015	 *
10016	 * @param {Object} options
10017	 * @param {Model} options.model used to read xml files
10018	 * @param {Boolean} options.lax whether to make parse errors warnings
10019	 */
10020	function Reader(options) {
10021
10022	  if (options instanceof Moddle) {
10023	    options = {
10024	      model: options
10025	    };
10026	  }
10027
10028	  assign(this, { lax: false }, options);
10029	}
10030
10031	/**
10032	 * The fromXML result.
10033	 *
10034	 * @typedef {Object} ParseResult
10035	 *
10036	 * @property {ModdleElement} rootElement
10037	 * @property {Array<Object>} references
10038	 * @property {Array<Error>} warnings
10039	 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
10040	 */
10041
10042	/**
10043	 * The fromXML result.
10044	 *
10045	 * @typedef {Error} ParseError
10046	 *
10047	 * @property {Array<Error>} warnings
10048	 */
10049
10050	/**
10051	 * Parse the given XML into a moddle document tree.
10052	 *
10053	 * @param {String} xml
10054	 * @param {ElementHandler|Object} options or rootHandler
10055	 *
10056	 * @returns {Promise<ParseResult, ParseError>}
10057	 */
10058	Reader.prototype.fromXML = function(xml, options, done) {
10059
10060	  var rootHandler = options.rootHandler;
10061
10062	  if (options instanceof ElementHandler) {
10063
10064	    // root handler passed via (xml, { rootHandler: ElementHandler }, ...)
10065	    rootHandler = options;
10066	    options = {};
10067	  } else {
10068	    if (typeof options === 'string') {
10069
10070	      // rootHandler passed via (xml, 'someString', ...)
10071	      rootHandler = this.handler(options);
10072	      options = {};
10073	    } else if (typeof rootHandler === 'string') {
10074
10075	      // rootHandler passed via (xml, { rootHandler: 'someString' }, ...)
10076	      rootHandler = this.handler(rootHandler);
10077	    }
10078	  }
10079
10080	  var model = this.model,
10081	      lax = this.lax;
10082
10083	  var context = new Context(assign({}, options, { rootHandler: rootHandler })),
10084	      parser = new Parser({ proxy: true }),
10085	      stack = createStack();
10086
10087	  rootHandler.context = context;
10088
10089	  // push root handler
10090	  stack.push(rootHandler);
10091
10092
10093	  /**
10094	   * Handle error.
10095	   *
10096	   * @param  {Error} err
10097	   * @param  {Function} getContext
10098	   * @param  {boolean} lax
10099	   *
10100	   * @return {boolean} true if handled
10101	   */
10102	  function handleError(err, getContext, lax) {
10103
10104	    var ctx = getContext();
10105
10106	    var line = ctx.line,
10107	        column = ctx.column,
10108	        data = ctx.data;
10109
10110	    // we receive the full context data here,
10111	    // for elements trim down the information
10112	    // to the tag name, only
10113	    if (data.charAt(0) === '<' && data.indexOf(' ') !== -1) {
10114	      data = data.slice(0, data.indexOf(' ')) + '>';
10115	    }
10116
10117	    var message =
10118	      'unparsable content ' + (data ? data + ' ' : '') + 'detected\n\t' +
10119	        'line: ' + line + '\n\t' +
10120	        'column: ' + column + '\n\t' +
10121	        'nested error: ' + err.message;
10122
10123	    if (lax) {
10124	      context.addWarning({
10125	        message: message,
10126	        error: err
10127	      });
10128
10129	      return true;
10130	    } else {
10131	      throw error$1(message);
10132	    }
10133	  }
10134
10135	  function handleWarning(err, getContext) {
10136
10137	    // just like handling errors in <lax=true> mode
10138	    return handleError(err, getContext, true);
10139	  }
10140
10141	  /**
10142	   * Resolve collected references on parse end.
10143	   */
10144	  function resolveReferences() {
10145
10146	    var elementsById = context.elementsById;
10147	    var references = context.references;
10148
10149	    var i, r;
10150
10151	    for (i = 0; (r = references[i]); i++) {
10152	      var element = r.element;
10153	      var reference = elementsById[r.id];
10154	      var property = getModdleDescriptor(element).propertiesByName[r.property];
10155
10156	      if (!reference) {
10157	        context.addWarning({
10158	          message: 'unresolved reference <' + r.id + '>',
10159	          element: r.element,
10160	          property: r.property,
10161	          value: r.id
10162	        });
10163	      }
10164
10165	      if (property.isMany) {
10166	        var collection = element.get(property.name),
10167	            idx = collection.indexOf(r);
10168
10169	        // we replace an existing place holder (idx != -1) or
10170	        // append to the collection instead
10171	        if (idx === -1) {
10172	          idx = collection.length;
10173	        }
10174
10175	        if (!reference) {
10176
10177	          // remove unresolvable reference
10178	          collection.splice(idx, 1);
10179	        } else {
10180
10181	          // add or update reference in collection
10182	          collection[idx] = reference;
10183	        }
10184	      } else {
10185	        element.set(property.name, reference);
10186	      }
10187	    }
10188	  }
10189
10190	  function handleClose() {
10191	    stack.pop().handleEnd();
10192	  }
10193
10194	  var PREAMBLE_START_PATTERN = /^<\?xml /i;
10195
10196	  var ENCODING_PATTERN = / encoding="([^"]+)"/i;
10197
10198	  var UTF_8_PATTERN = /^utf-8$/i;
10199
10200	  function handleQuestion(question) {
10201
10202	    if (!PREAMBLE_START_PATTERN.test(question)) {
10203	      return;
10204	    }
10205
10206	    var match = ENCODING_PATTERN.exec(question);
10207	    var encoding = match && match[1];
10208
10209	    if (!encoding || UTF_8_PATTERN.test(encoding)) {
10210	      return;
10211	    }
10212
10213	    context.addWarning({
10214	      message:
10215	        'unsupported document encoding <' + encoding + '>, ' +
10216	        'falling back to UTF-8'
10217	    });
10218	  }
10219
10220	  function handleOpen(node, getContext) {
10221	    var handler = stack.peek();
10222
10223	    try {
10224	      stack.push(handler.handleNode(node));
10225	    } catch (err) {
10226
10227	      if (handleError(err, getContext, lax)) {
10228	        stack.push(new NoopHandler());
10229	      }
10230	    }
10231	  }
10232
10233	  function handleCData(text, getContext) {
10234
10235	    try {
10236	      stack.peek().handleText(text);
10237	    } catch (err) {
10238	      handleWarning(err, getContext);
10239	    }
10240	  }
10241
10242	  function handleText(text, getContext) {
10243
10244	    // strip whitespace only nodes, i.e. before
10245	    // <!CDATA[ ... ]> sections and in between tags
10246
10247	    if (!text.trim()) {
10248	      return;
10249	    }
10250
10251	    handleCData(text, getContext);
10252	  }
10253
10254	  var uriMap = model.getPackages().reduce(function(uriMap, p) {
10255	    uriMap[p.uri] = p.prefix;
10256
10257	    return uriMap;
10258	  }, {
10259	    'http://www.w3.org/XML/1998/namespace': 'xml' // add default xml ns
10260	  });
10261	  parser
10262	    .ns(uriMap)
10263	    .on('openTag', function(obj, decodeStr, selfClosing, getContext) {
10264
10265	      // gracefully handle unparsable attributes (attrs=false)
10266	      var attrs = obj.attrs || {};
10267
10268	      var decodedAttrs = Object.keys(attrs).reduce(function(d, key) {
10269	        var value = decodeStr(attrs[key]);
10270
10271	        d[key] = value;
10272
10273	        return d;
10274	      }, {});
10275
10276	      var node = {
10277	        name: obj.name,
10278	        originalName: obj.originalName,
10279	        attributes: decodedAttrs,
10280	        ns: obj.ns
10281	      };
10282
10283	      handleOpen(node, getContext);
10284	    })
10285	    .on('question', handleQuestion)
10286	    .on('closeTag', handleClose)
10287	    .on('cdata', handleCData)
10288	    .on('text', function(text, decodeEntities, getContext) {
10289	      handleText(decodeEntities(text), getContext);
10290	    })
10291	    .on('error', handleError)
10292	    .on('warn', handleWarning);
10293
10294	  // async XML parsing to make sure the execution environment
10295	  // (node or brower) is kept responsive and that certain optimization
10296	  // strategies can kick in.
10297	  return new Promise(function(resolve, reject) {
10298
10299	    var err;
10300
10301	    try {
10302	      parser.parse(xml);
10303
10304	      resolveReferences();
10305	    } catch (e) {
10306	      err = e;
10307	    }
10308
10309	    var rootElement = rootHandler.element;
10310
10311	    if (!err && !rootElement) {
10312	      err = error$1('failed to parse document as <' + rootHandler.type.$descriptor.name + '>');
10313	    }
10314
10315	    var warnings = context.warnings;
10316	    var references = context.references;
10317	    var elementsById = context.elementsById;
10318
10319	    if (err) {
10320	      err.warnings = warnings;
10321
10322	      return reject(err);
10323	    } else {
10324	      return resolve({
10325	        rootElement: rootElement,
10326	        elementsById: elementsById,
10327	        references: references,
10328	        warnings: warnings
10329	      });
10330	    }
10331	  });
10332	};
10333
10334	Reader.prototype.handler = function(name) {
10335	  return new RootElementHandler(this.model, name);
10336	};
10337
10338
10339	// helpers //////////////////////////
10340
10341	function createStack() {
10342	  var stack = [];
10343
10344	  Object.defineProperty(stack, 'peek', {
10345	    value: function() {
10346	      return this[this.length - 1];
10347	    }
10348	  });
10349
10350	  return stack;
10351	}
10352
10353	var XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>\n';
10354
10355	var ESCAPE_ATTR_CHARS = /<|>|'|"|&|\n\r|\n/g;
10356	var ESCAPE_CHARS = /<|>|&/g;
10357
10358
10359	function Namespaces(parent) {
10360
10361	  var prefixMap = {};
10362	  var uriMap = {};
10363	  var used = {};
10364
10365	  var wellknown = [];
10366	  var custom = [];
10367
10368	  // API
10369
10370	  this.byUri = function(uri) {
10371	    return uriMap[uri] || (
10372	      parent && parent.byUri(uri)
10373	    );
10374	  };
10375
10376	  this.add = function(ns, isWellknown) {
10377
10378	    uriMap[ns.uri] = ns;
10379
10380	    if (isWellknown) {
10381	      wellknown.push(ns);
10382	    } else {
10383	      custom.push(ns);
10384	    }
10385
10386	    this.mapPrefix(ns.prefix, ns.uri);
10387	  };
10388
10389	  this.uriByPrefix = function(prefix) {
10390	    return prefixMap[prefix || 'xmlns'];
10391	  };
10392
10393	  this.mapPrefix = function(prefix, uri) {
10394	    prefixMap[prefix || 'xmlns'] = uri;
10395	  };
10396
10397	  this.getNSKey = function(ns) {
10398	    return (ns.prefix !== undefined) ? (ns.uri + '|' + ns.prefix) : ns.uri;
10399	  };
10400
10401	  this.logUsed = function(ns) {
10402
10403	    var uri = ns.uri;
10404	    var nsKey = this.getNSKey(ns);
10405
10406	    used[nsKey] = this.byUri(uri);
10407
10408	    // Inform parent recursively about the usage of this NS
10409	    if (parent) {
10410	      parent.logUsed(ns);
10411	    }
10412	  };
10413
10414	  this.getUsed = function(ns) {
10415
10416	    function isUsed(ns) {
10417	      var nsKey = self.getNSKey(ns);
10418
10419	      return used[nsKey];
10420	    }
10421
10422	    var self = this;
10423
10424	    var allNs = [].concat(wellknown, custom);
10425
10426	    return allNs.filter(isUsed);
10427	  };
10428
10429	}
10430
10431	function lower(string) {
10432	  return string.charAt(0).toLowerCase() + string.slice(1);
10433	}
10434
10435	function nameToAlias(name, pkg) {
10436	  if (hasLowerCaseAlias(pkg)) {
10437	    return lower(name);
10438	  } else {
10439	    return name;
10440	  }
10441	}
10442
10443	function inherits(ctor, superCtor) {
10444	  ctor.super_ = superCtor;
10445	  ctor.prototype = Object.create(superCtor.prototype, {
10446	    constructor: {
10447	      value: ctor,
10448	      enumerable: false,
10449	      writable: true,
10450	      configurable: true
10451	    }
10452	  });
10453	}
10454
10455	function nsName(ns) {
10456	  if (isString(ns)) {
10457	    return ns;
10458	  } else {
10459	    return (ns.prefix ? ns.prefix + ':' : '') + ns.localName;
10460	  }
10461	}
10462
10463	function getNsAttrs(namespaces) {
10464
10465	  return namespaces.getUsed().filter(function(ns) {
10466
10467	    // do not serialize built in <xml> namespace
10468	    return ns.prefix !== 'xml';
10469	  }).map(function(ns) {
10470	    var name = 'xmlns' + (ns.prefix ? ':' + ns.prefix : '');
10471	    return { name: name, value: ns.uri };
10472	  });
10473
10474	}
10475
10476	function getElementNs(ns, descriptor) {
10477	  if (descriptor.isGeneric) {
10478	    return assign({ localName: descriptor.ns.localName }, ns);
10479	  } else {
10480	    return assign({ localName: nameToAlias(descriptor.ns.localName, descriptor.$pkg) }, ns);
10481	  }
10482	}
10483
10484	function getPropertyNs(ns, descriptor) {
10485	  return assign({ localName: descriptor.ns.localName }, ns);
10486	}
10487
10488	function getSerializableProperties(element) {
10489	  var descriptor = element.$descriptor;
10490
10491	  return filter(descriptor.properties, function(p) {
10492	    var name = p.name;
10493
10494	    if (p.isVirtual) {
10495	      return false;
10496	    }
10497
10498	    // do not serialize defaults
10499	    if (!has(element, name)) {
10500	      return false;
10501	    }
10502
10503	    var value = element[name];
10504
10505	    // do not serialize default equals
10506	    if (value === p.default) {
10507	      return false;
10508	    }
10509
10510	    // do not serialize null properties
10511	    if (value === null) {
10512	      return false;
10513	    }
10514
10515	    return p.isMany ? value.length : true;
10516	  });
10517	}
10518
10519	var ESCAPE_ATTR_MAP = {
10520	  '\n': '#10',
10521	  '\n\r': '#10',
10522	  '"': '#34',
10523	  '\'': '#39',
10524	  '<': '#60',
10525	  '>': '#62',
10526	  '&': '#38'
10527	};
10528
10529	var ESCAPE_MAP = {
10530	  '<': 'lt',
10531	  '>': 'gt',
10532	  '&': 'amp'
10533	};
10534
10535	function escape(str, charPattern, replaceMap) {
10536
10537	  // ensure we are handling strings here
10538	  str = isString(str) ? str : '' + str;
10539
10540	  return str.replace(charPattern, function(s) {
10541	    return '&' + replaceMap[s] + ';';
10542	  });
10543	}
10544
10545	/**
10546	 * Escape a string attribute to not contain any bad values (line breaks, '"', ...)
10547	 *
10548	 * @param {String} str the string to escape
10549	 * @return {String} the escaped string
10550	 */
10551	function escapeAttr(str) {
10552	  return escape(str, ESCAPE_ATTR_CHARS, ESCAPE_ATTR_MAP);
10553	}
10554
10555	function escapeBody(str) {
10556	  return escape(str, ESCAPE_CHARS, ESCAPE_MAP);
10557	}
10558
10559	function filterAttributes(props) {
10560	  return filter(props, function(p) { return p.isAttr; });
10561	}
10562
10563	function filterContained(props) {
10564	  return filter(props, function(p) { return !p.isAttr; });
10565	}
10566
10567
10568	function ReferenceSerializer(tagName) {
10569	  this.tagName = tagName;
10570	}
10571
10572	ReferenceSerializer.prototype.build = function(element) {
10573	  this.element = element;
10574	  return this;
10575	};
10576
10577	ReferenceSerializer.prototype.serializeTo = function(writer) {
10578	  writer
10579	    .appendIndent()
10580	    .append('<' + this.tagName + '>' + this.element.id + '</' + this.tagName + '>')
10581	    .appendNewLine();
10582	};
10583
10584	function BodySerializer() {}
10585
10586	BodySerializer.prototype.serializeValue =
10587	BodySerializer.prototype.serializeTo = function(writer) {
10588	  writer.append(
10589	    this.escape
10590	      ? escapeBody(this.value)
10591	      : this.value
10592	  );
10593	};
10594
10595	BodySerializer.prototype.build = function(prop, value) {
10596	  this.value = value;
10597
10598	  if (prop.type === 'String' && value.search(ESCAPE_CHARS) !== -1) {
10599	    this.escape = true;
10600	  }
10601
10602	  return this;
10603	};
10604
10605	function ValueSerializer(tagName) {
10606	  this.tagName = tagName;
10607	}
10608
10609	inherits(ValueSerializer, BodySerializer);
10610
10611	ValueSerializer.prototype.serializeTo = function(writer) {
10612
10613	  writer
10614	    .appendIndent()
10615	    .append('<' + this.tagName + '>');
10616
10617	  this.serializeValue(writer);
10618
10619	  writer
10620	    .append('</' + this.tagName + '>')
10621	    .appendNewLine();
10622	};
10623
10624	function ElementSerializer(parent, propertyDescriptor) {
10625	  this.body = [];
10626	  this.attrs = [];
10627
10628	  this.parent = parent;
10629	  this.propertyDescriptor = propertyDescriptor;
10630	}
10631
10632	ElementSerializer.prototype.build = function(element) {
10633	  this.element = element;
10634
10635	  var elementDescriptor = element.$descriptor,
10636	      propertyDescriptor = this.propertyDescriptor;
10637
10638	  var otherAttrs,
10639	      properties;
10640
10641	  var isGeneric = elementDescriptor.isGeneric;
10642
10643	  if (isGeneric) {
10644	    otherAttrs = this.parseGeneric(element);
10645	  } else {
10646	    otherAttrs = this.parseNsAttributes(element);
10647	  }
10648
10649	  if (propertyDescriptor) {
10650	    this.ns = this.nsPropertyTagName(propertyDescriptor);
10651	  } else {
10652	    this.ns = this.nsTagName(elementDescriptor);
10653	  }
10654
10655	  // compute tag name
10656	  this.tagName = this.addTagName(this.ns);
10657
10658	  if (!isGeneric) {
10659	    properties = getSerializableProperties(element);
10660
10661	    this.parseAttributes(filterAttributes(properties));
10662	    this.parseContainments(filterContained(properties));
10663	  }
10664
10665	  this.parseGenericAttributes(element, otherAttrs);
10666
10667	  return this;
10668	};
10669
10670	ElementSerializer.prototype.nsTagName = function(descriptor) {
10671	  var effectiveNs = this.logNamespaceUsed(descriptor.ns);
10672	  return getElementNs(effectiveNs, descriptor);
10673	};
10674
10675	ElementSerializer.prototype.nsPropertyTagName = function(descriptor) {
10676	  var effectiveNs = this.logNamespaceUsed(descriptor.ns);
10677	  return getPropertyNs(effectiveNs, descriptor);
10678	};
10679
10680	ElementSerializer.prototype.isLocalNs = function(ns) {
10681	  return ns.uri === this.ns.uri;
10682	};
10683
10684	/**
10685	 * Get the actual ns attribute name for the given element.
10686	 *
10687	 * @param {Object} element
10688	 * @param {Boolean} [element.inherited=false]
10689	 *
10690	 * @return {Object} nsName
10691	 */
10692	ElementSerializer.prototype.nsAttributeName = function(element) {
10693
10694	  var ns;
10695
10696	  if (isString(element)) {
10697	    ns = parseName(element);
10698	  } else {
10699	    ns = element.ns;
10700	  }
10701
10702	  // return just local name for inherited attributes
10703	  if (element.inherited) {
10704	    return { localName: ns.localName };
10705	  }
10706
10707	  // parse + log effective ns
10708	  var effectiveNs = this.logNamespaceUsed(ns);
10709
10710	  // LOG ACTUAL namespace use
10711	  this.getNamespaces().logUsed(effectiveNs);
10712
10713	  // strip prefix if same namespace like parent
10714	  if (this.isLocalNs(effectiveNs)) {
10715	    return { localName: ns.localName };
10716	  } else {
10717	    return assign({ localName: ns.localName }, effectiveNs);
10718	  }
10719	};
10720
10721	ElementSerializer.prototype.parseGeneric = function(element) {
10722
10723	  var self = this,
10724	      body = this.body;
10725
10726	  var attributes = [];
10727
10728	  forEach(element, function(val, key) {
10729
10730	    var nonNsAttr;
10731
10732	    if (key === '$body') {
10733	      body.push(new BodySerializer().build({ type: 'String' }, val));
10734	    } else
10735	    if (key === '$children') {
10736	      forEach(val, function(child) {
10737	        body.push(new ElementSerializer(self).build(child));
10738	      });
10739	    } else
10740	    if (key.indexOf('$') !== 0) {
10741	      nonNsAttr = self.parseNsAttribute(element, key, val);
10742
10743	      if (nonNsAttr) {
10744	        attributes.push({ name: key, value: val });
10745	      }
10746	    }
10747	  });
10748
10749	  return attributes;
10750	};
10751
10752	ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
10753	  var model = element.$model;
10754
10755	  var nameNs = parseName(name);
10756
10757	  var ns;
10758
10759	  // parse xmlns:foo="http://foo.bar"
10760	  if (nameNs.prefix === 'xmlns') {
10761	    ns = { prefix: nameNs.localName, uri: value };
10762	  }
10763
10764	  // parse xmlns="http://foo.bar"
10765	  if (!nameNs.prefix && nameNs.localName === 'xmlns') {
10766	    ns = { uri: value };
10767	  }
10768
10769	  if (!ns) {
10770	    return {
10771	      name: name,
10772	      value: value
10773	    };
10774	  }
10775
10776	  if (model && model.getPackage(value)) {
10777
10778	    // register well known namespace
10779	    this.logNamespace(ns, true, true);
10780	  } else {
10781
10782	    // log custom namespace directly as used
10783	    var actualNs = this.logNamespaceUsed(ns, true);
10784
10785	    this.getNamespaces().logUsed(actualNs);
10786	  }
10787	};
10788
10789
10790	/**
10791	 * Parse namespaces and return a list of left over generic attributes
10792	 *
10793	 * @param  {Object} element
10794	 * @return {Array<Object>}
10795	 */
10796	ElementSerializer.prototype.parseNsAttributes = function(element, attrs) {
10797	  var self = this;
10798
10799	  var genericAttrs = element.$attrs;
10800
10801	  var attributes = [];
10802
10803	  // parse namespace attributes first
10804	  // and log them. push non namespace attributes to a list
10805	  // and process them later
10806	  forEach(genericAttrs, function(value, name) {
10807
10808	    var nonNsAttr = self.parseNsAttribute(element, name, value);
10809
10810	    if (nonNsAttr) {
10811	      attributes.push(nonNsAttr);
10812	    }
10813	  });
10814
10815	  return attributes;
10816	};
10817
10818	ElementSerializer.prototype.parseGenericAttributes = function(element, attributes) {
10819
10820	  var self = this;
10821
10822	  forEach(attributes, function(attr) {
10823
10824	    // do not serialize xsi:type attribute
10825	    // it is set manually based on the actual implementation type
10826	    if (attr.name === XSI_TYPE) {
10827	      return;
10828	    }
10829
10830	    try {
10831	      self.addAttribute(self.nsAttributeName(attr.name), attr.value);
10832	    } catch (e) {
10833	      console.warn(
10834	        'missing namespace information for ',
10835	        attr.name, '=', attr.value, 'on', element,
10836	        e);
10837	    }
10838	  });
10839	};
10840
10841	ElementSerializer.prototype.parseContainments = function(properties) {
10842
10843	  var self = this,
10844	      body = this.body,
10845	      element = this.element;
10846
10847	  forEach(properties, function(p) {
10848	    var value = element.get(p.name),
10849	        isReference = p.isReference,
10850	        isMany = p.isMany;
10851
10852	    if (!isMany) {
10853	      value = [ value ];
10854	    }
10855
10856	    if (p.isBody) {
10857	      body.push(new BodySerializer().build(p, value[0]));
10858	    } else
10859	    if (isSimple(p.type)) {
10860	      forEach(value, function(v) {
10861	        body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
10862	      });
10863	    } else
10864	    if (isReference) {
10865	      forEach(value, function(v) {
10866	        body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
10867	      });
10868	    } else {
10869
10870	      // allow serialization via type
10871	      // rather than element name
10872	      var asType = serializeAsType(p),
10873	          asProperty = serializeAsProperty(p);
10874
10875	      forEach(value, function(v) {
10876	        var serializer;
10877
10878	        if (asType) {
10879	          serializer = new TypeSerializer(self, p);
10880	        } else
10881	        if (asProperty) {
10882	          serializer = new ElementSerializer(self, p);
10883	        } else {
10884	          serializer = new ElementSerializer(self);
10885	        }
10886
10887	        body.push(serializer.build(v));
10888	      });
10889	    }
10890	  });
10891	};
10892
10893	ElementSerializer.prototype.getNamespaces = function(local) {
10894
10895	  var namespaces = this.namespaces,
10896	      parent = this.parent,
10897	      parentNamespaces;
10898
10899	  if (!namespaces) {
10900	    parentNamespaces = parent && parent.getNamespaces();
10901
10902	    if (local || !parentNamespaces) {
10903	      this.namespaces = namespaces = new Namespaces(parentNamespaces);
10904	    } else {
10905	      namespaces = parentNamespaces;
10906	    }
10907	  }
10908
10909	  return namespaces;
10910	};
10911
10912	ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
10913	  var namespaces = this.getNamespaces(local);
10914
10915	  var nsUri = ns.uri,
10916	      nsPrefix = ns.prefix;
10917
10918	  var existing = namespaces.byUri(nsUri);
10919
10920	  if (!existing || local) {
10921	    namespaces.add(ns, wellknown);
10922	  }
10923
10924	  namespaces.mapPrefix(nsPrefix, nsUri);
10925
10926	  return ns;
10927	};
10928
10929	ElementSerializer.prototype.logNamespaceUsed = function(ns, local) {
10930	  var element = this.element,
10931	      model = element.$model,
10932	      namespaces = this.getNamespaces(local);
10933
10934	  // ns may be
10935	  //
10936	  //   * prefix only
10937	  //   * prefix:uri
10938	  //   * localName only
10939
10940	  var prefix = ns.prefix,
10941	      uri = ns.uri,
10942	      newPrefix, idx,
10943	      wellknownUri;
10944
10945	  // handle anonymous namespaces (elementForm=unqualified), cf. #23
10946	  if (!prefix && !uri) {
10947	    return { localName: ns.localName };
10948	  }
10949
10950	  wellknownUri = DEFAULT_NS_MAP[prefix] || model && (model.getPackage(prefix) || {}).uri;
10951
10952	  uri = uri || wellknownUri || namespaces.uriByPrefix(prefix);
10953
10954	  if (!uri) {
10955	    throw new Error('no namespace uri given for prefix <' + prefix + '>');
10956	  }
10957
10958	  ns = namespaces.byUri(uri);
10959
10960	  if (!ns) {
10961	    newPrefix = prefix;
10962	    idx = 1;
10963
10964	    // find a prefix that is not mapped yet
10965	    while (namespaces.uriByPrefix(newPrefix)) {
10966	      newPrefix = prefix + '_' + idx++;
10967	    }
10968
10969	    ns = this.logNamespace({ prefix: newPrefix, uri: uri }, wellknownUri === uri);
10970	  }
10971
10972	  if (prefix) {
10973	    namespaces.mapPrefix(prefix, uri);
10974	  }
10975
10976	  return ns;
10977	};
10978
10979	ElementSerializer.prototype.parseAttributes = function(properties) {
10980	  var self = this,
10981	      element = this.element;
10982
10983	  forEach(properties, function(p) {
10984
10985	    var value = element.get(p.name);
10986
10987	    if (p.isReference) {
10988
10989	      if (!p.isMany) {
10990	        value = value.id;
10991	      }
10992	      else {
10993	        var values = [];
10994	        forEach(value, function(v) {
10995	          values.push(v.id);
10996	        });
10997
10998	        // IDREFS is a whitespace-separated list of references.
10999	        value = values.join(' ');
11000	      }
11001
11002	    }
11003
11004	    self.addAttribute(self.nsAttributeName(p), value);
11005	  });
11006	};
11007
11008	ElementSerializer.prototype.addTagName = function(nsTagName) {
11009	  var actualNs = this.logNamespaceUsed(nsTagName);
11010
11011	  this.getNamespaces().logUsed(actualNs);
11012
11013	  return nsName(nsTagName);
11014	};
11015
11016	ElementSerializer.prototype.addAttribute = function(name, value) {
11017	  var attrs = this.attrs;
11018
11019	  if (isString(value)) {
11020	    value = escapeAttr(value);
11021	  }
11022
11023	  attrs.push({ name: name, value: value });
11024	};
11025
11026	ElementSerializer.prototype.serializeAttributes = function(writer) {
11027	  var attrs = this.attrs,
11028	      namespaces = this.namespaces;
11029
11030	  if (namespaces) {
11031	    attrs = getNsAttrs(namespaces).concat(attrs);
11032	  }
11033
11034	  forEach(attrs, function(a) {
11035	    writer
11036	      .append(' ')
11037	      .append(nsName(a.name)).append('="').append(a.value).append('"');
11038	  });
11039	};
11040
11041	ElementSerializer.prototype.serializeTo = function(writer) {
11042	  var firstBody = this.body[0],
11043	      indent = firstBody && firstBody.constructor !== BodySerializer;
11044
11045	  writer
11046	    .appendIndent()
11047	    .append('<' + this.tagName);
11048
11049	  this.serializeAttributes(writer);
11050
11051	  writer.append(firstBody ? '>' : ' />');
11052
11053	  if (firstBody) {
11054
11055	    if (indent) {
11056	      writer
11057	        .appendNewLine()
11058	        .indent();
11059	    }
11060
11061	    forEach(this.body, function(b) {
11062	      b.serializeTo(writer);
11063	    });
11064
11065	    if (indent) {
11066	      writer
11067	        .unindent()
11068	        .appendIndent();
11069	    }
11070
11071	    writer.append('</' + this.tagName + '>');
11072	  }
11073
11074	  writer.appendNewLine();
11075	};
11076
11077	/**
11078	 * A serializer for types that handles serialization of data types
11079	 */
11080	function TypeSerializer(parent, propertyDescriptor) {
11081	  ElementSerializer.call(this, parent, propertyDescriptor);
11082	}
11083
11084	inherits(TypeSerializer, ElementSerializer);
11085
11086	TypeSerializer.prototype.parseNsAttributes = function(element) {
11087
11088	  // extracted attributes
11089	  var attributes = ElementSerializer.prototype.parseNsAttributes.call(this, element);
11090
11091	  var descriptor = element.$descriptor;
11092
11093	  // only serialize xsi:type if necessary
11094	  if (descriptor.name === this.propertyDescriptor.type) {
11095	    return attributes;
11096	  }
11097
11098	  var typeNs = this.typeNs = this.nsTagName(descriptor);
11099	  this.getNamespaces().logUsed(this.typeNs);
11100
11101	  // add xsi:type attribute to represent the elements
11102	  // actual type
11103
11104	  var pkg = element.$model.getPackage(typeNs.uri),
11105	      typePrefix = (pkg.xml && pkg.xml.typePrefix) || '';
11106
11107	  this.addAttribute(
11108	    this.nsAttributeName(XSI_TYPE),
11109	    (typeNs.prefix ? typeNs.prefix + ':' : '') + typePrefix + descriptor.ns.localName
11110	  );
11111
11112	  return attributes;
11113	};
11114
11115	TypeSerializer.prototype.isLocalNs = function(ns) {
11116	  return ns.uri === (this.typeNs || this.ns).uri;
11117	};
11118
11119	function SavingWriter() {
11120	  this.value = '';
11121
11122	  this.write = function(str) {
11123	    this.value += str;
11124	  };
11125	}
11126
11127	function FormatingWriter(out, format) {
11128
11129	  var indent = [''];
11130
11131	  this.append = function(str) {
11132	    out.write(str);
11133
11134	    return this;
11135	  };
11136
11137	  this.appendNewLine = function() {
11138	    if (format) {
11139	      out.write('\n');
11140	    }
11141
11142	    return this;
11143	  };
11144
11145	  this.appendIndent = function() {
11146	    if (format) {
11147	      out.write(indent.join('  '));
11148	    }
11149
11150	    return this;
11151	  };
11152
11153	  this.indent = function() {
11154	    indent.push('');
11155	    return this;
11156	  };
11157
11158	  this.unindent = function() {
11159	    indent.pop();
11160	    return this;
11161	  };
11162	}
11163
11164	/**
11165	 * A writer for meta-model backed document trees
11166	 *
11167	 * @param {Object} options output options to pass into the writer
11168	 */
11169	function Writer(options) {
11170
11171	  options = assign({ format: false, preamble: true }, options || {});
11172
11173	  function toXML(tree, writer) {
11174	    var internalWriter = writer || new SavingWriter();
11175	    var formatingWriter = new FormatingWriter(internalWriter, options.format);
11176
11177	    if (options.preamble) {
11178	      formatingWriter.append(XML_PREAMBLE);
11179	    }
11180
11181	    new ElementSerializer().build(tree).serializeTo(formatingWriter);
11182
11183	    if (!writer) {
11184	      return internalWriter.value;
11185	    }
11186	  }
11187
11188	  return {
11189	    toXML: toXML
11190	  };
11191	}
11192
11193	/**
11194	 * A sub class of {@link Moddle} with support for import and export of BPMN 2.0 xml files.
11195	 *
11196	 * @class BpmnModdle
11197	 * @extends Moddle
11198	 *
11199	 * @param {Object|Array} packages to use for instantiating the model
11200	 * @param {Object} [options] additional options to pass over
11201	 */
11202	function BpmnModdle(packages, options) {
11203	  Moddle.call(this, packages, options);
11204	}
11205
11206	BpmnModdle.prototype = Object.create(Moddle.prototype);
11207
11208	/**
11209	 * The fromXML result.
11210	 *
11211	 * @typedef {Object} ParseResult
11212	 *
11213	 * @property {ModdleElement} rootElement
11214	 * @property {Array<Object>} references
11215	 * @property {Array<Error>} warnings
11216	 * @property {Object} elementsById - a mapping containing each ID -> ModdleElement
11217	 */
11218
11219	/**
11220	 * The fromXML error.
11221	 *
11222	 * @typedef {Error} ParseError
11223	 *
11224	 * @property {Array<Error>} warnings
11225	 */
11226
11227	/**
11228	 * Instantiates a BPMN model tree from a given xml string.
11229	 *
11230	 * @param {String}   xmlStr
11231	 * @param {String}   [typeName='bpmn:Definitions'] name of the root element
11232	 * @param {Object}   [options]  options to pass to the underlying reader
11233	 *
11234	 * @returns {Promise<ParseResult, ParseError>}
11235	 */
11236	BpmnModdle.prototype.fromXML = function(xmlStr, typeName, options) {
11237
11238	  if (!isString(typeName)) {
11239	    options = typeName;
11240	    typeName = 'bpmn:Definitions';
11241	  }
11242
11243	  var reader = new Reader(assign({ model: this, lax: true }, options));
11244	  var rootHandler = reader.handler(typeName);
11245
11246	  return reader.fromXML(xmlStr, rootHandler);
11247	};
11248
11249
11250	/**
11251	 * The toXML result.
11252	 *
11253	 * @typedef {Object} SerializationResult
11254	 *
11255	 * @property {String} xml
11256	 */
11257
11258	/**
11259	 * Serializes a BPMN 2.0 object tree to XML.
11260	 *
11261	 * @param {String}   element    the root element, typically an instance of `bpmn:Definitions`
11262	 * @param {Object}   [options]  to pass to the underlying writer
11263	 *
11264	 * @returns {Promise<SerializationResult, Error>}
11265	 */
11266	BpmnModdle.prototype.toXML = function(element, options) {
11267
11268	  var writer = new Writer(options);
11269
11270	  return new Promise(function(resolve, reject) {
11271	    try {
11272	      var result = writer.toXML(element);
11273
11274	      return resolve({
11275	        xml: result
11276	      });
11277	    } catch (err) {
11278	      return reject(err);
11279	    }
11280	  });
11281	};
11282
11283	var name = "BPMN20";
11284	var uri = "http://www.omg.org/spec/BPMN/20100524/MODEL";
11285	var prefix = "bpmn";
11286	var associations = [
11287	];
11288	var types = [
11289		{
11290			name: "Interface",
11291			superClass: [
11292				"RootElement"
11293			],
11294			properties: [
11295				{
11296					name: "name",
11297					isAttr: true,
11298					type: "String"
11299				},
11300				{
11301					name: "operations",
11302					type: "Operation",
11303					isMany: true
11304				},
11305				{
11306					name: "implementationRef",
11307					isAttr: true,
11308					type: "String"
11309				}
11310			]
11311		},
11312		{
11313			name: "Operation",
11314			superClass: [
11315				"BaseElement"
11316			],
11317			properties: [
11318				{
11319					name: "name",
11320					isAttr: true,
11321					type: "String"
11322				},
11323				{
11324					name: "inMessageRef",
11325					type: "Message",
11326					isReference: true
11327				},
11328				{
11329					name: "outMessageRef",
11330					type: "Message",
11331					isReference: true
11332				},
11333				{
11334					name: "errorRef",
11335					type: "Error",
11336					isMany: true,
11337					isReference: true
11338				},
11339				{
11340					name: "implementationRef",
11341					isAttr: true,
11342					type: "String"
11343				}
11344			]
11345		},
11346		{
11347			name: "EndPoint",
11348			superClass: [
11349				"RootElement"
11350			]
11351		},
11352		{
11353			name: "Auditing",
11354			superClass: [
11355				"BaseElement"
11356			]
11357		},
11358		{
11359			name: "GlobalTask",
11360			superClass: [
11361				"CallableElement"
11362			],
11363			properties: [
11364				{
11365					name: "resources",
11366					type: "ResourceRole",
11367					isMany: true
11368				}
11369			]
11370		},
11371		{
11372			name: "Monitoring",
11373			superClass: [
11374				"BaseElement"
11375			]
11376		},
11377		{
11378			name: "Performer",
11379			superClass: [
11380				"ResourceRole"
11381			]
11382		},
11383		{
11384			name: "Process",
11385			superClass: [
11386				"FlowElementsContainer",
11387				"CallableElement"
11388			],
11389			properties: [
11390				{
11391					name: "processType",
11392					type: "ProcessType",
11393					isAttr: true
11394				},
11395				{
11396					name: "isClosed",
11397					isAttr: true,
11398					type: "Boolean"
11399				},
11400				{
11401					name: "auditing",
11402					type: "Auditing"
11403				},
11404				{
11405					name: "monitoring",
11406					type: "Monitoring"
11407				},
11408				{
11409					name: "properties",
11410					type: "Property",
11411					isMany: true
11412				},
11413				{
11414					name: "laneSets",
11415					isMany: true,
11416					replaces: "FlowElementsContainer#laneSets",
11417					type: "LaneSet"
11418				},
11419				{
11420					name: "flowElements",
11421					isMany: true,
11422					replaces: "FlowElementsContainer#flowElements",
11423					type: "FlowElement"
11424				},
11425				{
11426					name: "artifacts",
11427					type: "Artifact",
11428					isMany: true
11429				},
11430				{
11431					name: "resources",
11432					type: "ResourceRole",
11433					isMany: true
11434				},
11435				{
11436					name: "correlationSubscriptions",
11437					type: "CorrelationSubscription",
11438					isMany: true
11439				},
11440				{
11441					name: "supports",
11442					type: "Process",
11443					isMany: true,
11444					isReference: true
11445				},
11446				{
11447					name: "definitionalCollaborationRef",
11448					type: "Collaboration",
11449					isAttr: true,
11450					isReference: true
11451				},
11452				{
11453					name: "isExecutable",
11454					isAttr: true,
11455					type: "Boolean"
11456				}
11457			]
11458		},
11459		{
11460			name: "LaneSet",
11461			superClass: [
11462				"BaseElement"
11463			],
11464			properties: [
11465				{
11466					name: "lanes",
11467					type: "Lane",
11468					isMany: true
11469				},
11470				{
11471					name: "name",
11472					isAttr: true,
11473					type: "String"
11474				}
11475			]
11476		},
11477		{
11478			name: "Lane",
11479			superClass: [
11480				"BaseElement"
11481			],
11482			properties: [
11483				{
11484					name: "name",
11485					isAttr: true,
11486					type: "String"
11487				},
11488				{
11489					name: "partitionElementRef",
11490					type: "BaseElement",
11491					isAttr: true,
11492					isReference: true
11493				},
11494				{
11495					name: "partitionElement",
11496					type: "BaseElement"
11497				},
11498				{
11499					name: "flowNodeRef",
11500					type: "FlowNode",
11501					isMany: true,
11502					isReference: true
11503				},
11504				{
11505					name: "childLaneSet",
11506					type: "LaneSet",
11507					xml: {
11508						serialize: "xsi:type"
11509					}
11510				}
11511			]
11512		},
11513		{
11514			name: "GlobalManualTask",
11515			superClass: [
11516				"GlobalTask"
11517			]
11518		},
11519		{
11520			name: "ManualTask",
11521			superClass: [
11522				"Task"
11523			]
11524		},
11525		{
11526			name: "UserTask",
11527			superClass: [
11528				"Task"
11529			],
11530			properties: [
11531				{
11532					name: "renderings",
11533					type: "Rendering",
11534					isMany: true
11535				},
11536				{
11537					name: "implementation",
11538					isAttr: true,
11539					type: "String"
11540				}
11541			]
11542		},
11543		{
11544			name: "Rendering",
11545			superClass: [
11546				"BaseElement"
11547			]
11548		},
11549		{
11550			name: "HumanPerformer",
11551			superClass: [
11552				"Performer"
11553			]
11554		},
11555		{
11556			name: "PotentialOwner",
11557			superClass: [
11558				"HumanPerformer"
11559			]
11560		},
11561		{
11562			name: "GlobalUserTask",
11563			superClass: [
11564				"GlobalTask"
11565			],
11566			properties: [
11567				{
11568					name: "implementation",
11569					isAttr: true,
11570					type: "String"
11571				},
11572				{
11573					name: "renderings",
11574					type: "Rendering",
11575					isMany: true
11576				}
11577			]
11578		},
11579		{
11580			name: "Gateway",
11581			isAbstract: true,
11582			superClass: [
11583				"FlowNode"
11584			],
11585			properties: [
11586				{
11587					name: "gatewayDirection",
11588					type: "GatewayDirection",
11589					"default": "Unspecified",
11590					isAttr: true
11591				}
11592			]
11593		},
11594		{
11595			name: "EventBasedGateway",
11596			superClass: [
11597				"Gateway"
11598			],
11599			properties: [
11600				{
11601					name: "instantiate",
11602					"default": false,
11603					isAttr: true,
11604					type: "Boolean"
11605				},
11606				{
11607					name: "eventGatewayType",
11608					type: "EventBasedGatewayType",
11609					isAttr: true,
11610					"default": "Exclusive"
11611				}
11612			]
11613		},
11614		{
11615			name: "ComplexGateway",
11616			superClass: [
11617				"Gateway"
11618			],
11619			properties: [
11620				{
11621					name: "activationCondition",
11622					type: "Expression",
11623					xml: {
11624						serialize: "xsi:type"
11625					}
11626				},
11627				{
11628					name: "default",
11629					type: "SequenceFlow",
11630					isAttr: true,
11631					isReference: true
11632				}
11633			]
11634		},
11635		{
11636			name: "ExclusiveGateway",
11637			superClass: [
11638				"Gateway"
11639			],
11640			properties: [
11641				{
11642					name: "default",
11643					type: "SequenceFlow",
11644					isAttr: true,
11645					isReference: true
11646				}
11647			]
11648		},
11649		{
11650			name: "InclusiveGateway",
11651			superClass: [
11652				"Gateway"
11653			],
11654			properties: [
11655				{
11656					name: "default",
11657					type: "SequenceFlow",
11658					isAttr: true,
11659					isReference: true
11660				}
11661			]
11662		},
11663		{
11664			name: "ParallelGateway",
11665			superClass: [
11666				"Gateway"
11667			]
11668		},
11669		{
11670			name: "RootElement",
11671			isAbstract: true,
11672			superClass: [
11673				"BaseElement"
11674			]
11675		},
11676		{
11677			name: "Relationship",
11678			superClass: [
11679				"BaseElement"
11680			],
11681			properties: [
11682				{
11683					name: "type",
11684					isAttr: true,
11685					type: "String"
11686				},
11687				{
11688					name: "direction",
11689					type: "RelationshipDirection",
11690					isAttr: true
11691				},
11692				{
11693					name: "source",
11694					isMany: true,
11695					isReference: true,
11696					type: "Element"
11697				},
11698				{
11699					name: "target",
11700					isMany: true,
11701					isReference: true,
11702					type: "Element"
11703				}
11704			]
11705		},
11706		{
11707			name: "BaseElement",
11708			isAbstract: true,
11709			properties: [
11710				{
11711					name: "id",
11712					isAttr: true,
11713					type: "String",
11714					isId: true
11715				},
11716				{
11717					name: "documentation",
11718					type: "Documentation",
11719					isMany: true
11720				},
11721				{
11722					name: "extensionDefinitions",
11723					type: "ExtensionDefinition",
11724					isMany: true,
11725					isReference: true
11726				},
11727				{
11728					name: "extensionElements",
11729					type: "ExtensionElements"
11730				}
11731			]
11732		},
11733		{
11734			name: "Extension",
11735			properties: [
11736				{
11737					name: "mustUnderstand",
11738					"default": false,
11739					isAttr: true,
11740					type: "Boolean"
11741				},
11742				{
11743					name: "definition",
11744					type: "ExtensionDefinition",
11745					isAttr: true,
11746					isReference: true
11747				}
11748			]
11749		},
11750		{
11751			name: "ExtensionDefinition",
11752			properties: [
11753				{
11754					name: "name",
11755					isAttr: true,
11756					type: "String"
11757				},
11758				{
11759					name: "extensionAttributeDefinitions",
11760					type: "ExtensionAttributeDefinition",
11761					isMany: true
11762				}
11763			]
11764		},
11765		{
11766			name: "ExtensionAttributeDefinition",
11767			properties: [
11768				{
11769					name: "name",
11770					isAttr: true,
11771					type: "String"
11772				},
11773				{
11774					name: "type",
11775					isAttr: true,
11776					type: "String"
11777				},
11778				{
11779					name: "isReference",
11780					"default": false,
11781					isAttr: true,
11782					type: "Boolean"
11783				},
11784				{
11785					name: "extensionDefinition",
11786					type: "ExtensionDefinition",
11787					isAttr: true,
11788					isReference: true
11789				}
11790			]
11791		},
11792		{
11793			name: "ExtensionElements",
11794			properties: [
11795				{
11796					name: "valueRef",
11797					isAttr: true,
11798					isReference: true,
11799					type: "Element"
11800				},
11801				{
11802					name: "values",
11803					type: "Element",
11804					isMany: true
11805				},
11806				{
11807					name: "extensionAttributeDefinition",
11808					type: "ExtensionAttributeDefinition",
11809					isAttr: true,
11810					isReference: true
11811				}
11812			]
11813		},
11814		{
11815			name: "Documentation",
11816			superClass: [
11817				"BaseElement"
11818			],
11819			properties: [
11820				{
11821					name: "text",
11822					type: "String",
11823					isBody: true
11824				},
11825				{
11826					name: "textFormat",
11827					"default": "text/plain",
11828					isAttr: true,
11829					type: "String"
11830				}
11831			]
11832		},
11833		{
11834			name: "Event",
11835			isAbstract: true,
11836			superClass: [
11837				"FlowNode",
11838				"InteractionNode"
11839			],
11840			properties: [
11841				{
11842					name: "properties",
11843					type: "Property",
11844					isMany: true
11845				}
11846			]
11847		},
11848		{
11849			name: "IntermediateCatchEvent",
11850			superClass: [
11851				"CatchEvent"
11852			]
11853		},
11854		{
11855			name: "IntermediateThrowEvent",
11856			superClass: [
11857				"ThrowEvent"
11858			]
11859		},
11860		{
11861			name: "EndEvent",
11862			superClass: [
11863				"ThrowEvent"
11864			]
11865		},
11866		{
11867			name: "StartEvent",
11868			superClass: [
11869				"CatchEvent"
11870			],
11871			properties: [
11872				{
11873					name: "isInterrupting",
11874					"default": true,
11875					isAttr: true,
11876					type: "Boolean"
11877				}
11878			]
11879		},
11880		{
11881			name: "ThrowEvent",
11882			isAbstract: true,
11883			superClass: [
11884				"Event"
11885			],
11886			properties: [
11887				{
11888					name: "dataInputs",
11889					type: "DataInput",
11890					isMany: true
11891				},
11892				{
11893					name: "dataInputAssociations",
11894					type: "DataInputAssociation",
11895					isMany: true
11896				},
11897				{
11898					name: "inputSet",
11899					type: "InputSet"
11900				},
11901				{
11902					name: "eventDefinitions",
11903					type: "EventDefinition",
11904					isMany: true
11905				},
11906				{
11907					name: "eventDefinitionRef",
11908					type: "EventDefinition",
11909					isMany: true,
11910					isReference: true
11911				}
11912			]
11913		},
11914		{
11915			name: "CatchEvent",
11916			isAbstract: true,
11917			superClass: [
11918				"Event"
11919			],
11920			properties: [
11921				{
11922					name: "parallelMultiple",
11923					isAttr: true,
11924					type: "Boolean",
11925					"default": false
11926				},
11927				{
11928					name: "dataOutputs",
11929					type: "DataOutput",
11930					isMany: true
11931				},
11932				{
11933					name: "dataOutputAssociations",
11934					type: "DataOutputAssociation",
11935					isMany: true
11936				},
11937				{
11938					name: "outputSet",
11939					type: "OutputSet"
11940				},
11941				{
11942					name: "eventDefinitions",
11943					type: "EventDefinition",
11944					isMany: true
11945				},
11946				{
11947					name: "eventDefinitionRef",
11948					type: "EventDefinition",
11949					isMany: true,
11950					isReference: true
11951				}
11952			]
11953		},
11954		{
11955			name: "BoundaryEvent",
11956			superClass: [
11957				"CatchEvent"
11958			],
11959			properties: [
11960				{
11961					name: "cancelActivity",
11962					"default": true,
11963					isAttr: true,
11964					type: "Boolean"
11965				},
11966				{
11967					name: "attachedToRef",
11968					type: "Activity",
11969					isAttr: true,
11970					isReference: true
11971				}
11972			]
11973		},
11974		{
11975			name: "EventDefinition",
11976			isAbstract: true,
11977			superClass: [
11978				"RootElement"
11979			]
11980		},
11981		{
11982			name: "CancelEventDefinition",
11983			superClass: [
11984				"EventDefinition"
11985			]
11986		},
11987		{
11988			name: "ErrorEventDefinition",
11989			superClass: [
11990				"EventDefinition"
11991			],
11992			properties: [
11993				{
11994					name: "errorRef",
11995					type: "Error",
11996					isAttr: true,
11997					isReference: true
11998				}
11999			]
12000		},
12001		{
12002			name: "TerminateEventDefinition",
12003			superClass: [
12004				"EventDefinition"
12005			]
12006		},
12007		{
12008			name: "EscalationEventDefinition",
12009			superClass: [
12010				"EventDefinition"
12011			],
12012			properties: [
12013				{
12014					name: "escalationRef",
12015					type: "Escalation",
12016					isAttr: true,
12017					isReference: true
12018				}
12019			]
12020		},
12021		{
12022			name: "Escalation",
12023			properties: [
12024				{
12025					name: "structureRef",
12026					type: "ItemDefinition",
12027					isAttr: true,
12028					isReference: true
12029				},
12030				{
12031					name: "name",
12032					isAttr: true,
12033					type: "String"
12034				},
12035				{
12036					name: "escalationCode",
12037					isAttr: true,
12038					type: "String"
12039				}
12040			],
12041			superClass: [
12042				"RootElement"
12043			]
12044		},
12045		{
12046			name: "CompensateEventDefinition",
12047			superClass: [
12048				"EventDefinition"
12049			],
12050			properties: [
12051				{
12052					name: "waitForCompletion",
12053					isAttr: true,
12054					type: "Boolean",
12055					"default": true
12056				},
12057				{
12058					name: "activityRef",
12059					type: "Activity",
12060					isAttr: true,
12061					isReference: true
12062				}
12063			]
12064		},
12065		{
12066			name: "TimerEventDefinition",
12067			superClass: [
12068				"EventDefinition"
12069			],
12070			properties: [
12071				{
12072					name: "timeDate",
12073					type: "Expression",
12074					xml: {
12075						serialize: "xsi:type"
12076					}
12077				},
12078				{
12079					name: "timeCycle",
12080					type: "Expression",
12081					xml: {
12082						serialize: "xsi:type"
12083					}
12084				},
12085				{
12086					name: "timeDuration",
12087					type: "Expression",
12088					xml: {
12089						serialize: "xsi:type"
12090					}
12091				}
12092			]
12093		},
12094		{
12095			name: "LinkEventDefinition",
12096			superClass: [
12097				"EventDefinition"
12098			],
12099			properties: [
12100				{
12101					name: "name",
12102					isAttr: true,
12103					type: "String"
12104				},
12105				{
12106					name: "target",
12107					type: "LinkEventDefinition",
12108					isAttr: true,
12109					isReference: true
12110				},
12111				{
12112					name: "source",
12113					type: "LinkEventDefinition",
12114					isMany: true,
12115					isReference: true
12116				}
12117			]
12118		},
12119		{
12120			name: "MessageEventDefinition",
12121			superClass: [
12122				"EventDefinition"
12123			],
12124			properties: [
12125				{
12126					name: "messageRef",
12127					type: "Message",
12128					isAttr: true,
12129					isReference: true
12130				},
12131				{
12132					name: "operationRef",
12133					type: "Operation",
12134					isAttr: true,
12135					isReference: true
12136				}
12137			]
12138		},
12139		{
12140			name: "ConditionalEventDefinition",
12141			superClass: [
12142				"EventDefinition"
12143			],
12144			properties: [
12145				{
12146					name: "condition",
12147					type: "Expression",
12148					xml: {
12149						serialize: "xsi:type"
12150					}
12151				}
12152			]
12153		},
12154		{
12155			name: "SignalEventDefinition",
12156			superClass: [
12157				"EventDefinition"
12158			],
12159			properties: [
12160				{
12161					name: "signalRef",
12162					type: "Signal",
12163					isAttr: true,
12164					isReference: true
12165				}
12166			]
12167		},
12168		{
12169			name: "Signal",
12170			superClass: [
12171				"RootElement"
12172			],
12173			properties: [
12174				{
12175					name: "structureRef",
12176					type: "ItemDefinition",
12177					isAttr: true,
12178					isReference: true
12179				},
12180				{
12181					name: "name",
12182					isAttr: true,
12183					type: "String"
12184				}
12185			]
12186		},
12187		{
12188			name: "ImplicitThrowEvent",
12189			superClass: [
12190				"ThrowEvent"
12191			]
12192		},
12193		{
12194			name: "DataState",
12195			superClass: [
12196				"BaseElement"
12197			],
12198			properties: [
12199				{
12200					name: "name",
12201					isAttr: true,
12202					type: "String"
12203				}
12204			]
12205		},
12206		{
12207			name: "ItemAwareElement",
12208			superClass: [
12209				"BaseElement"
12210			],
12211			properties: [
12212				{
12213					name: "itemSubjectRef",
12214					type: "ItemDefinition",
12215					isAttr: true,
12216					isReference: true
12217				},
12218				{
12219					name: "dataState",
12220					type: "DataState"
12221				}
12222			]
12223		},
12224		{
12225			name: "DataAssociation",
12226			superClass: [
12227				"BaseElement"
12228			],
12229			properties: [
12230				{
12231					name: "sourceRef",
12232					type: "ItemAwareElement",
12233					isMany: true,
12234					isReference: true
12235				},
12236				{
12237					name: "targetRef",
12238					type: "ItemAwareElement",
12239					isReference: true
12240				},
12241				{
12242					name: "transformation",
12243					type: "FormalExpression",
12244					xml: {
12245						serialize: "property"
12246					}
12247				},
12248				{
12249					name: "assignment",
12250					type: "Assignment",
12251					isMany: true
12252				}
12253			]
12254		},
12255		{
12256			name: "DataInput",
12257			superClass: [
12258				"ItemAwareElement"
12259			],
12260			properties: [
12261				{
12262					name: "name",
12263					isAttr: true,
12264					type: "String"
12265				},
12266				{
12267					name: "isCollection",
12268					"default": false,
12269					isAttr: true,
12270					type: "Boolean"
12271				},
12272				{
12273					name: "inputSetRef",
12274					type: "InputSet",
12275					isMany: true,
12276					isVirtual: true,
12277					isReference: true
12278				},
12279				{
12280					name: "inputSetWithOptional",
12281					type: "InputSet",
12282					isMany: true,
12283					isVirtual: true,
12284					isReference: true
12285				},
12286				{
12287					name: "inputSetWithWhileExecuting",
12288					type: "InputSet",
12289					isMany: true,
12290					isVirtual: true,
12291					isReference: true
12292				}
12293			]
12294		},
12295		{
12296			name: "DataOutput",
12297			superClass: [
12298				"ItemAwareElement"
12299			],
12300			properties: [
12301				{
12302					name: "name",
12303					isAttr: true,
12304					type: "String"
12305				},
12306				{
12307					name: "isCollection",
12308					"default": false,
12309					isAttr: true,
12310					type: "Boolean"
12311				},
12312				{
12313					name: "outputSetRef",
12314					type: "OutputSet",
12315					isMany: true,
12316					isVirtual: true,
12317					isReference: true
12318				},
12319				{
12320					name: "outputSetWithOptional",
12321					type: "OutputSet",
12322					isMany: true,
12323					isVirtual: true,
12324					isReference: true
12325				},
12326				{
12327					name: "outputSetWithWhileExecuting",
12328					type: "OutputSet",
12329					isMany: true,
12330					isVirtual: true,
12331					isReference: true
12332				}
12333			]
12334		},
12335		{
12336			name: "InputSet",
12337			superClass: [
12338				"BaseElement"
12339			],
12340			properties: [
12341				{
12342					name: "name",
12343					isAttr: true,
12344					type: "String"
12345				},
12346				{
12347					name: "dataInputRefs",
12348					type: "DataInput",
12349					isMany: true,
12350					isReference: true
12351				},
12352				{
12353					name: "optionalInputRefs",
12354					type: "DataInput",
12355					isMany: true,
12356					isReference: true
12357				},
12358				{
12359					name: "whileExecutingInputRefs",
12360					type: "DataInput",
12361					isMany: true,
12362					isReference: true
12363				},
12364				{
12365					name: "outputSetRefs",
12366					type: "OutputSet",
12367					isMany: true,
12368					isReference: true
12369				}
12370			]
12371		},
12372		{
12373			name: "OutputSet",
12374			superClass: [
12375				"BaseElement"
12376			],
12377			properties: [
12378				{
12379					name: "dataOutputRefs",
12380					type: "DataOutput",
12381					isMany: true,
12382					isReference: true
12383				},
12384				{
12385					name: "name",
12386					isAttr: true,
12387					type: "String"
12388				},
12389				{
12390					name: "inputSetRefs",
12391					type: "InputSet",
12392					isMany: true,
12393					isReference: true
12394				},
12395				{
12396					name: "optionalOutputRefs",
12397					type: "DataOutput",
12398					isMany: true,
12399					isReference: true
12400				},
12401				{
12402					name: "whileExecutingOutputRefs",
12403					type: "DataOutput",
12404					isMany: true,
12405					isReference: true
12406				}
12407			]
12408		},
12409		{
12410			name: "Property",
12411			superClass: [
12412				"ItemAwareElement"
12413			],
12414			properties: [
12415				{
12416					name: "name",
12417					isAttr: true,
12418					type: "String"
12419				}
12420			]
12421		},
12422		{
12423			name: "DataInputAssociation",
12424			superClass: [
12425				"DataAssociation"
12426			]
12427		},
12428		{
12429			name: "DataOutputAssociation",
12430			superClass: [
12431				"DataAssociation"
12432			]
12433		},
12434		{
12435			name: "InputOutputSpecification",
12436			superClass: [
12437				"BaseElement"
12438			],
12439			properties: [
12440				{
12441					name: "dataInputs",
12442					type: "DataInput",
12443					isMany: true
12444				},
12445				{
12446					name: "dataOutputs",
12447					type: "DataOutput",
12448					isMany: true
12449				},
12450				{
12451					name: "inputSets",
12452					type: "InputSet",
12453					isMany: true
12454				},
12455				{
12456					name: "outputSets",
12457					type: "OutputSet",
12458					isMany: true
12459				}
12460			]
12461		},
12462		{
12463			name: "DataObject",
12464			superClass: [
12465				"FlowElement",
12466				"ItemAwareElement"
12467			],
12468			properties: [
12469				{
12470					name: "isCollection",
12471					"default": false,
12472					isAttr: true,
12473					type: "Boolean"
12474				}
12475			]
12476		},
12477		{
12478			name: "InputOutputBinding",
12479			properties: [
12480				{
12481					name: "inputDataRef",
12482					type: "InputSet",
12483					isAttr: true,
12484					isReference: true
12485				},
12486				{
12487					name: "outputDataRef",
12488					type: "OutputSet",
12489					isAttr: true,
12490					isReference: true
12491				},
12492				{
12493					name: "operationRef",
12494					type: "Operation",
12495					isAttr: true,
12496					isReference: true
12497				}
12498			]
12499		},
12500		{
12501			name: "Assignment",
12502			superClass: [
12503				"BaseElement"
12504			],
12505			properties: [
12506				{
12507					name: "from",
12508					type: "Expression",
12509					xml: {
12510						serialize: "xsi:type"
12511					}
12512				},
12513				{
12514					name: "to",
12515					type: "Expression",
12516					xml: {
12517						serialize: "xsi:type"
12518					}
12519				}
12520			]
12521		},
12522		{
12523			name: "DataStore",
12524			superClass: [
12525				"RootElement",
12526				"ItemAwareElement"
12527			],
12528			properties: [
12529				{
12530					name: "name",
12531					isAttr: true,
12532					type: "String"
12533				},
12534				{
12535					name: "capacity",
12536					isAttr: true,
12537					type: "Integer"
12538				},
12539				{
12540					name: "isUnlimited",
12541					"default": true,
12542					isAttr: true,
12543					type: "Boolean"
12544				}
12545			]
12546		},
12547		{
12548			name: "DataStoreReference",
12549			superClass: [
12550				"ItemAwareElement",
12551				"FlowElement"
12552			],
12553			properties: [
12554				{
12555					name: "dataStoreRef",
12556					type: "DataStore",
12557					isAttr: true,
12558					isReference: true
12559				}
12560			]
12561		},
12562		{
12563			name: "DataObjectReference",
12564			superClass: [
12565				"ItemAwareElement",
12566				"FlowElement"
12567			],
12568			properties: [
12569				{
12570					name: "dataObjectRef",
12571					type: "DataObject",
12572					isAttr: true,
12573					isReference: true
12574				}
12575			]
12576		},
12577		{
12578			name: "ConversationLink",
12579			superClass: [
12580				"BaseElement"
12581			],
12582			properties: [
12583				{
12584					name: "sourceRef",
12585					type: "InteractionNode",
12586					isAttr: true,
12587					isReference: true
12588				},
12589				{
12590					name: "targetRef",
12591					type: "InteractionNode",
12592					isAttr: true,
12593					isReference: true
12594				},
12595				{
12596					name: "name",
12597					isAttr: true,
12598					type: "String"
12599				}
12600			]
12601		},
12602		{
12603			name: "ConversationAssociation",
12604			superClass: [
12605				"BaseElement"
12606			],
12607			properties: [
12608				{
12609					name: "innerConversationNodeRef",
12610					type: "ConversationNode",
12611					isAttr: true,
12612					isReference: true
12613				},
12614				{
12615					name: "outerConversationNodeRef",
12616					type: "ConversationNode",
12617					isAttr: true,
12618					isReference: true
12619				}
12620			]
12621		},
12622		{
12623			name: "CallConversation",
12624			superClass: [
12625				"ConversationNode"
12626			],
12627			properties: [
12628				{
12629					name: "calledCollaborationRef",
12630					type: "Collaboration",
12631					isAttr: true,
12632					isReference: true
12633				},
12634				{
12635					name: "participantAssociations",
12636					type: "ParticipantAssociation",
12637					isMany: true
12638				}
12639			]
12640		},
12641		{
12642			name: "Conversation",
12643			superClass: [
12644				"ConversationNode"
12645			]
12646		},
12647		{
12648			name: "SubConversation",
12649			superClass: [
12650				"ConversationNode"
12651			],
12652			properties: [
12653				{
12654					name: "conversationNodes",
12655					type: "ConversationNode",
12656					isMany: true
12657				}
12658			]
12659		},
12660		{
12661			name: "ConversationNode",
12662			isAbstract: true,
12663			superClass: [
12664				"InteractionNode",
12665				"BaseElement"
12666			],
12667			properties: [
12668				{
12669					name: "name",
12670					isAttr: true,
12671					type: "String"
12672				},
12673				{
12674					name: "participantRef",
12675					type: "Participant",
12676					isMany: true,
12677					isReference: true
12678				},
12679				{
12680					name: "messageFlowRefs",
12681					type: "MessageFlow",
12682					isMany: true,
12683					isReference: true
12684				},
12685				{
12686					name: "correlationKeys",
12687					type: "CorrelationKey",
12688					isMany: true
12689				}
12690			]
12691		},
12692		{
12693			name: "GlobalConversation",
12694			superClass: [
12695				"Collaboration"
12696			]
12697		},
12698		{
12699			name: "PartnerEntity",
12700			superClass: [
12701				"RootElement"
12702			],
12703			properties: [
12704				{
12705					name: "name",
12706					isAttr: true,
12707					type: "String"
12708				},
12709				{
12710					name: "participantRef",
12711					type: "Participant",
12712					isMany: true,
12713					isReference: true
12714				}
12715			]
12716		},
12717		{
12718			name: "PartnerRole",
12719			superClass: [
12720				"RootElement"
12721			],
12722			properties: [
12723				{
12724					name: "name",
12725					isAttr: true,
12726					type: "String"
12727				},
12728				{
12729					name: "participantRef",
12730					type: "Participant",
12731					isMany: true,
12732					isReference: true
12733				}
12734			]
12735		},
12736		{
12737			name: "CorrelationProperty",
12738			superClass: [
12739				"RootElement"
12740			],
12741			properties: [
12742				{
12743					name: "correlationPropertyRetrievalExpression",
12744					type: "CorrelationPropertyRetrievalExpression",
12745					isMany: true
12746				},
12747				{
12748					name: "name",
12749					isAttr: true,
12750					type: "String"
12751				},
12752				{
12753					name: "type",
12754					type: "ItemDefinition",
12755					isAttr: true,
12756					isReference: true
12757				}
12758			]
12759		},
12760		{
12761			name: "Error",
12762			superClass: [
12763				"RootElement"
12764			],
12765			properties: [
12766				{
12767					name: "structureRef",
12768					type: "ItemDefinition",
12769					isAttr: true,
12770					isReference: true
12771				},
12772				{
12773					name: "name",
12774					isAttr: true,
12775					type: "String"
12776				},
12777				{
12778					name: "errorCode",
12779					isAttr: true,
12780					type: "String"
12781				}
12782			]
12783		},
12784		{
12785			name: "CorrelationKey",
12786			superClass: [
12787				"BaseElement"
12788			],
12789			properties: [
12790				{
12791					name: "correlationPropertyRef",
12792					type: "CorrelationProperty",
12793					isMany: true,
12794					isReference: true
12795				},
12796				{
12797					name: "name",
12798					isAttr: true,
12799					type: "String"
12800				}
12801			]
12802		},
12803		{
12804			name: "Expression",
12805			superClass: [
12806				"BaseElement"
12807			],
12808			isAbstract: false,
12809			properties: [
12810				{
12811					name: "body",
12812					isBody: true,
12813					type: "String"
12814				}
12815			]
12816		},
12817		{
12818			name: "FormalExpression",
12819			superClass: [
12820				"Expression"
12821			],
12822			properties: [
12823				{
12824					name: "language",
12825					isAttr: true,
12826					type: "String"
12827				},
12828				{
12829					name: "evaluatesToTypeRef",
12830					type: "ItemDefinition",
12831					isAttr: true,
12832					isReference: true
12833				}
12834			]
12835		},
12836		{
12837			name: "Message",
12838			superClass: [
12839				"RootElement"
12840			],
12841			properties: [
12842				{
12843					name: "name",
12844					isAttr: true,
12845					type: "String"
12846				},
12847				{
12848					name: "itemRef",
12849					type: "ItemDefinition",
12850					isAttr: true,
12851					isReference: true
12852				}
12853			]
12854		},
12855		{
12856			name: "ItemDefinition",
12857			superClass: [
12858				"RootElement"
12859			],
12860			properties: [
12861				{
12862					name: "itemKind",
12863					type: "ItemKind",
12864					isAttr: true
12865				},
12866				{
12867					name: "structureRef",
12868					isAttr: true,
12869					type: "String"
12870				},
12871				{
12872					name: "isCollection",
12873					"default": false,
12874					isAttr: true,
12875					type: "Boolean"
12876				},
12877				{
12878					name: "import",
12879					type: "Import",
12880					isAttr: true,
12881					isReference: true
12882				}
12883			]
12884		},
12885		{
12886			name: "FlowElement",
12887			isAbstract: true,
12888			superClass: [
12889				"BaseElement"
12890			],
12891			properties: [
12892				{
12893					name: "name",
12894					isAttr: true,
12895					type: "String"
12896				},
12897				{
12898					name: "auditing",
12899					type: "Auditing"
12900				},
12901				{
12902					name: "monitoring",
12903					type: "Monitoring"
12904				},
12905				{
12906					name: "categoryValueRef",
12907					type: "CategoryValue",
12908					isMany: true,
12909					isReference: true
12910				}
12911			]
12912		},
12913		{
12914			name: "SequenceFlow",
12915			superClass: [
12916				"FlowElement"
12917			],
12918			properties: [
12919				{
12920					name: "isImmediate",
12921					isAttr: true,
12922					type: "Boolean"
12923				},
12924				{
12925					name: "conditionExpression",
12926					type: "Expression",
12927					xml: {
12928						serialize: "xsi:type"
12929					}
12930				},
12931				{
12932					name: "sourceRef",
12933					type: "FlowNode",
12934					isAttr: true,
12935					isReference: true
12936				},
12937				{
12938					name: "targetRef",
12939					type: "FlowNode",
12940					isAttr: true,
12941					isReference: true
12942				}
12943			]
12944		},
12945		{
12946			name: "FlowElementsContainer",
12947			isAbstract: true,
12948			superClass: [
12949				"BaseElement"
12950			],
12951			properties: [
12952				{
12953					name: "laneSets",
12954					type: "LaneSet",
12955					isMany: true
12956				},
12957				{
12958					name: "flowElements",
12959					type: "FlowElement",
12960					isMany: true
12961				}
12962			]
12963		},
12964		{
12965			name: "CallableElement",
12966			isAbstract: true,
12967			superClass: [
12968				"RootElement"
12969			],
12970			properties: [
12971				{
12972					name: "name",
12973					isAttr: true,
12974					type: "String"
12975				},
12976				{
12977					name: "ioSpecification",
12978					type: "InputOutputSpecification",
12979					xml: {
12980						serialize: "property"
12981					}
12982				},
12983				{
12984					name: "supportedInterfaceRef",
12985					type: "Interface",
12986					isMany: true,
12987					isReference: true
12988				},
12989				{
12990					name: "ioBinding",
12991					type: "InputOutputBinding",
12992					isMany: true,
12993					xml: {
12994						serialize: "property"
12995					}
12996				}
12997			]
12998		},
12999		{
13000			name: "FlowNode",
13001			isAbstract: true,
13002			superClass: [
13003				"FlowElement"
13004			],
13005			properties: [
13006				{
13007					name: "incoming",
13008					type: "SequenceFlow",
13009					isMany: true,
13010					isReference: true
13011				},
13012				{
13013					name: "outgoing",
13014					type: "SequenceFlow",
13015					isMany: true,
13016					isReference: true
13017				},
13018				{
13019					name: "lanes",
13020					type: "Lane",
13021					isMany: true,
13022					isVirtual: true,
13023					isReference: true
13024				}
13025			]
13026		},
13027		{
13028			name: "CorrelationPropertyRetrievalExpression",
13029			superClass: [
13030				"BaseElement"
13031			],
13032			properties: [
13033				{
13034					name: "messagePath",
13035					type: "FormalExpression"
13036				},
13037				{
13038					name: "messageRef",
13039					type: "Message",
13040					isAttr: true,
13041					isReference: true
13042				}
13043			]
13044		},
13045		{
13046			name: "CorrelationPropertyBinding",
13047			superClass: [
13048				"BaseElement"
13049			],
13050			properties: [
13051				{
13052					name: "dataPath",
13053					type: "FormalExpression"
13054				},
13055				{
13056					name: "correlationPropertyRef",
13057					type: "CorrelationProperty",
13058					isAttr: true,
13059					isReference: true
13060				}
13061			]
13062		},
13063		{
13064			name: "Resource",
13065			superClass: [
13066				"RootElement"
13067			],
13068			properties: [
13069				{
13070					name: "name",
13071					isAttr: true,
13072					type: "String"
13073				},
13074				{
13075					name: "resourceParameters",
13076					type: "ResourceParameter",
13077					isMany: true
13078				}
13079			]
13080		},
13081		{
13082			name: "ResourceParameter",
13083			superClass: [
13084				"BaseElement"
13085			],
13086			properties: [
13087				{
13088					name: "name",
13089					isAttr: true,
13090					type: "String"
13091				},
13092				{
13093					name: "isRequired",
13094					isAttr: true,
13095					type: "Boolean"
13096				},
13097				{
13098					name: "type",
13099					type: "ItemDefinition",
13100					isAttr: true,
13101					isReference: true
13102				}
13103			]
13104		},
13105		{
13106			name: "CorrelationSubscription",
13107			superClass: [
13108				"BaseElement"
13109			],
13110			properties: [
13111				{
13112					name: "correlationKeyRef",
13113					type: "CorrelationKey",
13114					isAttr: true,
13115					isReference: true
13116				},
13117				{
13118					name: "correlationPropertyBinding",
13119					type: "CorrelationPropertyBinding",
13120					isMany: true
13121				}
13122			]
13123		},
13124		{
13125			name: "MessageFlow",
13126			superClass: [
13127				"BaseElement"
13128			],
13129			properties: [
13130				{
13131					name: "name",
13132					isAttr: true,
13133					type: "String"
13134				},
13135				{
13136					name: "sourceRef",
13137					type: "InteractionNode",
13138					isAttr: true,
13139					isReference: true
13140				},
13141				{
13142					name: "targetRef",
13143					type: "InteractionNode",
13144					isAttr: true,
13145					isReference: true
13146				},
13147				{
13148					name: "messageRef",
13149					type: "Message",
13150					isAttr: true,
13151					isReference: true
13152				}
13153			]
13154		},
13155		{
13156			name: "MessageFlowAssociation",
13157			superClass: [
13158				"BaseElement"
13159			],
13160			properties: [
13161				{
13162					name: "innerMessageFlowRef",
13163					type: "MessageFlow",
13164					isAttr: true,
13165					isReference: true
13166				},
13167				{
13168					name: "outerMessageFlowRef",
13169					type: "MessageFlow",
13170					isAttr: true,
13171					isReference: true
13172				}
13173			]
13174		},
13175		{
13176			name: "InteractionNode",
13177			isAbstract: true,
13178			properties: [
13179				{
13180					name: "incomingConversationLinks",
13181					type: "ConversationLink",
13182					isMany: true,
13183					isVirtual: true,
13184					isReference: true
13185				},
13186				{
13187					name: "outgoingConversationLinks",
13188					type: "ConversationLink",
13189					isMany: true,
13190					isVirtual: true,
13191					isReference: true
13192				}
13193			]
13194		},
13195		{
13196			name: "Participant",
13197			superClass: [
13198				"InteractionNode",
13199				"BaseElement"
13200			],
13201			properties: [
13202				{
13203					name: "name",
13204					isAttr: true,
13205					type: "String"
13206				},
13207				{
13208					name: "interfaceRef",
13209					type: "Interface",
13210					isMany: true,
13211					isReference: true
13212				},
13213				{
13214					name: "participantMultiplicity",
13215					type: "ParticipantMultiplicity"
13216				},
13217				{
13218					name: "endPointRefs",
13219					type: "EndPoint",
13220					isMany: true,
13221					isReference: true
13222				},
13223				{
13224					name: "processRef",
13225					type: "Process",
13226					isAttr: true,
13227					isReference: true
13228				}
13229			]
13230		},
13231		{
13232			name: "ParticipantAssociation",
13233			superClass: [
13234				"BaseElement"
13235			],
13236			properties: [
13237				{
13238					name: "innerParticipantRef",
13239					type: "Participant",
13240					isAttr: true,
13241					isReference: true
13242				},
13243				{
13244					name: "outerParticipantRef",
13245					type: "Participant",
13246					isAttr: true,
13247					isReference: true
13248				}
13249			]
13250		},
13251		{
13252			name: "ParticipantMultiplicity",
13253			properties: [
13254				{
13255					name: "minimum",
13256					"default": 0,
13257					isAttr: true,
13258					type: "Integer"
13259				},
13260				{
13261					name: "maximum",
13262					"default": 1,
13263					isAttr: true,
13264					type: "Integer"
13265				}
13266			],
13267			superClass: [
13268				"BaseElement"
13269			]
13270		},
13271		{
13272			name: "Collaboration",
13273			superClass: [
13274				"RootElement"
13275			],
13276			properties: [
13277				{
13278					name: "name",
13279					isAttr: true,
13280					type: "String"
13281				},
13282				{
13283					name: "isClosed",
13284					isAttr: true,
13285					type: "Boolean"
13286				},
13287				{
13288					name: "participants",
13289					type: "Participant",
13290					isMany: true
13291				},
13292				{
13293					name: "messageFlows",
13294					type: "MessageFlow",
13295					isMany: true
13296				},
13297				{
13298					name: "artifacts",
13299					type: "Artifact",
13300					isMany: true
13301				},
13302				{
13303					name: "conversations",
13304					type: "ConversationNode",
13305					isMany: true
13306				},
13307				{
13308					name: "conversationAssociations",
13309					type: "ConversationAssociation"
13310				},
13311				{
13312					name: "participantAssociations",
13313					type: "ParticipantAssociation",
13314					isMany: true
13315				},
13316				{
13317					name: "messageFlowAssociations",
13318					type: "MessageFlowAssociation",
13319					isMany: true
13320				},
13321				{
13322					name: "correlationKeys",
13323					type: "CorrelationKey",
13324					isMany: true
13325				},
13326				{
13327					name: "choreographyRef",
13328					type: "Choreography",
13329					isMany: true,
13330					isReference: true
13331				},
13332				{
13333					name: "conversationLinks",
13334					type: "ConversationLink",
13335					isMany: true
13336				}
13337			]
13338		},
13339		{
13340			name: "ChoreographyActivity",
13341			isAbstract: true,
13342			superClass: [
13343				"FlowNode"
13344			],
13345			properties: [
13346				{
13347					name: "participantRef",
13348					type: "Participant",
13349					isMany: true,
13350					isReference: true
13351				},
13352				{
13353					name: "initiatingParticipantRef",
13354					type: "Participant",
13355					isAttr: true,
13356					isReference: true
13357				},
13358				{
13359					name: "correlationKeys",
13360					type: "CorrelationKey",
13361					isMany: true
13362				},
13363				{
13364					name: "loopType",
13365					type: "ChoreographyLoopType",
13366					"default": "None",
13367					isAttr: true
13368				}
13369			]
13370		},
13371		{
13372			name: "CallChoreography",
13373			superClass: [
13374				"ChoreographyActivity"
13375			],
13376			properties: [
13377				{
13378					name: "calledChoreographyRef",
13379					type: "Choreography",
13380					isAttr: true,
13381					isReference: true
13382				},
13383				{
13384					name: "participantAssociations",
13385					type: "ParticipantAssociation",
13386					isMany: true
13387				}
13388			]
13389		},
13390		{
13391			name: "SubChoreography",
13392			superClass: [
13393				"ChoreographyActivity",
13394				"FlowElementsContainer"
13395			],
13396			properties: [
13397				{
13398					name: "artifacts",
13399					type: "Artifact",
13400					isMany: true
13401				}
13402			]
13403		},
13404		{
13405			name: "ChoreographyTask",
13406			superClass: [
13407				"ChoreographyActivity"
13408			],
13409			properties: [
13410				{
13411					name: "messageFlowRef",
13412					type: "MessageFlow",
13413					isMany: true,
13414					isReference: true
13415				}
13416			]
13417		},
13418		{
13419			name: "Choreography",
13420			superClass: [
13421				"Collaboration",
13422				"FlowElementsContainer"
13423			]
13424		},
13425		{
13426			name: "GlobalChoreographyTask",
13427			superClass: [
13428				"Choreography"
13429			],
13430			properties: [
13431				{
13432					name: "initiatingParticipantRef",
13433					type: "Participant",
13434					isAttr: true,
13435					isReference: true
13436				}
13437			]
13438		},
13439		{
13440			name: "TextAnnotation",
13441			superClass: [
13442				"Artifact"
13443			],
13444			properties: [
13445				{
13446					name: "text",
13447					type: "String"
13448				},
13449				{
13450					name: "textFormat",
13451					"default": "text/plain",
13452					isAttr: true,
13453					type: "String"
13454				}
13455			]
13456		},
13457		{
13458			name: "Group",
13459			superClass: [
13460				"Artifact"
13461			],
13462			properties: [
13463				{
13464					name: "categoryValueRef",
13465					type: "CategoryValue",
13466					isAttr: true,
13467					isReference: true
13468				}
13469			]
13470		},
13471		{
13472			name: "Association",
13473			superClass: [
13474				"Artifact"
13475			],
13476			properties: [
13477				{
13478					name: "associationDirection",
13479					type: "AssociationDirection",
13480					isAttr: true
13481				},
13482				{
13483					name: "sourceRef",
13484					type: "BaseElement",
13485					isAttr: true,
13486					isReference: true
13487				},
13488				{
13489					name: "targetRef",
13490					type: "BaseElement",
13491					isAttr: true,
13492					isReference: true
13493				}
13494			]
13495		},
13496		{
13497			name: "Category",
13498			superClass: [
13499				"RootElement"
13500			],
13501			properties: [
13502				{
13503					name: "categoryValue",
13504					type: "CategoryValue",
13505					isMany: true
13506				},
13507				{
13508					name: "name",
13509					isAttr: true,
13510					type: "String"
13511				}
13512			]
13513		},
13514		{
13515			name: "Artifact",
13516			isAbstract: true,
13517			superClass: [
13518				"BaseElement"
13519			]
13520		},
13521		{
13522			name: "CategoryValue",
13523			superClass: [
13524				"BaseElement"
13525			],
13526			properties: [
13527				{
13528					name: "categorizedFlowElements",
13529					type: "FlowElement",
13530					isMany: true,
13531					isVirtual: true,
13532					isReference: true
13533				},
13534				{
13535					name: "value",
13536					isAttr: true,
13537					type: "String"
13538				}
13539			]
13540		},
13541		{
13542			name: "Activity",
13543			isAbstract: true,
13544			superClass: [
13545				"FlowNode"
13546			],
13547			properties: [
13548				{
13549					name: "isForCompensation",
13550					"default": false,
13551					isAttr: true,
13552					type: "Boolean"
13553				},
13554				{
13555					name: "default",
13556					type: "SequenceFlow",
13557					isAttr: true,
13558					isReference: true
13559				},
13560				{
13561					name: "ioSpecification",
13562					type: "InputOutputSpecification",
13563					xml: {
13564						serialize: "property"
13565					}
13566				},
13567				{
13568					name: "boundaryEventRefs",
13569					type: "BoundaryEvent",
13570					isMany: true,
13571					isReference: true
13572				},
13573				{
13574					name: "properties",
13575					type: "Property",
13576					isMany: true
13577				},
13578				{
13579					name: "dataInputAssociations",
13580					type: "DataInputAssociation",
13581					isMany: true
13582				},
13583				{
13584					name: "dataOutputAssociations",
13585					type: "DataOutputAssociation",
13586					isMany: true
13587				},
13588				{
13589					name: "startQuantity",
13590					"default": 1,
13591					isAttr: true,
13592					type: "Integer"
13593				},
13594				{
13595					name: "resources",
13596					type: "ResourceRole",
13597					isMany: true
13598				},
13599				{
13600					name: "completionQuantity",
13601					"default": 1,
13602					isAttr: true,
13603					type: "Integer"
13604				},
13605				{
13606					name: "loopCharacteristics",
13607					type: "LoopCharacteristics"
13608				}
13609			]
13610		},
13611		{
13612			name: "ServiceTask",
13613			superClass: [
13614				"Task"
13615			],
13616			properties: [
13617				{
13618					name: "implementation",
13619					isAttr: true,
13620					type: "String"
13621				},
13622				{
13623					name: "operationRef",
13624					type: "Operation",
13625					isAttr: true,
13626					isReference: true
13627				}
13628			]
13629		},
13630		{
13631			name: "SubProcess",
13632			superClass: [
13633				"Activity",
13634				"FlowElementsContainer",
13635				"InteractionNode"
13636			],
13637			properties: [
13638				{
13639					name: "triggeredByEvent",
13640					"default": false,
13641					isAttr: true,
13642					type: "Boolean"
13643				},
13644				{
13645					name: "artifacts",
13646					type: "Artifact",
13647					isMany: true
13648				}
13649			]
13650		},
13651		{
13652			name: "LoopCharacteristics",
13653			isAbstract: true,
13654			superClass: [
13655				"BaseElement"
13656			]
13657		},
13658		{
13659			name: "MultiInstanceLoopCharacteristics",
13660			superClass: [
13661				"LoopCharacteristics"
13662			],
13663			properties: [
13664				{
13665					name: "isSequential",
13666					"default": false,
13667					isAttr: true,
13668					type: "Boolean"
13669				},
13670				{
13671					name: "behavior",
13672					type: "MultiInstanceBehavior",
13673					"default": "All",
13674					isAttr: true
13675				},
13676				{
13677					name: "loopCardinality",
13678					type: "Expression",
13679					xml: {
13680						serialize: "xsi:type"
13681					}
13682				},
13683				{
13684					name: "loopDataInputRef",
13685					type: "ItemAwareElement",
13686					isReference: true
13687				},
13688				{
13689					name: "loopDataOutputRef",
13690					type: "ItemAwareElement",
13691					isReference: true
13692				},
13693				{
13694					name: "inputDataItem",
13695					type: "DataInput",
13696					xml: {
13697						serialize: "property"
13698					}
13699				},
13700				{
13701					name: "outputDataItem",
13702					type: "DataOutput",
13703					xml: {
13704						serialize: "property"
13705					}
13706				},
13707				{
13708					name: "complexBehaviorDefinition",
13709					type: "ComplexBehaviorDefinition",
13710					isMany: true
13711				},
13712				{
13713					name: "completionCondition",
13714					type: "Expression",
13715					xml: {
13716						serialize: "xsi:type"
13717					}
13718				},
13719				{
13720					name: "oneBehaviorEventRef",
13721					type: "EventDefinition",
13722					isAttr: true,
13723					isReference: true
13724				},
13725				{
13726					name: "noneBehaviorEventRef",
13727					type: "EventDefinition",
13728					isAttr: true,
13729					isReference: true
13730				}
13731			]
13732		},
13733		{
13734			name: "StandardLoopCharacteristics",
13735			superClass: [
13736				"LoopCharacteristics"
13737			],
13738			properties: [
13739				{
13740					name: "testBefore",
13741					"default": false,
13742					isAttr: true,
13743					type: "Boolean"
13744				},
13745				{
13746					name: "loopCondition",
13747					type: "Expression",
13748					xml: {
13749						serialize: "xsi:type"
13750					}
13751				},
13752				{
13753					name: "loopMaximum",
13754					type: "Integer",
13755					isAttr: true
13756				}
13757			]
13758		},
13759		{
13760			name: "CallActivity",
13761			superClass: [
13762				"Activity",
13763				"InteractionNode"
13764			],
13765			properties: [
13766				{
13767					name: "calledElement",
13768					type: "String",
13769					isAttr: true
13770				}
13771			]
13772		},
13773		{
13774			name: "Task",
13775			superClass: [
13776				"Activity",
13777				"InteractionNode"
13778			]
13779		},
13780		{
13781			name: "SendTask",
13782			superClass: [
13783				"Task"
13784			],
13785			properties: [
13786				{
13787					name: "implementation",
13788					isAttr: true,
13789					type: "String"
13790				},
13791				{
13792					name: "operationRef",
13793					type: "Operation",
13794					isAttr: true,
13795					isReference: true
13796				},
13797				{
13798					name: "messageRef",
13799					type: "Message",
13800					isAttr: true,
13801					isReference: true
13802				}
13803			]
13804		},
13805		{
13806			name: "ReceiveTask",
13807			superClass: [
13808				"Task"
13809			],
13810			properties: [
13811				{
13812					name: "implementation",
13813					isAttr: true,
13814					type: "String"
13815				},
13816				{
13817					name: "instantiate",
13818					"default": false,
13819					isAttr: true,
13820					type: "Boolean"
13821				},
13822				{
13823					name: "operationRef",
13824					type: "Operation",
13825					isAttr: true,
13826					isReference: true
13827				},
13828				{
13829					name: "messageRef",
13830					type: "Message",
13831					isAttr: true,
13832					isReference: true
13833				}
13834			]
13835		},
13836		{
13837			name: "ScriptTask",
13838			superClass: [
13839				"Task"
13840			],
13841			properties: [
13842				{
13843					name: "scriptFormat",
13844					isAttr: true,
13845					type: "String"
13846				},
13847				{
13848					name: "script",
13849					type: "String"
13850				}
13851			]
13852		},
13853		{
13854			name: "BusinessRuleTask",
13855			superClass: [
13856				"Task"
13857			],
13858			properties: [
13859				{
13860					name: "implementation",
13861					isAttr: true,
13862					type: "String"
13863				}
13864			]
13865		},
13866		{
13867			name: "AdHocSubProcess",
13868			superClass: [
13869				"SubProcess"
13870			],
13871			properties: [
13872				{
13873					name: "completionCondition",
13874					type: "Expression",
13875					xml: {
13876						serialize: "xsi:type"
13877					}
13878				},
13879				{
13880					name: "ordering",
13881					type: "AdHocOrdering",
13882					isAttr: true
13883				},
13884				{
13885					name: "cancelRemainingInstances",
13886					"default": true,
13887					isAttr: true,
13888					type: "Boolean"
13889				}
13890			]
13891		},
13892		{
13893			name: "Transaction",
13894			superClass: [
13895				"SubProcess"
13896			],
13897			properties: [
13898				{
13899					name: "protocol",
13900					isAttr: true,
13901					type: "String"
13902				},
13903				{
13904					name: "method",
13905					isAttr: true,
13906					type: "String"
13907				}
13908			]
13909		},
13910		{
13911			name: "GlobalScriptTask",
13912			superClass: [
13913				"GlobalTask"
13914			],
13915			properties: [
13916				{
13917					name: "scriptLanguage",
13918					isAttr: true,
13919					type: "String"
13920				},
13921				{
13922					name: "script",
13923					isAttr: true,
13924					type: "String"
13925				}
13926			]
13927		},
13928		{
13929			name: "GlobalBusinessRuleTask",
13930			superClass: [
13931				"GlobalTask"
13932			],
13933			properties: [
13934				{
13935					name: "implementation",
13936					isAttr: true,
13937					type: "String"
13938				}
13939			]
13940		},
13941		{
13942			name: "ComplexBehaviorDefinition",
13943			superClass: [
13944				"BaseElement"
13945			],
13946			properties: [
13947				{
13948					name: "condition",
13949					type: "FormalExpression"
13950				},
13951				{
13952					name: "event",
13953					type: "ImplicitThrowEvent"
13954				}
13955			]
13956		},
13957		{
13958			name: "ResourceRole",
13959			superClass: [
13960				"BaseElement"
13961			],
13962			properties: [
13963				{
13964					name: "resourceRef",
13965					type: "Resource",
13966					isReference: true
13967				},
13968				{
13969					name: "resourceParameterBindings",
13970					type: "ResourceParameterBinding",
13971					isMany: true
13972				},
13973				{
13974					name: "resourceAssignmentExpression",
13975					type: "ResourceAssignmentExpression"
13976				},
13977				{
13978					name: "name",
13979					isAttr: true,
13980					type: "String"
13981				}
13982			]
13983		},
13984		{
13985			name: "ResourceParameterBinding",
13986			properties: [
13987				{
13988					name: "expression",
13989					type: "Expression",
13990					xml: {
13991						serialize: "xsi:type"
13992					}
13993				},
13994				{
13995					name: "parameterRef",
13996					type: "ResourceParameter",
13997					isAttr: true,
13998					isReference: true
13999				}
14000			],
14001			superClass: [
14002				"BaseElement"
14003			]
14004		},
14005		{
14006			name: "ResourceAssignmentExpression",
14007			properties: [
14008				{
14009					name: "expression",
14010					type: "Expression",
14011					xml: {
14012						serialize: "xsi:type"
14013					}
14014				}
14015			],
14016			superClass: [
14017				"BaseElement"
14018			]
14019		},
14020		{
14021			name: "Import",
14022			properties: [
14023				{
14024					name: "importType",
14025					isAttr: true,
14026					type: "String"
14027				},
14028				{
14029					name: "location",
14030					isAttr: true,
14031					type: "String"
14032				},
14033				{
14034					name: "namespace",
14035					isAttr: true,
14036					type: "String"
14037				}
14038			]
14039		},
14040		{
14041			name: "Definitions",
14042			superClass: [
14043				"BaseElement"
14044			],
14045			properties: [
14046				{
14047					name: "name",
14048					isAttr: true,
14049					type: "String"
14050				},
14051				{
14052					name: "targetNamespace",
14053					isAttr: true,
14054					type: "String"
14055				},
14056				{
14057					name: "expressionLanguage",
14058					"default": "http://www.w3.org/1999/XPath",
14059					isAttr: true,
14060					type: "String"
14061				},
14062				{
14063					name: "typeLanguage",
14064					"default": "http://www.w3.org/2001/XMLSchema",
14065					isAttr: true,
14066					type: "String"
14067				},
14068				{
14069					name: "imports",
14070					type: "Import",
14071					isMany: true
14072				},
14073				{
14074					name: "extensions",
14075					type: "Extension",
14076					isMany: true
14077				},
14078				{
14079					name: "rootElements",
14080					type: "RootElement",
14081					isMany: true
14082				},
14083				{
14084					name: "diagrams",
14085					isMany: true,
14086					type: "bpmndi:BPMNDiagram"
14087				},
14088				{
14089					name: "exporter",
14090					isAttr: true,
14091					type: "String"
14092				},
14093				{
14094					name: "relationships",
14095					type: "Relationship",
14096					isMany: true
14097				},
14098				{
14099					name: "exporterVersion",
14100					isAttr: true,
14101					type: "String"
14102				}
14103			]
14104		}
14105	];
14106	var enumerations = [
14107		{
14108			name: "ProcessType",
14109			literalValues: [
14110				{
14111					name: "None"
14112				},
14113				{
14114					name: "Public"
14115				},
14116				{
14117					name: "Private"
14118				}
14119			]
14120		},
14121		{
14122			name: "GatewayDirection",
14123			literalValues: [
14124				{
14125					name: "Unspecified"
14126				},
14127				{
14128					name: "Converging"
14129				},
14130				{
14131					name: "Diverging"
14132				},
14133				{
14134					name: "Mixed"
14135				}
14136			]
14137		},
14138		{
14139			name: "EventBasedGatewayType",
14140			literalValues: [
14141				{
14142					name: "Parallel"
14143				},
14144				{
14145					name: "Exclusive"
14146				}
14147			]
14148		},
14149		{
14150			name: "RelationshipDirection",
14151			literalValues: [
14152				{
14153					name: "None"
14154				},
14155				{
14156					name: "Forward"
14157				},
14158				{
14159					name: "Backward"
14160				},
14161				{
14162					name: "Both"
14163				}
14164			]
14165		},
14166		{
14167			name: "ItemKind",
14168			literalValues: [
14169				{
14170					name: "Physical"
14171				},
14172				{
14173					name: "Information"
14174				}
14175			]
14176		},
14177		{
14178			name: "ChoreographyLoopType",
14179			literalValues: [
14180				{
14181					name: "None"
14182				},
14183				{
14184					name: "Standard"
14185				},
14186				{
14187					name: "MultiInstanceSequential"
14188				},
14189				{
14190					name: "MultiInstanceParallel"
14191				}
14192			]
14193		},
14194		{
14195			name: "AssociationDirection",
14196			literalValues: [
14197				{
14198					name: "None"
14199				},
14200				{
14201					name: "One"
14202				},
14203				{
14204					name: "Both"
14205				}
14206			]
14207		},
14208		{
14209			name: "MultiInstanceBehavior",
14210			literalValues: [
14211				{
14212					name: "None"
14213				},
14214				{
14215					name: "One"
14216				},
14217				{
14218					name: "All"
14219				},
14220				{
14221					name: "Complex"
14222				}
14223			]
14224		},
14225		{
14226			name: "AdHocOrdering",
14227			literalValues: [
14228				{
14229					name: "Parallel"
14230				},
14231				{
14232					name: "Sequential"
14233				}
14234			]
14235		}
14236	];
14237	var xml = {
14238		tagAlias: "lowerCase",
14239		typePrefix: "t"
14240	};
14241	var BpmnPackage = {
14242		name: name,
14243		uri: uri,
14244		prefix: prefix,
14245		associations: associations,
14246		types: types,
14247		enumerations: enumerations,
14248		xml: xml
14249	};
14250
14251	var name$1 = "BPMNDI";
14252	var uri$1 = "http://www.omg.org/spec/BPMN/20100524/DI";
14253	var prefix$1 = "bpmndi";
14254	var types$1 = [
14255		{
14256			name: "BPMNDiagram",
14257			properties: [
14258				{
14259					name: "plane",
14260					type: "BPMNPlane",
14261					redefines: "di:Diagram#rootElement"
14262				},
14263				{
14264					name: "labelStyle",
14265					type: "BPMNLabelStyle",
14266					isMany: true
14267				}
14268			],
14269			superClass: [
14270				"di:Diagram"
14271			]
14272		},
14273		{
14274			name: "BPMNPlane",
14275			properties: [
14276				{
14277					name: "bpmnElement",
14278					isAttr: true,
14279					isReference: true,
14280					type: "bpmn:BaseElement",
14281					redefines: "di:DiagramElement#modelElement"
14282				}
14283			],
14284			superClass: [
14285				"di:Plane"
14286			]
14287		},
14288		{
14289			name: "BPMNShape",
14290			properties: [
14291				{
14292					name: "bpmnElement",
14293					isAttr: true,
14294					isReference: true,
14295					type: "bpmn:BaseElement",
14296					redefines: "di:DiagramElement#modelElement"
14297				},
14298				{
14299					name: "isHorizontal",
14300					isAttr: true,
14301					type: "Boolean"
14302				},
14303				{
14304					name: "isExpanded",
14305					isAttr: true,
14306					type: "Boolean"
14307				},
14308				{
14309					name: "isMarkerVisible",
14310					isAttr: true,
14311					type: "Boolean"
14312				},
14313				{
14314					name: "label",
14315					type: "BPMNLabel"
14316				},
14317				{
14318					name: "isMessageVisible",
14319					isAttr: true,
14320					type: "Boolean"
14321				},
14322				{
14323					name: "participantBandKind",
14324					type: "ParticipantBandKind",
14325					isAttr: true
14326				},
14327				{
14328					name: "choreographyActivityShape",
14329					type: "BPMNShape",
14330					isAttr: true,
14331					isReference: true
14332				}
14333			],
14334			superClass: [
14335				"di:LabeledShape"
14336			]
14337		},
14338		{
14339			name: "BPMNEdge",
14340			properties: [
14341				{
14342					name: "label",
14343					type: "BPMNLabel"
14344				},
14345				{
14346					name: "bpmnElement",
14347					isAttr: true,
14348					isReference: true,
14349					type: "bpmn:BaseElement",
14350					redefines: "di:DiagramElement#modelElement"
14351				},
14352				{
14353					name: "sourceElement",
14354					isAttr: true,
14355					isReference: true,
14356					type: "di:DiagramElement",
14357					redefines: "di:Edge#source"
14358				},
14359				{
14360					name: "targetElement",
14361					isAttr: true,
14362					isReference: true,
14363					type: "di:DiagramElement",
14364					redefines: "di:Edge#target"
14365				},
14366				{
14367					name: "messageVisibleKind",
14368					type: "MessageVisibleKind",
14369					isAttr: true,
14370					"default": "initiating"
14371				}
14372			],
14373			superClass: [
14374				"di:LabeledEdge"
14375			]
14376		},
14377		{
14378			name: "BPMNLabel",
14379			properties: [
14380				{
14381					name: "labelStyle",
14382					type: "BPMNLabelStyle",
14383					isAttr: true,
14384					isReference: true,
14385					redefines: "di:DiagramElement#style"
14386				}
14387			],
14388			superClass: [
14389				"di:Label"
14390			]
14391		},
14392		{
14393			name: "BPMNLabelStyle",
14394			properties: [
14395				{
14396					name: "font",
14397					type: "dc:Font"
14398				}
14399			],
14400			superClass: [
14401				"di:Style"
14402			]
14403		}
14404	];
14405	var enumerations$1 = [
14406		{
14407			name: "ParticipantBandKind",
14408			literalValues: [
14409				{
14410					name: "top_initiating"
14411				},
14412				{
14413					name: "middle_initiating"
14414				},
14415				{
14416					name: "bottom_initiating"
14417				},
14418				{
14419					name: "top_non_initiating"
14420				},
14421				{
14422					name: "middle_non_initiating"
14423				},
14424				{
14425					name: "bottom_non_initiating"
14426				}
14427			]
14428		},
14429		{
14430			name: "MessageVisibleKind",
14431			literalValues: [
14432				{
14433					name: "initiating"
14434				},
14435				{
14436					name: "non_initiating"
14437				}
14438			]
14439		}
14440	];
14441	var associations$1 = [
14442	];
14443	var BpmnDiPackage = {
14444		name: name$1,
14445		uri: uri$1,
14446		prefix: prefix$1,
14447		types: types$1,
14448		enumerations: enumerations$1,
14449		associations: associations$1
14450	};
14451
14452	var name$2 = "DC";
14453	var uri$2 = "http://www.omg.org/spec/DD/20100524/DC";
14454	var prefix$2 = "dc";
14455	var types$2 = [
14456		{
14457			name: "Boolean"
14458		},
14459		{
14460			name: "Integer"
14461		},
14462		{
14463			name: "Real"
14464		},
14465		{
14466			name: "String"
14467		},
14468		{
14469			name: "Font",
14470			properties: [
14471				{
14472					name: "name",
14473					type: "String",
14474					isAttr: true
14475				},
14476				{
14477					name: "size",
14478					type: "Real",
14479					isAttr: true
14480				},
14481				{
14482					name: "isBold",
14483					type: "Boolean",
14484					isAttr: true
14485				},
14486				{
14487					name: "isItalic",
14488					type: "Boolean",
14489					isAttr: true
14490				},
14491				{
14492					name: "isUnderline",
14493					type: "Boolean",
14494					isAttr: true
14495				},
14496				{
14497					name: "isStrikeThrough",
14498					type: "Boolean",
14499					isAttr: true
14500				}
14501			]
14502		},
14503		{
14504			name: "Point",
14505			properties: [
14506				{
14507					name: "x",
14508					type: "Real",
14509					"default": "0",
14510					isAttr: true
14511				},
14512				{
14513					name: "y",
14514					type: "Real",
14515					"default": "0",
14516					isAttr: true
14517				}
14518			]
14519		},
14520		{
14521			name: "Bounds",
14522			properties: [
14523				{
14524					name: "x",
14525					type: "Real",
14526					"default": "0",
14527					isAttr: true
14528				},
14529				{
14530					name: "y",
14531					type: "Real",
14532					"default": "0",
14533					isAttr: true
14534				},
14535				{
14536					name: "width",
14537					type: "Real",
14538					isAttr: true
14539				},
14540				{
14541					name: "height",
14542					type: "Real",
14543					isAttr: true
14544				}
14545			]
14546		}
14547	];
14548	var associations$2 = [
14549	];
14550	var DcPackage = {
14551		name: name$2,
14552		uri: uri$2,
14553		prefix: prefix$2,
14554		types: types$2,
14555		associations: associations$2
14556	};
14557
14558	var name$3 = "DI";
14559	var uri$3 = "http://www.omg.org/spec/DD/20100524/DI";
14560	var prefix$3 = "di";
14561	var types$3 = [
14562		{
14563			name: "DiagramElement",
14564			isAbstract: true,
14565			properties: [
14566				{
14567					name: "id",
14568					isAttr: true,
14569					isId: true,
14570					type: "String"
14571				},
14572				{
14573					name: "extension",
14574					type: "Extension"
14575				},
14576				{
14577					name: "owningDiagram",
14578					type: "Diagram",
14579					isReadOnly: true,
14580					isVirtual: true,
14581					isReference: true
14582				},
14583				{
14584					name: "owningElement",
14585					type: "DiagramElement",
14586					isReadOnly: true,
14587					isVirtual: true,
14588					isReference: true
14589				},
14590				{
14591					name: "modelElement",
14592					isReadOnly: true,
14593					isVirtual: true,
14594					isReference: true,
14595					type: "Element"
14596				},
14597				{
14598					name: "style",
14599					type: "Style",
14600					isReadOnly: true,
14601					isVirtual: true,
14602					isReference: true
14603				},
14604				{
14605					name: "ownedElement",
14606					type: "DiagramElement",
14607					isReadOnly: true,
14608					isMany: true,
14609					isVirtual: true
14610				}
14611			]
14612		},
14613		{
14614			name: "Node",
14615			isAbstract: true,
14616			superClass: [
14617				"DiagramElement"
14618			]
14619		},
14620		{
14621			name: "Edge",
14622			isAbstract: true,
14623			superClass: [
14624				"DiagramElement"
14625			],
14626			properties: [
14627				{
14628					name: "source",
14629					type: "DiagramElement",
14630					isReadOnly: true,
14631					isVirtual: true,
14632					isReference: true
14633				},
14634				{
14635					name: "target",
14636					type: "DiagramElement",
14637					isReadOnly: true,
14638					isVirtual: true,
14639					isReference: true
14640				},
14641				{
14642					name: "waypoint",
14643					isUnique: false,
14644					isMany: true,
14645					type: "dc:Point",
14646					xml: {
14647						serialize: "xsi:type"
14648					}
14649				}
14650			]
14651		},
14652		{
14653			name: "Diagram",
14654			isAbstract: true,
14655			properties: [
14656				{
14657					name: "id",
14658					isAttr: true,
14659					isId: true,
14660					type: "String"
14661				},
14662				{
14663					name: "rootElement",
14664					type: "DiagramElement",
14665					isReadOnly: true,
14666					isVirtual: true
14667				},
14668				{
14669					name: "name",
14670					isAttr: true,
14671					type: "String"
14672				},
14673				{
14674					name: "documentation",
14675					isAttr: true,
14676					type: "String"
14677				},
14678				{
14679					name: "resolution",
14680					isAttr: true,
14681					type: "Real"
14682				},
14683				{
14684					name: "ownedStyle",
14685					type: "Style",
14686					isReadOnly: true,
14687					isMany: true,
14688					isVirtual: true
14689				}
14690			]
14691		},
14692		{
14693			name: "Shape",
14694			isAbstract: true,
14695			superClass: [
14696				"Node"
14697			],
14698			properties: [
14699				{
14700					name: "bounds",
14701					type: "dc:Bounds"
14702				}
14703			]
14704		},
14705		{
14706			name: "Plane",
14707			isAbstract: true,
14708			superClass: [
14709				"Node"
14710			],
14711			properties: [
14712				{
14713					name: "planeElement",
14714					type: "DiagramElement",
14715					subsettedProperty: "DiagramElement-ownedElement",
14716					isMany: true
14717				}
14718			]
14719		},
14720		{
14721			name: "LabeledEdge",
14722			isAbstract: true,
14723			superClass: [
14724				"Edge"
14725			],
14726			properties: [
14727				{
14728					name: "ownedLabel",
14729					type: "Label",
14730					isReadOnly: true,
14731					subsettedProperty: "DiagramElement-ownedElement",
14732					isMany: true,
14733					isVirtual: true
14734				}
14735			]
14736		},
14737		{
14738			name: "LabeledShape",
14739			isAbstract: true,
14740			superClass: [
14741				"Shape"
14742			],
14743			properties: [
14744				{
14745					name: "ownedLabel",
14746					type: "Label",
14747					isReadOnly: true,
14748					subsettedProperty: "DiagramElement-ownedElement",
14749					isMany: true,
14750					isVirtual: true
14751				}
14752			]
14753		},
14754		{
14755			name: "Label",
14756			isAbstract: true,
14757			superClass: [
14758				"Node"
14759			],
14760			properties: [
14761				{
14762					name: "bounds",
14763					type: "dc:Bounds"
14764				}
14765			]
14766		},
14767		{
14768			name: "Style",
14769			isAbstract: true,
14770			properties: [
14771				{
14772					name: "id",
14773					isAttr: true,
14774					isId: true,
14775					type: "String"
14776				}
14777			]
14778		},
14779		{
14780			name: "Extension",
14781			properties: [
14782				{
14783					name: "values",
14784					isMany: true,
14785					type: "Element"
14786				}
14787			]
14788		}
14789	];
14790	var associations$3 = [
14791	];
14792	var xml$1 = {
14793		tagAlias: "lowerCase"
14794	};
14795	var DiPackage = {
14796		name: name$3,
14797		uri: uri$3,
14798		prefix: prefix$3,
14799		types: types$3,
14800		associations: associations$3,
14801		xml: xml$1
14802	};
14803
14804	var name$4 = "bpmn.io colors for BPMN";
14805	var uri$4 = "http://bpmn.io/schema/bpmn/biocolor/1.0";
14806	var prefix$4 = "bioc";
14807	var types$4 = [
14808		{
14809			name: "ColoredShape",
14810			"extends": [
14811				"bpmndi:BPMNShape"
14812			],
14813			properties: [
14814				{
14815					name: "stroke",
14816					isAttr: true,
14817					type: "String"
14818				},
14819				{
14820					name: "fill",
14821					isAttr: true,
14822					type: "String"
14823				}
14824			]
14825		},
14826		{
14827			name: "ColoredEdge",
14828			"extends": [
14829				"bpmndi:BPMNEdge"
14830			],
14831			properties: [
14832				{
14833					name: "stroke",
14834					isAttr: true,
14835					type: "String"
14836				},
14837				{
14838					name: "fill",
14839					isAttr: true,
14840					type: "String"
14841				}
14842			]
14843		}
14844	];
14845	var enumerations$2 = [
14846	];
14847	var associations$4 = [
14848	];
14849	var BiocPackage = {
14850		name: name$4,
14851		uri: uri$4,
14852		prefix: prefix$4,
14853		types: types$4,
14854		enumerations: enumerations$2,
14855		associations: associations$4
14856	};
14857
14858	var name$5 = "BPMN in Color";
14859	var uri$5 = "http://www.omg.org/spec/BPMN/non-normative/color/1.0";
14860	var prefix$5 = "color";
14861	var types$5 = [
14862		{
14863			name: "ColoredLabel",
14864			"extends": [
14865				"bpmndi:BPMNLabel"
14866			],
14867			properties: [
14868				{
14869					name: "color",
14870					isAttr: true,
14871					type: "String"
14872				}
14873			]
14874		},
14875		{
14876			name: "ColoredShape",
14877			"extends": [
14878				"bpmndi:BPMNShape"
14879			],
14880			properties: [
14881				{
14882					name: "background-color",
14883					isAttr: true,
14884					type: "String"
14885				},
14886				{
14887					name: "border-color",
14888					isAttr: true,
14889					type: "String"
14890				}
14891			]
14892		},
14893		{
14894			name: "ColoredEdge",
14895			"extends": [
14896				"bpmndi:BPMNEdge"
14897			],
14898			properties: [
14899				{
14900					name: "border-color",
14901					isAttr: true,
14902					type: "String"
14903				}
14904			]
14905		}
14906	];
14907	var enumerations$3 = [
14908	];
14909	var associations$5 = [
14910	];
14911	var BpmnInColorPackage = {
14912		name: name$5,
14913		uri: uri$5,
14914		prefix: prefix$5,
14915		types: types$5,
14916		enumerations: enumerations$3,
14917		associations: associations$5
14918	};
14919
14920	var packages = {
14921	  bpmn: BpmnPackage,
14922	  bpmndi: BpmnDiPackage,
14923	  dc: DcPackage,
14924	  di: DiPackage,
14925	  bioc: BiocPackage,
14926	  color: BpmnInColorPackage
14927	};
14928
14929	function simple(additionalPackages, options) {
14930	  var pks = assign({}, packages, additionalPackages);
14931
14932	  return new BpmnModdle(pks, options);
14933	}
14934
14935	function elementToString(e) {
14936	  if (!e) {
14937	    return '<null>';
14938	  }
14939
14940	  return '<' + e.$type + (e.id ? ' id="' + e.id : '') + '" />';
14941	}
14942
14943	var diRefs = new Refs(
14944	  { name: 'bpmnElement', enumerable: true },
14945	  { name: 'di', configurable: true }
14946	);
14947
14948	/**
14949	 * Returns true if an element has the given meta-model type
14950	 *
14951	 * @param  {ModdleElement}  element
14952	 * @param  {string}         type
14953	 *
14954	 * @return {boolean}
14955	 */
14956	function is$2(element, type) {
14957	  return element.$instanceOf(type);
14958	}
14959
14960
14961	/**
14962	 * Find a suitable display candidate for definitions where the DI does not
14963	 * correctly specify one.
14964	 */
14965	function findDisplayCandidate(definitions) {
14966	  return find(definitions.rootElements, function(e) {
14967	    return is$2(e, 'bpmn:Process') || is$2(e, 'bpmn:Collaboration');
14968	  });
14969	}
14970
14971
14972	function BpmnTreeWalker(handler, translate) {
14973
14974	  // list of containers already walked
14975	  var handledElements = {};
14976
14977	  // list of elements to handle deferred to ensure
14978	  // prerequisites are drawn
14979	  var deferred = [];
14980
14981	  // Helpers //////////////////////
14982
14983	  function contextual(fn, ctx) {
14984	    return function(e) {
14985	      fn(e, ctx);
14986	    };
14987	  }
14988
14989	  function handled(element) {
14990	    handledElements[element.id] = element;
14991	  }
14992
14993	  function isHandled(element) {
14994	    return handledElements[element.id];
14995	  }
14996
14997	  function visit(element, ctx) {
14998
14999	    var gfx = element.gfx;
15000
15001	    // avoid multiple rendering of elements
15002	    if (gfx) {
15003	      throw new Error(
15004	        translate('already rendered {element}', { element: elementToString(element) })
15005	      );
15006	    }
15007
15008	    // call handler
15009	    return handler.element(element, ctx);
15010	  }
15011
15012	  function visitRoot(element, diagram) {
15013	    return handler.root(element, diagram);
15014	  }
15015
15016	  function visitIfDi(element, ctx) {
15017
15018	    try {
15019	      var gfx = element.di && visit(element, ctx);
15020
15021	      handled(element);
15022
15023	      return gfx;
15024	    } catch (e) {
15025	      logError(e.message, { element: element, error: e });
15026
15027	      console.error(translate('failed to import {element}', { element: elementToString(element) }));
15028	      console.error(e);
15029	    }
15030	  }
15031
15032	  function logError(message, context) {
15033	    handler.error(message, context);
15034	  }
15035
15036	  // DI handling //////////////////////
15037
15038	  function registerDi(di) {
15039	    var bpmnElement = di.bpmnElement;
15040
15041	    if (bpmnElement) {
15042	      if (bpmnElement.di) {
15043	        logError(
15044	          translate('multiple DI elements defined for {element}', {
15045	            element: elementToString(bpmnElement)
15046	          }),
15047	          { element: bpmnElement }
15048	        );
15049	      } else {
15050	        diRefs.bind(bpmnElement, 'di');
15051	        bpmnElement.di = di;
15052	      }
15053	    } else {
15054	      logError(
15055	        translate('no bpmnElement referenced in {element}', {
15056	          element: elementToString(di)
15057	        }),
15058	        { element: di }
15059	      );
15060	    }
15061	  }
15062
15063	  function handleDiagram(diagram) {
15064	    handlePlane(diagram.plane);
15065	  }
15066
15067	  function handlePlane(plane) {
15068	    registerDi(plane);
15069
15070	    forEach(plane.planeElement, handlePlaneElement);
15071	  }
15072
15073	  function handlePlaneElement(planeElement) {
15074	    registerDi(planeElement);
15075	  }
15076
15077
15078	  // Semantic handling //////////////////////
15079
15080	  /**
15081	   * Handle definitions and return the rendered diagram (if any)
15082	   *
15083	   * @param {ModdleElement} definitions to walk and import
15084	   * @param {ModdleElement} [diagram] specific diagram to import and display
15085	   *
15086	   * @throws {Error} if no diagram to display could be found
15087	   */
15088	  function handleDefinitions(definitions, diagram) {
15089
15090	    // make sure we walk the correct bpmnElement
15091
15092	    var diagrams = definitions.diagrams;
15093
15094	    if (diagram && diagrams.indexOf(diagram) === -1) {
15095	      throw new Error(translate('diagram not part of bpmn:Definitions'));
15096	    }
15097
15098	    if (!diagram && diagrams && diagrams.length) {
15099	      diagram = diagrams[0];
15100	    }
15101
15102	    // no diagram -> nothing to import
15103	    if (!diagram) {
15104	      throw new Error(translate('no diagram to display'));
15105	    }
15106
15107	    // load DI from selected diagram only
15108	    handleDiagram(diagram);
15109
15110
15111	    var plane = diagram.plane;
15112
15113	    if (!plane) {
15114	      throw new Error(translate(
15115	        'no plane for {element}',
15116	        { element: elementToString(diagram) }
15117	      ));
15118	    }
15119
15120	    var rootElement = plane.bpmnElement;
15121
15122	    // ensure we default to a suitable display candidate (process or collaboration),
15123	    // even if non is specified in DI
15124	    if (!rootElement) {
15125	      rootElement = findDisplayCandidate(definitions);
15126
15127	      if (!rootElement) {
15128	        throw new Error(translate('no process or collaboration to display'));
15129	      } else {
15130
15131	        logError(
15132	          translate('correcting missing bpmnElement on {plane} to {rootElement}', {
15133	            plane: elementToString(plane),
15134	            rootElement: elementToString(rootElement)
15135	          })
15136	        );
15137
15138	        // correct DI on the fly
15139	        plane.bpmnElement = rootElement;
15140	        registerDi(plane);
15141	      }
15142	    }
15143
15144
15145	    var ctx = visitRoot(rootElement, plane);
15146
15147	    if (is$2(rootElement, 'bpmn:Process')) {
15148	      handleProcess(rootElement, ctx);
15149	    } else if (is$2(rootElement, 'bpmn:Collaboration')) {
15150	      handleCollaboration(rootElement);
15151
15152	      // force drawing of everything not yet drawn that is part of the target DI
15153	      handleUnhandledProcesses(definitions.rootElements, ctx);
15154	    } else {
15155	      throw new Error(
15156	        translate('unsupported bpmnElement for {plane}: {rootElement}', {
15157	          plane: elementToString(plane),
15158	          rootElement: elementToString(rootElement)
15159	        })
15160	      );
15161	    }
15162
15163	    // handle all deferred elements
15164	    handleDeferred();
15165	  }
15166
15167	  function handleDeferred() {
15168
15169	    var fn;
15170
15171	    // drain deferred until empty
15172	    while (deferred.length) {
15173	      fn = deferred.shift();
15174
15175	      fn();
15176	    }
15177	  }
15178
15179	  function handleProcess(process, context) {
15180	    handleFlowElementsContainer(process, context);
15181	    handleIoSpecification(process.ioSpecification, context);
15182
15183	    handleArtifacts(process.artifacts, context);
15184
15185	    // log process handled
15186	    handled(process);
15187	  }
15188
15189	  function handleUnhandledProcesses(rootElements, ctx) {
15190
15191	    // walk through all processes that have not yet been drawn and draw them
15192	    // if they contain lanes with DI information.
15193	    // we do this to pass the free-floating lane test cases in the MIWG test suite
15194	    var processes = filter(rootElements, function(e) {
15195	      return !isHandled(e) && is$2(e, 'bpmn:Process') && e.laneSets;
15196	    });
15197
15198	    processes.forEach(contextual(handleProcess, ctx));
15199	  }
15200
15201	  function handleMessageFlow(messageFlow, context) {
15202	    visitIfDi(messageFlow, context);
15203	  }
15204
15205	  function handleMessageFlows(messageFlows, context) {
15206	    forEach(messageFlows, contextual(handleMessageFlow, context));
15207	  }
15208
15209	  function handleDataAssociation(association, context) {
15210	    visitIfDi(association, context);
15211	  }
15212
15213	  function handleDataInput(dataInput, context) {
15214	    visitIfDi(dataInput, context);
15215	  }
15216
15217	  function handleDataOutput(dataOutput, context) {
15218	    visitIfDi(dataOutput, context);
15219	  }
15220
15221	  function handleArtifact(artifact, context) {
15222
15223	    // bpmn:TextAnnotation
15224	    // bpmn:Group
15225	    // bpmn:Association
15226
15227	    visitIfDi(artifact, context);
15228	  }
15229
15230	  function handleArtifacts(artifacts, context) {
15231
15232	    forEach(artifacts, function(e) {
15233	      if (is$2(e, 'bpmn:Association')) {
15234	        deferred.push(function() {
15235	          handleArtifact(e, context);
15236	        });
15237	      } else {
15238	        handleArtifact(e, context);
15239	      }
15240	    });
15241	  }
15242
15243	  function handleIoSpecification(ioSpecification, context) {
15244
15245	    if (!ioSpecification) {
15246	      return;
15247	    }
15248
15249	    forEach(ioSpecification.dataInputs, contextual(handleDataInput, context));
15250	    forEach(ioSpecification.dataOutputs, contextual(handleDataOutput, context));
15251	  }
15252
15253	  function handleSubProcess(subProcess, context) {
15254	    handleFlowElementsContainer(subProcess, context);
15255	    handleArtifacts(subProcess.artifacts, context);
15256	  }
15257
15258	  function handleFlowNode(flowNode, context) {
15259	    var childCtx = visitIfDi(flowNode, context);
15260
15261	    if (is$2(flowNode, 'bpmn:SubProcess')) {
15262	      handleSubProcess(flowNode, childCtx || context);
15263	    }
15264
15265	    if (is$2(flowNode, 'bpmn:Activity')) {
15266	      handleIoSpecification(flowNode.ioSpecification, context);
15267	    }
15268
15269	    // defer handling of associations
15270	    // affected types:
15271	    //
15272	    //   * bpmn:Activity
15273	    //   * bpmn:ThrowEvent
15274	    //   * bpmn:CatchEvent
15275	    //
15276	    deferred.push(function() {
15277	      forEach(flowNode.dataInputAssociations, contextual(handleDataAssociation, context));
15278	      forEach(flowNode.dataOutputAssociations, contextual(handleDataAssociation, context));
15279	    });
15280	  }
15281
15282	  function handleSequenceFlow(sequenceFlow, context) {
15283	    visitIfDi(sequenceFlow, context);
15284	  }
15285
15286	  function handleDataElement(dataObject, context) {
15287	    visitIfDi(dataObject, context);
15288	  }
15289
15290	  function handleLane(lane, context) {
15291
15292	    deferred.push(function() {
15293
15294	      var newContext = visitIfDi(lane, context);
15295
15296	      if (lane.childLaneSet) {
15297	        handleLaneSet(lane.childLaneSet, newContext || context);
15298	      }
15299
15300	      wireFlowNodeRefs(lane);
15301	    });
15302	  }
15303
15304	  function handleLaneSet(laneSet, context) {
15305	    forEach(laneSet.lanes, contextual(handleLane, context));
15306	  }
15307
15308	  function handleLaneSets(laneSets, context) {
15309	    forEach(laneSets, contextual(handleLaneSet, context));
15310	  }
15311
15312	  function handleFlowElementsContainer(container, context) {
15313	    handleFlowElements(container.flowElements, context);
15314
15315	    if (container.laneSets) {
15316	      handleLaneSets(container.laneSets, context);
15317	    }
15318	  }
15319
15320	  function handleFlowElements(flowElements, context) {
15321	    forEach(flowElements, function(e) {
15322	      if (is$2(e, 'bpmn:SequenceFlow')) {
15323	        deferred.push(function() {
15324	          handleSequenceFlow(e, context);
15325	        });
15326	      } else if (is$2(e, 'bpmn:BoundaryEvent')) {
15327	        deferred.unshift(function() {
15328	          handleFlowNode(e, context);
15329	        });
15330	      } else if (is$2(e, 'bpmn:FlowNode')) {
15331	        handleFlowNode(e, context);
15332	      } else if (is$2(e, 'bpmn:DataObject')) ; else if (is$2(e, 'bpmn:DataStoreReference')) {
15333	        handleDataElement(e, context);
15334	      } else if (is$2(e, 'bpmn:DataObjectReference')) {
15335	        handleDataElement(e, context);
15336	      } else {
15337	        logError(
15338	          translate('unrecognized flowElement {element} in context {context}', {
15339	            element: elementToString(e),
15340	            context: (context ? elementToString(context.businessObject) : 'null')
15341	          }),
15342	          { element: e, context: context }
15343	        );
15344	      }
15345	    });
15346	  }
15347
15348	  function handleParticipant(participant, context) {
15349	    var newCtx = visitIfDi(participant, context);
15350
15351	    var process = participant.processRef;
15352	    if (process) {
15353	      handleProcess(process, newCtx || context);
15354	    }
15355	  }
15356
15357	  function handleCollaboration(collaboration) {
15358
15359	    forEach(collaboration.participants, contextual(handleParticipant));
15360
15361	    handleArtifacts(collaboration.artifacts);
15362
15363	    // handle message flows latest in the process
15364	    deferred.push(function() {
15365	      handleMessageFlows(collaboration.messageFlows);
15366	    });
15367	  }
15368
15369
15370	  function wireFlowNodeRefs(lane) {
15371
15372	    // wire the virtual flowNodeRefs <-> relationship
15373	    forEach(lane.flowNodeRef, function(flowNode) {
15374	      var lanes = flowNode.get('lanes');
15375
15376	      if (lanes) {
15377	        lanes.push(lane);
15378	      }
15379	    });
15380	  }
15381
15382	  // API //////////////////////
15383
15384	  return {
15385	    handleDeferred: handleDeferred,
15386	    handleDefinitions: handleDefinitions,
15387	    handleSubProcess: handleSubProcess,
15388	    registerDi: registerDi
15389	  };
15390	}
15391
15392	/**
15393	 * The importBpmnDiagram result.
15394	 *
15395	 * @typedef {Object} ImportBPMNDiagramResult
15396	 *
15397	 * @property {Array<string>} warnings
15398	 */
15399
15400	/**
15401	* The importBpmnDiagram error.
15402	*
15403	* @typedef {Error} ImportBPMNDiagramError
15404	*
15405	* @property {Array<string>} warnings
15406	*/
15407
15408	/**
15409	 * Import the definitions into a diagram.
15410	 *
15411	 * Errors and warnings are reported through the specified callback.
15412	 *
15413	 * @param  {djs.Diagram} diagram
15414	 * @param  {ModdleElement<Definitions>} definitions
15415	 * @param  {ModdleElement<BPMNDiagram>} [bpmnDiagram] the diagram to be rendered
15416	 * (if not provided, the first one will be rendered)
15417	 *
15418	 * Returns {Promise<ImportBPMNDiagramResult, ImportBPMNDiagramError>}
15419	 */
15420	function importBpmnDiagram(diagram, definitions, bpmnDiagram) {
15421
15422	  var importer,
15423	      eventBus,
15424	      translate;
15425
15426	  var error,
15427	      warnings = [];
15428
15429	  /**
15430	   * Walk the diagram semantically, importing (=drawing)
15431	   * all elements you encounter.
15432	   *
15433	   * @param {ModdleElement<Definitions>} definitions
15434	   * @param {ModdleElement<BPMNDiagram>} bpmnDiagram
15435	   */
15436	  function render(definitions, bpmnDiagram) {
15437
15438	    var visitor = {
15439
15440	      root: function(element) {
15441	        return importer.add(element);
15442	      },
15443
15444	      element: function(element, parentShape) {
15445	        return importer.add(element, parentShape);
15446	      },
15447
15448	      error: function(message, context) {
15449	        warnings.push({ message: message, context: context });
15450	      }
15451	    };
15452
15453	    var walker = new BpmnTreeWalker(visitor, translate);
15454
15455	    // traverse BPMN 2.0 document model,
15456	    // starting at definitions
15457	    walker.handleDefinitions(definitions, bpmnDiagram);
15458	  }
15459
15460	  return new Promise(function(resolve, reject) {
15461	    try {
15462	      importer = diagram.get('bpmnImporter');
15463	      eventBus = diagram.get('eventBus');
15464	      translate = diagram.get('translate');
15465
15466	      eventBus.fire('import.render.start', { definitions: definitions });
15467
15468	      render(definitions, bpmnDiagram);
15469
15470	      eventBus.fire('import.render.complete', {
15471	        error: error,
15472	        warnings: warnings
15473	      });
15474
15475	      return resolve({ warnings: warnings });
15476	    } catch (e) {
15477
15478	      e.warnings = warnings;
15479	      return reject(e);
15480	    }
15481	  });
15482	}
15483
15484	// TODO(nikku): remove with future bpmn-js version
15485
15486	/**
15487	 * Wraps APIs to check:
15488	 *
15489	 * 1) If a callback is passed -> Warn users about callback deprecation.
15490	 * 2) If Promise class is implemented in current environment.
15491	 *
15492	 * @private
15493	 */
15494	function wrapForCompatibility(api) {
15495
15496	  return function() {
15497
15498	    if (!window.Promise) {
15499	      throw new Error('Promises is not supported in this environment. Please polyfill Promise.');
15500	    }
15501
15502	    var argLen = arguments.length;
15503	    if (argLen >= 1 && isFunction(arguments[argLen - 1])) {
15504
15505	      var callback = arguments[argLen - 1];
15506
15507	      console.warn(new Error(
15508	        'Passing callbacks to ' + api.name + ' is deprecated and will be removed in a future major release. ' +
15509	        'Please switch to promises: https://bpmn.io/l/moving-to-promises.html'
15510	      ));
15511
15512	      var argsWithoutCallback = Array.prototype.slice.call(arguments, 0, -1);
15513
15514	      api.apply(this, argsWithoutCallback).then(function(result) {
15515
15516	        var firstKey = Object.keys(result)[0];
15517
15518	        // The APIs we are wrapping all resolve a single item depending on the API.
15519	        // For instance, importXML resolves { warnings } and saveXML returns { xml }.
15520	        // That's why we can call the callback with the first item of result.
15521	        return callback(null, result[firstKey]);
15522
15523	        // Passing a second paramter instead of catch because we don't want to
15524	        // catch errors thrown by callback().
15525	      }, function(err) {
15526
15527	        return callback(err, err.warnings);
15528	      });
15529	    } else {
15530
15531	      return api.apply(this, arguments);
15532	    }
15533	  };
15534	}
15535
15536	/**
15537	 * This file must not be changed or exchanged.
15538	 *
15539	 * @see http://bpmn.io/license for more information.
15540	 */
15541
15542
15543	// inlined ../../resources/logo.svg
15544	var BPMNIO_LOGO_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.02 5.57" width="53" height="21" style="vertical-align:middle"><path fill="currentColor" d="M1.88.92v.14c0 .41-.13.68-.4.8.33.14.46.44.46.86v.33c0 .61-.33.95-.95.95H0V0h.95c.65 0 .93.3.93.92zM.63.57v1.06h.24c.24 0 .38-.1.38-.43V.98c0-.28-.1-.4-.32-.4zm0 1.63v1.22h.36c.2 0 .32-.1.32-.39v-.35c0-.37-.12-.48-.4-.48H.63zM4.18.99v.52c0 .64-.31.98-.94.98h-.3V4h-.62V0h.92c.63 0 .94.35.94.99zM2.94.57v1.35h.3c.2 0 .3-.09.3-.37v-.6c0-.29-.1-.38-.3-.38h-.3zm2.89 2.27L6.25 0h.88v4h-.6V1.12L6.1 3.99h-.6l-.46-2.82v2.82h-.55V0h.87zM8.14 1.1V4h-.56V0h.79L9 2.4V0h.56v4h-.64zm2.49 2.29v.6h-.6v-.6zM12.12 1c0-.63.33-1 .95-1 .61 0 .95.37.95 1v2.04c0 .64-.34 1-.95 1-.62 0-.95-.37-.95-1zm.62 2.08c0 .28.13.39.33.39s.32-.1.32-.4V.98c0-.29-.12-.4-.32-.4s-.33.11-.33.4z"/><path fill="currentColor" d="M0 4.53h14.02v1.04H0zM11.08 0h.63v.62h-.63zm.63 4V1h-.63v2.98z"/></svg>';
15545
15546	var BPMNIO_IMG = BPMNIO_LOGO_SVG;
15547
15548	function css(attrs) {
15549	  return attrs.join(';');
15550	}
15551
15552	var LINK_STYLES = css([
15553	  'color: #404040'
15554	]);
15555
15556	var LIGHTBOX_STYLES = css([
15557	  'z-index: 1001',
15558	  'position: fixed',
15559	  'top: 0',
15560	  'left: 0',
15561	  'right: 0',
15562	  'bottom: 0'
15563	]);
15564
15565	var BACKDROP_STYLES = css([
15566	  'width: 100%',
15567	  'height: 100%',
15568	  'background: rgba(40,40,40,0.2)'
15569	]);
15570
15571	var NOTICE_STYLES = css([
15572	  'position: absolute',
15573	  'left: 50%',
15574	  'top: 40%',
15575	  'transform: translate(-50%)',
15576	  'width: 260px',
15577	  'padding: 10px',
15578	  'background: white',
15579	  'box-shadow: 0 1px 4px rgba(0,0,0,0.3)',
15580	  'font-family: Helvetica, Arial, sans-serif',
15581	  'font-size: 14px',
15582	  'display: flex',
15583	  'line-height: 1.3'
15584	]);
15585
15586	var LIGHTBOX_MARKUP =
15587	  '<div class="bjs-powered-by-lightbox" style="' + LIGHTBOX_STYLES + '">' +
15588	    '<div class="backdrop" style="' + BACKDROP_STYLES + '"></div>' +
15589	    '<div class="notice" style="' + NOTICE_STYLES + '">' +
15590	      '<a href="https://bpmn.io" target="_blank" rel="noopener" style="margin: 15px 20px 15px 10px; align-self: center;' + LINK_STYLES + '">' +
15591	        BPMNIO_IMG +
15592	      '</a>' +
15593	      '<span>' +
15594	        'Web-based tooling for BPMN, DMN and CMMN diagrams ' +
15595	        'powered by <a href="https://bpmn.io" target="_blank" rel="noopener">bpmn.io</a>.' +
15596	      '</span>' +
15597	    '</div>' +
15598	  '</div>';
15599
15600
15601	var lightbox;
15602
15603	function open() {
15604
15605	  if (!lightbox) {
15606	    lightbox = domify(LIGHTBOX_MARKUP);
15607
15608	    delegate.bind(lightbox, '.backdrop', 'click', function(event) {
15609	      document.body.removeChild(lightbox);
15610	    });
15611	  }
15612
15613	  document.body.appendChild(lightbox);
15614	}
15615
15616	/**
15617	 * The code in the <project-logo></project-logo> area
15618	 * must not be changed.
15619	 *
15620	 * @see http://bpmn.io/license for more information.
15621	 */
15622
15623	/**
15624	 * A base viewer for BPMN 2.0 diagrams.
15625	 *
15626	 * Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
15627	 * bundles that include actual features.
15628	 *
15629	 * @param {Object} [options] configuration options to pass to the viewer
15630	 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
15631	 * @param {string|number} [options.width] the width of the viewer
15632	 * @param {string|number} [options.height] the height of the viewer
15633	 * @param {Object} [options.moddleExtensions] extension packages to provide
15634	 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
15635	 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
15636	 */
15637	function BaseViewer(options) {
15638
15639	  options = assign({}, DEFAULT_OPTIONS, options);
15640
15641	  this._moddle = this._createModdle(options);
15642
15643	  this._container = this._createContainer(options);
15644
15645	  /* <project-logo> */
15646
15647	  addProjectLogo(this._container);
15648
15649	  /* </project-logo> */
15650
15651	  this._init(this._container, this._moddle, options);
15652	}
15653
15654	inherits$1(BaseViewer, Diagram);
15655
15656	/**
15657	* The importXML result.
15658	*
15659	* @typedef {Object} ImportXMLResult
15660	*
15661	* @property {Array<string>} warnings
15662	*/
15663
15664	/**
15665	* The importXML error.
15666	*
15667	* @typedef {Error} ImportXMLError
15668	*
15669	* @property {Array<string>} warnings
15670	*/
15671
15672	/**
15673	 * Parse and render a BPMN 2.0 diagram.
15674	 *
15675	 * Once finished the viewer reports back the result to the
15676	 * provided callback function with (err, warnings).
15677	 *
15678	 * ## Life-Cycle Events
15679	 *
15680	 * During import the viewer will fire life-cycle events:
15681	 *
15682	 *   * import.parse.start (about to read model from xml)
15683	 *   * import.parse.complete (model read; may have worked or not)
15684	 *   * import.render.start (graphical import start)
15685	 *   * import.render.complete (graphical import finished)
15686	 *   * import.done (everything done)
15687	 *
15688	 * You can use these events to hook into the life-cycle.
15689	 *
15690	 * @param {string} xml the BPMN 2.0 xml
15691	 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
15692	 *
15693	 * Returns {Promise<ImportXMLResult, ImportXMLError>}
15694	 */
15695	BaseViewer.prototype.importXML = wrapForCompatibility(function importXML(xml, bpmnDiagram) {
15696
15697	  var self = this;
15698
15699	  function ParseCompleteEvent(data) {
15700
15701	    var event = self.get('eventBus').createEvent(data);
15702
15703	    // TODO(nikku): remove with future bpmn-js version
15704	    Object.defineProperty(event, 'context', {
15705	      enumerable: true,
15706	      get: function() {
15707
15708	        console.warn(new Error(
15709	          'import.parse.complete <context> is deprecated ' +
15710	          'and will be removed in future library versions'
15711	        ));
15712
15713	        return {
15714	          warnings: data.warnings,
15715	          references: data.references,
15716	          elementsById: data.elementsById
15717	        };
15718	      }
15719	    });
15720
15721	    return event;
15722	  }
15723
15724	  return new Promise(function(resolve, reject) {
15725
15726	    // hook in pre-parse listeners +
15727	    // allow xml manipulation
15728	    xml = self._emit('import.parse.start', { xml: xml }) || xml;
15729
15730	    self._moddle.fromXML(xml, 'bpmn:Definitions').then(function(result) {
15731	      var definitions = result.rootElement;
15732	      var references = result.references;
15733	      var parseWarnings = result.warnings;
15734	      var elementsById = result.elementsById;
15735
15736	      // hook in post parse listeners +
15737	      // allow definitions manipulation
15738	      definitions = self._emit('import.parse.complete', ParseCompleteEvent({
15739	        error: null,
15740	        definitions: definitions,
15741	        elementsById: elementsById,
15742	        references: references,
15743	        warnings: parseWarnings
15744	      })) || definitions;
15745
15746	      self.importDefinitions(definitions, bpmnDiagram).then(function(result) {
15747	        var allWarnings = [].concat(parseWarnings, result.warnings || []);
15748
15749	        self._emit('import.done', { error: null, warnings: allWarnings });
15750
15751	        return resolve({ warnings: allWarnings });
15752	      }).catch(function(err) {
15753	        var allWarnings = [].concat(parseWarnings, err.warnings || []);
15754
15755	        self._emit('import.done', { error: err, warnings: allWarnings });
15756
15757	        return reject(addWarningsToError(err, allWarnings));
15758	      });
15759	    }).catch(function(err) {
15760
15761	      self._emit('import.parse.complete', {
15762	        error: err
15763	      });
15764
15765	      err = checkValidationError(err);
15766
15767	      self._emit('import.done', { error: err, warnings: err.warnings });
15768
15769	      return reject(err);
15770	    });
15771	  });
15772	});
15773
15774	/**
15775	* The importDefinitions result.
15776	*
15777	* @typedef {Object} ImportDefinitionsResult
15778	*
15779	* @property {Array<string>} warnings
15780	*/
15781
15782	/**
15783	* The importDefinitions error.
15784	*
15785	* @typedef {Error} ImportDefinitionsError
15786	*
15787	* @property {Array<string>} warnings
15788	*/
15789
15790	/**
15791	 * Import parsed definitions and render a BPMN 2.0 diagram.
15792	 *
15793	 * Once finished the viewer reports back the result to the
15794	 * provided callback function with (err, warnings).
15795	 *
15796	 * ## Life-Cycle Events
15797	 *
15798	 * During import the viewer will fire life-cycle events:
15799	 *
15800	 *   * import.render.start (graphical import start)
15801	 *   * import.render.complete (graphical import finished)
15802	 *
15803	 * You can use these events to hook into the life-cycle.
15804	 *
15805	 * @param {ModdleElement<Definitions>} definitions parsed BPMN 2.0 definitions
15806	 * @param {ModdleElement<BPMNDiagram>|string} [bpmnDiagram] BPMN diagram or id of diagram to render (if not provided, the first one will be rendered)
15807	 *
15808	 * Returns {Promise<ImportDefinitionsResult, ImportDefinitionsError>}
15809	 */
15810	BaseViewer.prototype.importDefinitions = wrapForCompatibility(function importDefinitions(definitions, bpmnDiagram) {
15811
15812	  var self = this;
15813
15814	  return new Promise(function(resolve, reject) {
15815
15816	    self._setDefinitions(definitions);
15817
15818	    self.open(bpmnDiagram).then(function(result) {
15819
15820	      var warnings = result.warnings;
15821
15822	      return resolve({ warnings: warnings });
15823	    }).catch(function(err) {
15824
15825	      return reject(err);
15826	    });
15827	  });
15828	});
15829
15830	/**
15831	 * The open result.
15832	 *
15833	 * @typedef {Object} OpenResult
15834	 *
15835	 * @property {Array<string>} warnings
15836	 */
15837
15838	/**
15839	* The open error.
15840	*
15841	* @typedef {Error} OpenError
15842	*
15843	* @property {Array<string>} warnings
15844	*/
15845
15846	/**
15847	 * Open diagram of previously imported XML.
15848	 *
15849	 * Once finished the viewer reports back the result to the
15850	 * provided callback function with (err, warnings).
15851	 *
15852	 * ## Life-Cycle Events
15853	 *
15854	 * During switch the viewer will fire life-cycle events:
15855	 *
15856	 *   * import.render.start (graphical import start)
15857	 *   * import.render.complete (graphical import finished)
15858	 *
15859	 * You can use these events to hook into the life-cycle.
15860	 *
15861	 * @param {string|ModdleElement<BPMNDiagram>} [bpmnDiagramOrId] id or the diagram to open
15862	 *
15863	 * Returns {Promise<OpenResult, OpenError>}
15864	 */
15865	BaseViewer.prototype.open = wrapForCompatibility(function open(bpmnDiagramOrId) {
15866
15867	  var definitions = this._definitions;
15868	  var bpmnDiagram = bpmnDiagramOrId;
15869
15870	  var self = this;
15871
15872	  return new Promise(function(resolve, reject) {
15873	    if (!definitions) {
15874	      var err1 = new Error('no XML imported');
15875
15876	      return reject(addWarningsToError(err1, []));
15877	    }
15878
15879	    if (typeof bpmnDiagramOrId === 'string') {
15880	      bpmnDiagram = findBPMNDiagram(definitions, bpmnDiagramOrId);
15881
15882	      if (!bpmnDiagram) {
15883	        var err2 = new Error('BPMNDiagram <' + bpmnDiagramOrId + '> not found');
15884
15885	        return reject(addWarningsToError(err2, []));
15886	      }
15887	    }
15888
15889	    // clear existing rendered diagram
15890	    // catch synchronous exceptions during #clear()
15891	    try {
15892	      self.clear();
15893	    } catch (error) {
15894
15895	      return reject(addWarningsToError(error, []));
15896	    }
15897
15898	    // perform graphical import
15899	    importBpmnDiagram(self, definitions, bpmnDiagram).then(function(result) {
15900
15901	      var warnings = result.warnings;
15902
15903	      return resolve({ warnings: warnings });
15904	    }).catch(function(err) {
15905
15906	      return reject(err);
15907	    });
15908	  });
15909	});
15910
15911	/**
15912	 * The saveXML result.
15913	 *
15914	 * @typedef {Object} SaveXMLResult
15915	 *
15916	 * @property {string} xml
15917	 */
15918
15919	/**
15920	 * Export the currently displayed BPMN 2.0 diagram as
15921	 * a BPMN 2.0 XML document.
15922	 *
15923	 * ## Life-Cycle Events
15924	 *
15925	 * During XML saving the viewer will fire life-cycle events:
15926	 *
15927	 *   * saveXML.start (before serialization)
15928	 *   * saveXML.serialized (after xml generation)
15929	 *   * saveXML.done (everything done)
15930	 *
15931	 * You can use these events to hook into the life-cycle.
15932	 *
15933	 * @param {Object} [options] export options
15934	 * @param {boolean} [options.format=false] output formatted XML
15935	 * @param {boolean} [options.preamble=true] output preamble
15936	 *
15937	 * Returns {Promise<SaveXMLResult, Error>}
15938	 */
15939	BaseViewer.prototype.saveXML = wrapForCompatibility(function saveXML(options) {
15940
15941	  options = options || {};
15942
15943	  var self = this;
15944
15945	  var definitions = this._definitions;
15946
15947	  return new Promise(function(resolve) {
15948
15949	    if (!definitions) {
15950	      return resolve({
15951	        error: new Error('no definitions loaded')
15952	      });
15953	    }
15954
15955	    // allow to fiddle around with definitions
15956	    definitions = self._emit('saveXML.start', {
15957	      definitions: definitions
15958	    }) || definitions;
15959
15960	    self._moddle.toXML(definitions, options).then(function(result) {
15961
15962	      var xml = result.xml;
15963
15964	      xml = self._emit('saveXML.serialized', {
15965	        xml: xml
15966	      }) || xml;
15967
15968	      return resolve({
15969	        xml: xml
15970	      });
15971	    });
15972	  }).catch(function(error) {
15973	    return { error: error };
15974	  }).then(function(result) {
15975
15976	    self._emit('saveXML.done', result);
15977
15978	    var error = result.error;
15979
15980	    if (error) {
15981	      return Promise.reject(error);
15982	    }
15983
15984	    return result;
15985	  });
15986	});
15987
15988	/**
15989	 * The saveSVG result.
15990	 *
15991	 * @typedef {Object} SaveSVGResult
15992	 *
15993	 * @property {string} svg
15994	 */
15995
15996	/**
15997	 * Export the currently displayed BPMN 2.0 diagram as
15998	 * an SVG image.
15999	 *
16000	 * ## Life-Cycle Events
16001	 *
16002	 * During SVG saving the viewer will fire life-cycle events:
16003	 *
16004	 *   * saveSVG.start (before serialization)
16005	 *   * saveSVG.done (everything done)
16006	 *
16007	 * You can use these events to hook into the life-cycle.
16008	 *
16009	 * @param {Object} [options]
16010	 *
16011	 * Returns {Promise<SaveSVGResult, Error>}
16012	 */
16013	BaseViewer.prototype.saveSVG = wrapForCompatibility(function saveSVG(options) {
16014
16015	  var self = this;
16016
16017	  return new Promise(function(resolve, reject) {
16018
16019	    self._emit('saveSVG.start');
16020
16021	    var svg, err;
16022
16023	    try {
16024	      var canvas = self.get('canvas');
16025
16026	      var contentNode = canvas.getDefaultLayer(),
16027	          defsNode = query('defs', canvas._svg);
16028
16029	      var contents = innerSVG(contentNode),
16030	          defs = defsNode ? '<defs>' + innerSVG(defsNode) + '</defs>' : '';
16031
16032	      var bbox = contentNode.getBBox();
16033
16034	      svg =
16035	        '<?xml version="1.0" encoding="utf-8"?>\n' +
16036	        '<!-- created with bpmn-js / http://bpmn.io -->\n' +
16037	        '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
16038	        '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
16039	             'width="' + bbox.width + '" height="' + bbox.height + '" ' +
16040	             'viewBox="' + bbox.x + ' ' + bbox.y + ' ' + bbox.width + ' ' + bbox.height + '" version="1.1">' +
16041	          defs + contents +
16042	        '</svg>';
16043	    } catch (e) {
16044	      err = e;
16045	    }
16046
16047	    self._emit('saveSVG.done', {
16048	      error: err,
16049	      svg: svg
16050	    });
16051
16052	    if (!err) {
16053	      return resolve({ svg: svg });
16054	    }
16055
16056	    return reject(err);
16057	  });
16058	});
16059
16060	/**
16061	 * Get a named diagram service.
16062	 *
16063	 * @example
16064	 *
16065	 * var elementRegistry = viewer.get('elementRegistry');
16066	 * var startEventShape = elementRegistry.get('StartEvent_1');
16067	 *
16068	 * @param {string} name
16069	 *
16070	 * @return {Object} diagram service instance
16071	 *
16072	 * @method BaseViewer#get
16073	 */
16074
16075	/**
16076	 * Invoke a function in the context of this viewer.
16077	 *
16078	 * @example
16079	 *
16080	 * viewer.invoke(function(elementRegistry) {
16081	 *   var startEventShape = elementRegistry.get('StartEvent_1');
16082	 * });
16083	 *
16084	 * @param {Function} fn to be invoked
16085	 *
16086	 * @return {Object} the functions return value
16087	 *
16088	 * @method BaseViewer#invoke
16089	 */
16090
16091
16092	BaseViewer.prototype._setDefinitions = function(definitions) {
16093	  this._definitions = definitions;
16094	};
16095
16096	BaseViewer.prototype.getModules = function() {
16097	  return this._modules;
16098	};
16099
16100	/**
16101	 * Remove all drawn elements from the viewer.
16102	 *
16103	 * After calling this method the viewer can still
16104	 * be reused for opening another diagram.
16105	 *
16106	 * @method BaseViewer#clear
16107	 */
16108	BaseViewer.prototype.clear = function() {
16109	  if (!this.getDefinitions()) {
16110
16111	    // no diagram to clear
16112	    return;
16113	  }
16114
16115	  // remove businessObject#di binding
16116	  //
16117	  // this is necessary, as we establish the bindings
16118	  // in the BpmnTreeWalker (and assume none are given
16119	  // on reimport)
16120	  this.get('elementRegistry').forEach(function(element) {
16121	    var bo = element.businessObject;
16122
16123	    if (bo && bo.di) {
16124	      delete bo.di;
16125	    }
16126	  });
16127
16128	  // remove drawn elements
16129	  Diagram.prototype.clear.call(this);
16130	};
16131
16132	/**
16133	 * Destroy the viewer instance and remove all its
16134	 * remainders from the document tree.
16135	 */
16136	BaseViewer.prototype.destroy = function() {
16137
16138	  // diagram destroy
16139	  Diagram.prototype.destroy.call(this);
16140
16141	  // dom detach
16142	  remove$2(this._container);
16143	};
16144
16145	/**
16146	 * Register an event listener
16147	 *
16148	 * Remove a previously added listener via {@link #off(event, callback)}.
16149	 *
16150	 * @param {string} event
16151	 * @param {number} [priority]
16152	 * @param {Function} callback
16153	 * @param {Object} [that]
16154	 */
16155	BaseViewer.prototype.on = function(event, priority, callback, target) {
16156	  return this.get('eventBus').on(event, priority, callback, target);
16157	};
16158
16159	/**
16160	 * De-register an event listener
16161	 *
16162	 * @param {string} event
16163	 * @param {Function} callback
16164	 */
16165	BaseViewer.prototype.off = function(event, callback) {
16166	  this.get('eventBus').off(event, callback);
16167	};
16168
16169	BaseViewer.prototype.attachTo = function(parentNode) {
16170
16171	  if (!parentNode) {
16172	    throw new Error('parentNode required');
16173	  }
16174
16175	  // ensure we detach from the
16176	  // previous, old parent
16177	  this.detach();
16178
16179	  // unwrap jQuery if provided
16180	  if (parentNode.get && parentNode.constructor.prototype.jquery) {
16181	    parentNode = parentNode.get(0);
16182	  }
16183
16184	  if (typeof parentNode === 'string') {
16185	    parentNode = query(parentNode);
16186	  }
16187
16188	  parentNode.appendChild(this._container);
16189
16190	  this._emit('attach', {});
16191
16192	  this.get('canvas').resized();
16193	};
16194
16195	BaseViewer.prototype.getDefinitions = function() {
16196	  return this._definitions;
16197	};
16198
16199	BaseViewer.prototype.detach = function() {
16200
16201	  var container = this._container,
16202	      parentNode = container.parentNode;
16203
16204	  if (!parentNode) {
16205	    return;
16206	  }
16207
16208	  this._emit('detach', {});
16209
16210	  parentNode.removeChild(container);
16211	};
16212
16213	BaseViewer.prototype._init = function(container, moddle, options) {
16214
16215	  var baseModules = options.modules || this.getModules(),
16216	      additionalModules = options.additionalModules || [],
16217	      staticModules = [
16218	        {
16219	          bpmnjs: [ 'value', this ],
16220	          moddle: [ 'value', moddle ]
16221	        }
16222	      ];
16223
16224	  var diagramModules = [].concat(staticModules, baseModules, additionalModules);
16225
16226	  var diagramOptions = assign(omit(options, [ 'additionalModules' ]), {
16227	    canvas: assign({}, options.canvas, { container: container }),
16228	    modules: diagramModules
16229	  });
16230
16231	  // invoke diagram constructor
16232	  Diagram.call(this, diagramOptions);
16233
16234	  if (options && options.container) {
16235	    this.attachTo(options.container);
16236	  }
16237	};
16238
16239	/**
16240	 * Emit an event on the underlying {@link EventBus}
16241	 *
16242	 * @param  {string} type
16243	 * @param  {Object} event
16244	 *
16245	 * @return {Object} event processing result (if any)
16246	 */
16247	BaseViewer.prototype._emit = function(type, event) {
16248	  return this.get('eventBus').fire(type, event);
16249	};
16250
16251	BaseViewer.prototype._createContainer = function(options) {
16252
16253	  var container = domify('<div class="bjs-container"></div>');
16254
16255	  assign(container.style, {
16256	    width: ensureUnit(options.width),
16257	    height: ensureUnit(options.height),
16258	    position: options.position
16259	  });
16260
16261	  return container;
16262	};
16263
16264	BaseViewer.prototype._createModdle = function(options) {
16265	  var moddleOptions = assign({}, this._moddleExtensions, options.moddleExtensions);
16266
16267	  return new simple(moddleOptions);
16268	};
16269
16270	BaseViewer.prototype._modules = [];
16271
16272	// helpers ///////////////
16273
16274	function addWarningsToError(err, warningsAry) {
16275	  err.warnings = warningsAry;
16276	  return err;
16277	}
16278
16279	function checkValidationError(err) {
16280
16281	  // check if we can help the user by indicating wrong BPMN 2.0 xml
16282	  // (in case he or the exporting tool did not get that right)
16283
16284	  var pattern = /unparsable content <([^>]+)> detected([\s\S]*)$/;
16285	  var match = pattern.exec(err.message);
16286
16287	  if (match) {
16288	    err.message =
16289	      'unparsable content <' + match[1] + '> detected; ' +
16290	      'this may indicate an invalid BPMN 2.0 diagram file' + match[2];
16291	  }
16292
16293	  return err;
16294	}
16295
16296	var DEFAULT_OPTIONS = {
16297	  width: '100%',
16298	  height: '100%',
16299	  position: 'relative'
16300	};
16301
16302
16303	/**
16304	 * Ensure the passed argument is a proper unit (defaulting to px)
16305	 */
16306	function ensureUnit(val) {
16307	  return val + (isNumber(val) ? 'px' : '');
16308	}
16309
16310
16311	/**
16312	 * Find BPMNDiagram in definitions by ID
16313	 *
16314	 * @param {ModdleElement<Definitions>} definitions
16315	 * @param {string} diagramId
16316	 *
16317	 * @return {ModdleElement<BPMNDiagram>|null}
16318	 */
16319	function findBPMNDiagram(definitions, diagramId) {
16320	  if (!diagramId) {
16321	    return null;
16322	  }
16323
16324	  return find(definitions.diagrams, function(element) {
16325	    return element.id === diagramId;
16326	  }) || null;
16327	}
16328
16329	/**
16330	 * Adds the project logo to the diagram container as
16331	 * required by the bpmn.io license.
16332	 *
16333	 * @see http://bpmn.io/license
16334	 *
16335	 * @param {Element} container
16336	 */
16337	function addProjectLogo(container) {
16338	  var img = BPMNIO_IMG;
16339
16340	  var linkMarkup =
16341	    '<a href="http://bpmn.io" ' +
16342	       'target="_blank" ' +
16343	       'class="bjs-powered-by" ' +
16344	       'title="Powered by bpmn.io" ' +
16345	       'style="position: absolute; bottom: 15px; right: 15px; z-index: 100; ' + LINK_STYLES + '">' +
16346	      img +
16347	    '</a>';
16348
16349	  var linkElement = domify(linkMarkup);
16350
16351	  container.appendChild(linkElement);
16352
16353	  componentEvent.bind(linkElement, 'click', function(event) {
16354	    open();
16355
16356	    event.preventDefault();
16357	  });
16358	}
16359
16360	/* </project-logo> */
16361
16362	/**
16363	 * A base modeler for BPMN 2.0 diagrams.
16364	 *
16365	 * Have a look at {@link Modeler} for a bundle that includes actual features.
16366	 *
16367	 * @param {Object} [options] configuration options to pass to the viewer
16368	 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
16369	 * @param {string|number} [options.width] the width of the viewer
16370	 * @param {string|number} [options.height] the height of the viewer
16371	 * @param {Object} [options.moddleExtensions] extension packages to provide
16372	 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
16373	 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
16374	 */
16375	function BaseModeler(options) {
16376	  BaseViewer.call(this, options);
16377
16378	  // hook ID collection into the modeler
16379	  this.on('import.parse.complete', function(event) {
16380	    if (!event.error) {
16381	      this._collectIds(event.definitions, event.elementsById);
16382	    }
16383	  }, this);
16384
16385	  this.on('diagram.destroy', function() {
16386	    this.get('moddle').ids.clear();
16387	  }, this);
16388	}
16389
16390	inherits$1(BaseModeler, BaseViewer);
16391
16392
16393	/**
16394	 * Create a moddle instance, attaching ids to it.
16395	 *
16396	 * @param {Object} options
16397	 */
16398	BaseModeler.prototype._createModdle = function(options) {
16399	  var moddle = BaseViewer.prototype._createModdle.call(this, options);
16400
16401	  // attach ids to moddle to be able to track
16402	  // and validated ids in the BPMN 2.0 XML document
16403	  // tree
16404	  moddle.ids = new Ids([ 32, 36, 1 ]);
16405
16406	  return moddle;
16407	};
16408
16409	/**
16410	 * Collect ids processed during parsing of the
16411	 * definitions object.
16412	 *
16413	 * @param {ModdleElement} definitions
16414	 * @param {Context} context
16415	 */
16416	BaseModeler.prototype._collectIds = function(definitions, elementsById) {
16417
16418	  var moddle = definitions.$model,
16419	      ids = moddle.ids,
16420	      id;
16421
16422	  // remove references from previous import
16423	  ids.clear();
16424
16425	  for (id in elementsById) {
16426	    ids.claim(id, elementsById[id]);
16427	  }
16428	};
16429
16430	/**
16431	 * Is an element of the given BPMN type?
16432	 *
16433	 * @param  {djs.model.Base|ModdleElement} element
16434	 * @param  {string} type
16435	 *
16436	 * @return {boolean}
16437	 */
16438	function is$1(element, type) {
16439	  var bo = getBusinessObject(element);
16440
16441	  return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
16442	}
16443
16444
16445	/**
16446	 * Return the business object for a given element.
16447	 *
16448	 * @param  {djs.model.Base|ModdleElement} element
16449	 *
16450	 * @return {ModdleElement}
16451	 */
16452	function getBusinessObject(element) {
16453	  return (element && element.businessObject) || element;
16454	}
16455
16456	function isExpanded(element) {
16457
16458	  if (is$1(element, 'bpmn:CallActivity')) {
16459	    return false;
16460	  }
16461
16462	  if (is$1(element, 'bpmn:SubProcess')) {
16463	    return getBusinessObject(element).di && !!getBusinessObject(element).di.isExpanded;
16464	  }
16465
16466	  if (is$1(element, 'bpmn:Participant')) {
16467	    return !!getBusinessObject(element).processRef;
16468	  }
16469
16470	  return true;
16471	}
16472
16473	function isInterrupting(element) {
16474	  return element && getBusinessObject(element).isInterrupting !== false;
16475	}
16476
16477	function isEventSubProcess(element) {
16478	  return element && !!getBusinessObject(element).triggeredByEvent;
16479	}
16480
16481	function hasEventDefinition$2(element, eventType) {
16482	  var bo = getBusinessObject(element),
16483	      hasEventDefinition = false;
16484
16485	  if (bo.eventDefinitions) {
16486	    forEach(bo.eventDefinitions, function(event) {
16487	      if (is$1(event, eventType)) {
16488	        hasEventDefinition = true;
16489	      }
16490	    });
16491	  }
16492
16493	  return hasEventDefinition;
16494	}
16495
16496	function hasErrorEventDefinition(element) {
16497	  return hasEventDefinition$2(element, 'bpmn:ErrorEventDefinition');
16498	}
16499
16500	function hasEscalationEventDefinition(element) {
16501	  return hasEventDefinition$2(element, 'bpmn:EscalationEventDefinition');
16502	}
16503
16504	function hasCompensateEventDefinition(element) {
16505	  return hasEventDefinition$2(element, 'bpmn:CompensateEventDefinition');
16506	}
16507
16508	function getLabelAttr(semantic) {
16509	  if (
16510	    is$1(semantic, 'bpmn:FlowElement') ||
16511	    is$1(semantic, 'bpmn:Participant') ||
16512	    is$1(semantic, 'bpmn:Lane') ||
16513	    is$1(semantic, 'bpmn:SequenceFlow') ||
16514	    is$1(semantic, 'bpmn:MessageFlow') ||
16515	    is$1(semantic, 'bpmn:DataInput') ||
16516	    is$1(semantic, 'bpmn:DataOutput')
16517	  ) {
16518	    return 'name';
16519	  }
16520
16521	  if (is$1(semantic, 'bpmn:TextAnnotation')) {
16522	    return 'text';
16523	  }
16524
16525	  if (is$1(semantic, 'bpmn:Group')) {
16526	    return 'categoryValueRef';
16527	  }
16528	}
16529
16530	function getCategoryValue(semantic) {
16531	  var categoryValueRef = semantic['categoryValueRef'];
16532
16533	  if (!categoryValueRef) {
16534	    return '';
16535	  }
16536
16537
16538	  return categoryValueRef.value || '';
16539	}
16540
16541	function getLabel(element) {
16542	  var semantic = element.businessObject,
16543	      attr = getLabelAttr(semantic);
16544
16545	  if (attr) {
16546
16547	    if (attr === 'categoryValueRef') {
16548
16549	      return getCategoryValue(semantic);
16550	    }
16551
16552	    return semantic[attr] || '';
16553	  }
16554	}
16555
16556
16557	function setLabel(element, text, isExternal) {
16558	  var semantic = element.businessObject,
16559	      attr = getLabelAttr(semantic);
16560
16561	  if (attr) {
16562
16563	    if (attr === 'categoryValueRef') {
16564	      semantic['categoryValueRef'].value = text;
16565	    } else {
16566	      semantic[attr] = text;
16567	    }
16568
16569	  }
16570
16571	  return element;
16572	}
16573
16574	// element utils //////////////////////
16575
16576	/**
16577	 * Checks if eventDefinition of the given element matches with semantic type.
16578	 *
16579	 * @return {boolean} true if element is of the given semantic type
16580	 */
16581	function isTypedEvent(event, eventDefinitionType, filter) {
16582
16583	  function matches(definition, filter) {
16584	    return every(filter, function(val, key) {
16585
16586	      // we want a == conversion here, to be able to catch
16587	      // undefined == false and friends
16588	      /* jshint -W116 */
16589	      return definition[key] == val;
16590	    });
16591	  }
16592
16593	  return some(event.eventDefinitions, function(definition) {
16594	    return definition.$type === eventDefinitionType && matches(event, filter);
16595	  });
16596	}
16597
16598	function isThrowEvent(event) {
16599	  return (event.$type === 'bpmn:IntermediateThrowEvent') || (event.$type === 'bpmn:EndEvent');
16600	}
16601
16602	function isCollection(element) {
16603	  var dataObject = element.dataObjectRef;
16604
16605	  return element.isCollection || (dataObject && dataObject.isCollection);
16606	}
16607
16608	function getDi(element) {
16609	  return element.businessObject.di;
16610	}
16611
16612	function getSemantic(element) {
16613	  return element.businessObject;
16614	}
16615
16616
16617	// color access //////////////////////
16618
16619	function getFillColor(element, defaultColor) {
16620	  var di = getDi(element);
16621
16622	  return di.get('color:background-color') || di.get('bioc:fill') || defaultColor || 'white';
16623	}
16624
16625	function getStrokeColor$1(element, defaultColor) {
16626	  var di = getDi(element);
16627
16628	  return di.get('color:border-color') || di.get('bioc:stroke') || defaultColor || 'black';
16629	}
16630
16631	function getLabelColor(element, defaultColor, defaultStrokeColor) {
16632	  var di = getDi(element),
16633	      label = di.get('label');
16634
16635	  return label && label.get('color:color') || defaultColor ||
16636	    getStrokeColor$1(element, defaultStrokeColor);
16637	}
16638
16639	// cropping path customizations //////////////////////
16640
16641	function getCirclePath(shape) {
16642
16643	  var cx = shape.x + shape.width / 2,
16644	      cy = shape.y + shape.height / 2,
16645	      radius = shape.width / 2;
16646
16647	  var circlePath = [
16648	    ['M', cx, cy],
16649	    ['m', 0, -radius],
16650	    ['a', radius, radius, 0, 1, 1, 0, 2 * radius],
16651	    ['a', radius, radius, 0, 1, 1, 0, -2 * radius],
16652	    ['z']
16653	  ];
16654
16655	  return componentsToPath(circlePath);
16656	}
16657
16658	function getRoundRectPath(shape, borderRadius) {
16659
16660	  var x = shape.x,
16661	      y = shape.y,
16662	      width = shape.width,
16663	      height = shape.height;
16664
16665	  var roundRectPath = [
16666	    ['M', x + borderRadius, y],
16667	    ['l', width - borderRadius * 2, 0],
16668	    ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, borderRadius],
16669	    ['l', 0, height - borderRadius * 2],
16670	    ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, borderRadius],
16671	    ['l', borderRadius * 2 - width, 0],
16672	    ['a', borderRadius, borderRadius, 0, 0, 1, -borderRadius, -borderRadius],
16673	    ['l', 0, borderRadius * 2 - height],
16674	    ['a', borderRadius, borderRadius, 0, 0, 1, borderRadius, -borderRadius],
16675	    ['z']
16676	  ];
16677
16678	  return componentsToPath(roundRectPath);
16679	}
16680
16681	function getDiamondPath(shape) {
16682
16683	  var width = shape.width,
16684	      height = shape.height,
16685	      x = shape.x,
16686	      y = shape.y,
16687	      halfWidth = width / 2,
16688	      halfHeight = height / 2;
16689
16690	  var diamondPath = [
16691	    ['M', x + halfWidth, y],
16692	    ['l', halfWidth, halfHeight],
16693	    ['l', -halfWidth, halfHeight],
16694	    ['l', -halfWidth, -halfHeight],
16695	    ['z']
16696	  ];
16697
16698	  return componentsToPath(diamondPath);
16699	}
16700
16701	function getRectPath(shape) {
16702	  var x = shape.x,
16703	      y = shape.y,
16704	      width = shape.width,
16705	      height = shape.height;
16706
16707	  var rectPath = [
16708	    ['M', x, y],
16709	    ['l', width, 0],
16710	    ['l', 0, height],
16711	    ['l', -width, 0],
16712	    ['z']
16713	  ];
16714
16715	  return componentsToPath(rectPath);
16716	}
16717
16718	var RENDERER_IDS = new Ids();
16719
16720	var TASK_BORDER_RADIUS = 10;
16721	var INNER_OUTER_DIST = 3;
16722
16723	var DEFAULT_FILL_OPACITY = .95,
16724	    HIGH_FILL_OPACITY = .35;
16725
16726	var ELEMENT_LABEL_DISTANCE$1 = 10;
16727
16728	function BpmnRenderer(
16729	    config, eventBus, styles, pathMap,
16730	    canvas, textRenderer, priority) {
16731
16732	  BaseRenderer.call(this, eventBus, priority);
16733
16734	  var defaultFillColor = config && config.defaultFillColor,
16735	      defaultStrokeColor = config && config.defaultStrokeColor,
16736	      defaultLabelColor = config && config.defaultLabelColor;
16737
16738	  var rendererId = RENDERER_IDS.next();
16739
16740	  var markers = {};
16741
16742	  var computeStyle = styles.computeStyle;
16743
16744	  function addMarker(id, options) {
16745	    var attrs = assign({
16746	      fill: 'black',
16747	      strokeWidth: 1,
16748	      strokeLinecap: 'round',
16749	      strokeDasharray: 'none'
16750	    }, options.attrs);
16751
16752	    var ref = options.ref || { x: 0, y: 0 };
16753
16754	    var scale = options.scale || 1;
16755
16756	    // fix for safari / chrome / firefox bug not correctly
16757	    // resetting stroke dash array
16758	    if (attrs.strokeDasharray === 'none') {
16759	      attrs.strokeDasharray = [10000, 1];
16760	    }
16761
16762	    var marker = create$1('marker');
16763
16764	    attr(options.element, attrs);
16765
16766	    append(marker, options.element);
16767
16768	    attr(marker, {
16769	      id: id,
16770	      viewBox: '0 0 20 20',
16771	      refX: ref.x,
16772	      refY: ref.y,
16773	      markerWidth: 20 * scale,
16774	      markerHeight: 20 * scale,
16775	      orient: 'auto'
16776	    });
16777
16778	    var defs = query('defs', canvas._svg);
16779
16780	    if (!defs) {
16781	      defs = create$1('defs');
16782
16783	      append(canvas._svg, defs);
16784	    }
16785
16786	    append(defs, marker);
16787
16788	    markers[id] = marker;
16789	  }
16790
16791	  function colorEscape(str) {
16792
16793	    // only allow characters and numbers
16794	    return str.replace(/[^0-9a-zA-z]+/g, '_');
16795	  }
16796
16797	  function marker(type, fill, stroke) {
16798	    var id = type + '-' + colorEscape(fill) + '-' + colorEscape(stroke) + '-' + rendererId;
16799
16800	    if (!markers[id]) {
16801	      createMarker(id, type, fill, stroke);
16802	    }
16803
16804	    return 'url(#' + id + ')';
16805	  }
16806
16807	  function createMarker(id, type, fill, stroke) {
16808
16809	    if (type === 'sequenceflow-end') {
16810	      var sequenceflowEnd = create$1('path');
16811	      attr(sequenceflowEnd, { d: 'M 1 5 L 11 10 L 1 15 Z' });
16812
16813	      addMarker(id, {
16814	        element: sequenceflowEnd,
16815	        ref: { x: 11, y: 10 },
16816	        scale: 0.5,
16817	        attrs: {
16818	          fill: stroke,
16819	          stroke: stroke
16820	        }
16821	      });
16822	    }
16823
16824	    if (type === 'messageflow-start') {
16825	      var messageflowStart = create$1('circle');
16826	      attr(messageflowStart, { cx: 6, cy: 6, r: 3.5 });
16827
16828	      addMarker(id, {
16829	        element: messageflowStart,
16830	        attrs: {
16831	          fill: fill,
16832	          stroke: stroke
16833	        },
16834	        ref: { x: 6, y: 6 }
16835	      });
16836	    }
16837
16838	    if (type === 'messageflow-end') {
16839	      var messageflowEnd = create$1('path');
16840	      attr(messageflowEnd, { d: 'm 1 5 l 0 -3 l 7 3 l -7 3 z' });
16841
16842	      addMarker(id, {
16843	        element: messageflowEnd,
16844	        attrs: {
16845	          fill: fill,
16846	          stroke: stroke,
16847	          strokeLinecap: 'butt'
16848	        },
16849	        ref: { x: 8.5, y: 5 }
16850	      });
16851	    }
16852
16853	    if (type === 'association-start') {
16854	      var associationStart = create$1('path');
16855	      attr(associationStart, { d: 'M 11 5 L 1 10 L 11 15' });
16856
16857	      addMarker(id, {
16858	        element: associationStart,
16859	        attrs: {
16860	          fill: 'none',
16861	          stroke: stroke,
16862	          strokeWidth: 1.5
16863	        },
16864	        ref: { x: 1, y: 10 },
16865	        scale: 0.5
16866	      });
16867	    }
16868
16869	    if (type === 'association-end') {
16870	      var associationEnd = create$1('path');
16871	      attr(associationEnd, { d: 'M 1 5 L 11 10 L 1 15' });
16872
16873	      addMarker(id, {
16874	        element: associationEnd,
16875	        attrs: {
16876	          fill: 'none',
16877	          stroke: stroke,
16878	          strokeWidth: 1.5
16879	        },
16880	        ref: { x: 12, y: 10 },
16881	        scale: 0.5
16882	      });
16883	    }
16884
16885	    if (type === 'conditional-flow-marker') {
16886	      var conditionalflowMarker = create$1('path');
16887	      attr(conditionalflowMarker, { d: 'M 0 10 L 8 6 L 16 10 L 8 14 Z' });
16888
16889	      addMarker(id, {
16890	        element: conditionalflowMarker,
16891	        attrs: {
16892	          fill: fill,
16893	          stroke: stroke
16894	        },
16895	        ref: { x: -1, y: 10 },
16896	        scale: 0.5
16897	      });
16898	    }
16899
16900	    if (type === 'conditional-default-flow-marker') {
16901	      var conditionaldefaultflowMarker = create$1('path');
16902	      attr(conditionaldefaultflowMarker, { d: 'M 6 4 L 10 16' });
16903
16904	      addMarker(id, {
16905	        element: conditionaldefaultflowMarker,
16906	        attrs: {
16907	          stroke: stroke
16908	        },
16909	        ref: { x: 0, y: 10 },
16910	        scale: 0.5
16911	      });
16912	    }
16913	  }
16914
16915	  function drawCircle(parentGfx, width, height, offset, attrs) {
16916
16917	    if (isObject(offset)) {
16918	      attrs = offset;
16919	      offset = 0;
16920	    }
16921
16922	    offset = offset || 0;
16923
16924	    attrs = computeStyle(attrs, {
16925	      stroke: 'black',
16926	      strokeWidth: 2,
16927	      fill: 'white'
16928	    });
16929
16930	    if (attrs.fill === 'none') {
16931	      delete attrs.fillOpacity;
16932	    }
16933
16934	    var cx = width / 2,
16935	        cy = height / 2;
16936
16937	    var circle = create$1('circle');
16938	    attr(circle, {
16939	      cx: cx,
16940	      cy: cy,
16941	      r: Math.round((width + height) / 4 - offset)
16942	    });
16943	    attr(circle, attrs);
16944
16945	    append(parentGfx, circle);
16946
16947	    return circle;
16948	  }
16949
16950	  function drawRect(parentGfx, width, height, r, offset, attrs) {
16951
16952	    if (isObject(offset)) {
16953	      attrs = offset;
16954	      offset = 0;
16955	    }
16956
16957	    offset = offset || 0;
16958
16959	    attrs = computeStyle(attrs, {
16960	      stroke: 'black',
16961	      strokeWidth: 2,
16962	      fill: 'white'
16963	    });
16964
16965	    var rect = create$1('rect');
16966	    attr(rect, {
16967	      x: offset,
16968	      y: offset,
16969	      width: width - offset * 2,
16970	      height: height - offset * 2,
16971	      rx: r,
16972	      ry: r
16973	    });
16974	    attr(rect, attrs);
16975
16976	    append(parentGfx, rect);
16977
16978	    return rect;
16979	  }
16980
16981	  function drawDiamond(parentGfx, width, height, attrs) {
16982
16983	    var x_2 = width / 2;
16984	    var y_2 = height / 2;
16985
16986	    var points = [{ x: x_2, y: 0 }, { x: width, y: y_2 }, { x: x_2, y: height }, { x: 0, y: y_2 }];
16987
16988	    var pointsString = points.map(function(point) {
16989	      return point.x + ',' + point.y;
16990	    }).join(' ');
16991
16992	    attrs = computeStyle(attrs, {
16993	      stroke: 'black',
16994	      strokeWidth: 2,
16995	      fill: 'white'
16996	    });
16997
16998	    var polygon = create$1('polygon');
16999	    attr(polygon, {
17000	      points: pointsString
17001	    });
17002	    attr(polygon, attrs);
17003
17004	    append(parentGfx, polygon);
17005
17006	    return polygon;
17007	  }
17008
17009	  function drawLine(parentGfx, waypoints, attrs) {
17010	    attrs = computeStyle(attrs, [ 'no-fill' ], {
17011	      stroke: 'black',
17012	      strokeWidth: 2,
17013	      fill: 'none'
17014	    });
17015
17016	    var line = createLine(waypoints, attrs);
17017
17018	    append(parentGfx, line);
17019
17020	    return line;
17021	  }
17022
17023	  function drawPath(parentGfx, d, attrs) {
17024
17025	    attrs = computeStyle(attrs, [ 'no-fill' ], {
17026	      strokeWidth: 2,
17027	      stroke: 'black'
17028	    });
17029
17030	    var path = create$1('path');
17031	    attr(path, { d: d });
17032	    attr(path, attrs);
17033
17034	    append(parentGfx, path);
17035
17036	    return path;
17037	  }
17038
17039	  function drawMarker(type, parentGfx, path, attrs) {
17040	    return drawPath(parentGfx, path, assign({ 'data-marker': type }, attrs));
17041	  }
17042
17043	  function as(type) {
17044	    return function(parentGfx, element) {
17045	      return handlers[type](parentGfx, element);
17046	    };
17047	  }
17048
17049	  function renderer(type) {
17050	    return handlers[type];
17051	  }
17052
17053	  function renderEventContent(element, parentGfx) {
17054
17055	    var event = getSemantic(element);
17056	    var isThrowing = isThrowEvent(event);
17057
17058	    if (event.eventDefinitions && event.eventDefinitions.length>1) {
17059	      if (event.parallelMultiple) {
17060	        return renderer('bpmn:ParallelMultipleEventDefinition')(parentGfx, element, isThrowing);
17061	      }
17062	      else {
17063	        return renderer('bpmn:MultipleEventDefinition')(parentGfx, element, isThrowing);
17064	      }
17065	    }
17066
17067	    if (isTypedEvent(event, 'bpmn:MessageEventDefinition')) {
17068	      return renderer('bpmn:MessageEventDefinition')(parentGfx, element, isThrowing);
17069	    }
17070
17071	    if (isTypedEvent(event, 'bpmn:TimerEventDefinition')) {
17072	      return renderer('bpmn:TimerEventDefinition')(parentGfx, element, isThrowing);
17073	    }
17074
17075	    if (isTypedEvent(event, 'bpmn:ConditionalEventDefinition')) {
17076	      return renderer('bpmn:ConditionalEventDefinition')(parentGfx, element);
17077	    }
17078
17079	    if (isTypedEvent(event, 'bpmn:SignalEventDefinition')) {
17080	      return renderer('bpmn:SignalEventDefinition')(parentGfx, element, isThrowing);
17081	    }
17082
17083	    if (isTypedEvent(event, 'bpmn:EscalationEventDefinition')) {
17084	      return renderer('bpmn:EscalationEventDefinition')(parentGfx, element, isThrowing);
17085	    }
17086
17087	    if (isTypedEvent(event, 'bpmn:LinkEventDefinition')) {
17088	      return renderer('bpmn:LinkEventDefinition')(parentGfx, element, isThrowing);
17089	    }
17090
17091	    if (isTypedEvent(event, 'bpmn:ErrorEventDefinition')) {
17092	      return renderer('bpmn:ErrorEventDefinition')(parentGfx, element, isThrowing);
17093	    }
17094
17095	    if (isTypedEvent(event, 'bpmn:CancelEventDefinition')) {
17096	      return renderer('bpmn:CancelEventDefinition')(parentGfx, element, isThrowing);
17097	    }
17098
17099	    if (isTypedEvent(event, 'bpmn:CompensateEventDefinition')) {
17100	      return renderer('bpmn:CompensateEventDefinition')(parentGfx, element, isThrowing);
17101	    }
17102
17103	    if (isTypedEvent(event, 'bpmn:TerminateEventDefinition')) {
17104	      return renderer('bpmn:TerminateEventDefinition')(parentGfx, element, isThrowing);
17105	    }
17106
17107	    return null;
17108	  }
17109
17110	  function renderLabel(parentGfx, label, options) {
17111
17112	    options = assign({
17113	      size: {
17114	        width: 100
17115	      }
17116	    }, options);
17117
17118	    var text = textRenderer.createText(label || '', options);
17119
17120	    classes(text).add('djs-label');
17121
17122	    append(parentGfx, text);
17123
17124	    return text;
17125	  }
17126
17127	  function renderEmbeddedLabel(parentGfx, element, align) {
17128	    var semantic = getSemantic(element);
17129
17130	    return renderLabel(parentGfx, semantic.name, {
17131	      box: element,
17132	      align: align,
17133	      padding: 5,
17134	      style: {
17135	        fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
17136	      }
17137	    });
17138	  }
17139
17140	  function renderExternalLabel(parentGfx, element) {
17141
17142	    var box = {
17143	      width: 90,
17144	      height: 30,
17145	      x: element.width / 2 + element.x,
17146	      y: element.height / 2 + element.y
17147	    };
17148
17149	    return renderLabel(parentGfx, getLabel(element), {
17150	      box: box,
17151	      fitBox: true,
17152	      style: assign(
17153	        {},
17154	        textRenderer.getExternalStyle(),
17155	        {
17156	          fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
17157	        }
17158	      )
17159	    });
17160	  }
17161
17162	  function renderLaneLabel(parentGfx, text, element) {
17163	    var textBox = renderLabel(parentGfx, text, {
17164	      box: {
17165	        height: 30,
17166	        width: element.height
17167	      },
17168	      align: 'center-middle',
17169	      style: {
17170	        fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
17171	      }
17172	    });
17173
17174	    var top = -1 * element.height;
17175
17176	    transform(textBox, 0, -top, 270);
17177	  }
17178
17179	  function createPathFromConnection(connection) {
17180	    var waypoints = connection.waypoints;
17181
17182	    var pathData = 'm  ' + waypoints[0].x + ',' + waypoints[0].y;
17183	    for (var i = 1; i < waypoints.length; i++) {
17184	      pathData += 'L' + waypoints[i].x + ',' + waypoints[i].y + ' ';
17185	    }
17186	    return pathData;
17187	  }
17188
17189	  var handlers = this.handlers = {
17190	    'bpmn:Event': function(parentGfx, element, attrs) {
17191
17192	      if (!('fillOpacity' in attrs)) {
17193	        attrs.fillOpacity = DEFAULT_FILL_OPACITY;
17194	      }
17195
17196	      return drawCircle(parentGfx, element.width, element.height, attrs);
17197	    },
17198	    'bpmn:StartEvent': function(parentGfx, element) {
17199	      var attrs = {
17200	        fill: getFillColor(element, defaultFillColor),
17201	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17202	      };
17203
17204	      var semantic = getSemantic(element);
17205
17206	      if (!semantic.isInterrupting) {
17207	        attrs = {
17208	          strokeDasharray: '6',
17209	          strokeLinecap: 'round',
17210	          fill: getFillColor(element, defaultFillColor),
17211	          stroke: getStrokeColor$1(element, defaultStrokeColor)
17212	        };
17213	      }
17214
17215	      var circle = renderer('bpmn:Event')(parentGfx, element, attrs);
17216
17217	      renderEventContent(element, parentGfx);
17218
17219	      return circle;
17220	    },
17221	    'bpmn:MessageEventDefinition': function(parentGfx, element, isThrowing) {
17222	      var pathData = pathMap.getScaledPath('EVENT_MESSAGE', {
17223	        xScaleFactor: 0.9,
17224	        yScaleFactor: 0.9,
17225	        containerWidth: element.width,
17226	        containerHeight: element.height,
17227	        position: {
17228	          mx: 0.235,
17229	          my: 0.315
17230	        }
17231	      });
17232
17233	      var fill = isThrowing ? getStrokeColor$1(element, defaultStrokeColor) : getFillColor(element, defaultFillColor);
17234	      var stroke = isThrowing ? getFillColor(element, defaultFillColor) : getStrokeColor$1(element, defaultStrokeColor);
17235
17236	      var messagePath = drawPath(parentGfx, pathData, {
17237	        strokeWidth: 1,
17238	        fill: fill,
17239	        stroke: stroke
17240	      });
17241
17242	      return messagePath;
17243	    },
17244	    'bpmn:TimerEventDefinition': function(parentGfx, element) {
17245	      var circle = drawCircle(parentGfx, element.width, element.height, 0.2 * element.height, {
17246	        strokeWidth: 2,
17247	        fill: getFillColor(element, defaultFillColor),
17248	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17249	      });
17250
17251	      var pathData = pathMap.getScaledPath('EVENT_TIMER_WH', {
17252	        xScaleFactor: 0.75,
17253	        yScaleFactor: 0.75,
17254	        containerWidth: element.width,
17255	        containerHeight: element.height,
17256	        position: {
17257	          mx: 0.5,
17258	          my: 0.5
17259	        }
17260	      });
17261
17262	      drawPath(parentGfx, pathData, {
17263	        strokeWidth: 2,
17264	        strokeLinecap: 'square',
17265	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17266	      });
17267
17268	      for (var i = 0;i < 12; i++) {
17269
17270	        var linePathData = pathMap.getScaledPath('EVENT_TIMER_LINE', {
17271	          xScaleFactor: 0.75,
17272	          yScaleFactor: 0.75,
17273	          containerWidth: element.width,
17274	          containerHeight: element.height,
17275	          position: {
17276	            mx: 0.5,
17277	            my: 0.5
17278	          }
17279	        });
17280
17281	        var width = element.width / 2;
17282	        var height = element.height / 2;
17283
17284	        drawPath(parentGfx, linePathData, {
17285	          strokeWidth: 1,
17286	          strokeLinecap: 'square',
17287	          transform: 'rotate(' + (i * 30) + ',' + height + ',' + width + ')',
17288	          stroke: getStrokeColor$1(element, defaultStrokeColor)
17289	        });
17290	      }
17291
17292	      return circle;
17293	    },
17294	    'bpmn:EscalationEventDefinition': function(parentGfx, event, isThrowing) {
17295	      var pathData = pathMap.getScaledPath('EVENT_ESCALATION', {
17296	        xScaleFactor: 1,
17297	        yScaleFactor: 1,
17298	        containerWidth: event.width,
17299	        containerHeight: event.height,
17300	        position: {
17301	          mx: 0.5,
17302	          my: 0.2
17303	        }
17304	      });
17305
17306	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17307
17308	      return drawPath(parentGfx, pathData, {
17309	        strokeWidth: 1,
17310	        fill: fill,
17311	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17312	      });
17313	    },
17314	    'bpmn:ConditionalEventDefinition': function(parentGfx, event) {
17315	      var pathData = pathMap.getScaledPath('EVENT_CONDITIONAL', {
17316	        xScaleFactor: 1,
17317	        yScaleFactor: 1,
17318	        containerWidth: event.width,
17319	        containerHeight: event.height,
17320	        position: {
17321	          mx: 0.5,
17322	          my: 0.222
17323	        }
17324	      });
17325
17326	      return drawPath(parentGfx, pathData, {
17327	        strokeWidth: 1,
17328	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17329	      });
17330	    },
17331	    'bpmn:LinkEventDefinition': function(parentGfx, event, isThrowing) {
17332	      var pathData = pathMap.getScaledPath('EVENT_LINK', {
17333	        xScaleFactor: 1,
17334	        yScaleFactor: 1,
17335	        containerWidth: event.width,
17336	        containerHeight: event.height,
17337	        position: {
17338	          mx: 0.57,
17339	          my: 0.263
17340	        }
17341	      });
17342
17343	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17344
17345	      return drawPath(parentGfx, pathData, {
17346	        strokeWidth: 1,
17347	        fill: fill,
17348	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17349	      });
17350	    },
17351	    'bpmn:ErrorEventDefinition': function(parentGfx, event, isThrowing) {
17352	      var pathData = pathMap.getScaledPath('EVENT_ERROR', {
17353	        xScaleFactor: 1.1,
17354	        yScaleFactor: 1.1,
17355	        containerWidth: event.width,
17356	        containerHeight: event.height,
17357	        position: {
17358	          mx: 0.2,
17359	          my: 0.722
17360	        }
17361	      });
17362
17363	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17364
17365	      return drawPath(parentGfx, pathData, {
17366	        strokeWidth: 1,
17367	        fill: fill,
17368	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17369	      });
17370	    },
17371	    'bpmn:CancelEventDefinition': function(parentGfx, event, isThrowing) {
17372	      var pathData = pathMap.getScaledPath('EVENT_CANCEL_45', {
17373	        xScaleFactor: 1.0,
17374	        yScaleFactor: 1.0,
17375	        containerWidth: event.width,
17376	        containerHeight: event.height,
17377	        position: {
17378	          mx: 0.638,
17379	          my: -0.055
17380	        }
17381	      });
17382
17383	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17384
17385	      var path = drawPath(parentGfx, pathData, {
17386	        strokeWidth: 1,
17387	        fill: fill,
17388	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17389	      });
17390
17391	      rotate(path, 45);
17392
17393	      return path;
17394	    },
17395	    'bpmn:CompensateEventDefinition': function(parentGfx, event, isThrowing) {
17396	      var pathData = pathMap.getScaledPath('EVENT_COMPENSATION', {
17397	        xScaleFactor: 1,
17398	        yScaleFactor: 1,
17399	        containerWidth: event.width,
17400	        containerHeight: event.height,
17401	        position: {
17402	          mx: 0.22,
17403	          my: 0.5
17404	        }
17405	      });
17406
17407	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17408
17409	      return drawPath(parentGfx, pathData, {
17410	        strokeWidth: 1,
17411	        fill: fill,
17412	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17413	      });
17414	    },
17415	    'bpmn:SignalEventDefinition': function(parentGfx, event, isThrowing) {
17416	      var pathData = pathMap.getScaledPath('EVENT_SIGNAL', {
17417	        xScaleFactor: 0.9,
17418	        yScaleFactor: 0.9,
17419	        containerWidth: event.width,
17420	        containerHeight: event.height,
17421	        position: {
17422	          mx: 0.5,
17423	          my: 0.2
17424	        }
17425	      });
17426
17427	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17428
17429	      return drawPath(parentGfx, pathData, {
17430	        strokeWidth: 1,
17431	        fill: fill,
17432	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17433	      });
17434	    },
17435	    'bpmn:MultipleEventDefinition': function(parentGfx, event, isThrowing) {
17436	      var pathData = pathMap.getScaledPath('EVENT_MULTIPLE', {
17437	        xScaleFactor: 1.1,
17438	        yScaleFactor: 1.1,
17439	        containerWidth: event.width,
17440	        containerHeight: event.height,
17441	        position: {
17442	          mx: 0.222,
17443	          my: 0.36
17444	        }
17445	      });
17446
17447	      var fill = isThrowing ? getStrokeColor$1(event, defaultStrokeColor) : 'none';
17448
17449	      return drawPath(parentGfx, pathData, {
17450	        strokeWidth: 1,
17451	        fill: fill
17452	      });
17453	    },
17454	    'bpmn:ParallelMultipleEventDefinition': function(parentGfx, event) {
17455	      var pathData = pathMap.getScaledPath('EVENT_PARALLEL_MULTIPLE', {
17456	        xScaleFactor: 1.2,
17457	        yScaleFactor: 1.2,
17458	        containerWidth: event.width,
17459	        containerHeight: event.height,
17460	        position: {
17461	          mx: 0.458,
17462	          my: 0.194
17463	        }
17464	      });
17465
17466	      return drawPath(parentGfx, pathData, {
17467	        strokeWidth: 1,
17468	        fill: getStrokeColor$1(event, defaultStrokeColor),
17469	        stroke: getStrokeColor$1(event, defaultStrokeColor)
17470	      });
17471	    },
17472	    'bpmn:EndEvent': function(parentGfx, element) {
17473	      var circle = renderer('bpmn:Event')(parentGfx, element, {
17474	        strokeWidth: 4,
17475	        fill: getFillColor(element, defaultFillColor),
17476	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17477	      });
17478
17479	      renderEventContent(element, parentGfx);
17480
17481	      return circle;
17482	    },
17483	    'bpmn:TerminateEventDefinition': function(parentGfx, element) {
17484	      var circle = drawCircle(parentGfx, element.width, element.height, 8, {
17485	        strokeWidth: 4,
17486	        fill: getStrokeColor$1(element, defaultStrokeColor),
17487	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17488	      });
17489
17490	      return circle;
17491	    },
17492	    'bpmn:IntermediateEvent': function(parentGfx, element) {
17493	      var outer = renderer('bpmn:Event')(parentGfx, element, {
17494	        strokeWidth: 1,
17495	        fill: getFillColor(element, defaultFillColor),
17496	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17497	      });
17498
17499	      /* inner */
17500	      drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, {
17501	        strokeWidth: 1,
17502	        fill: getFillColor(element, 'none'),
17503	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17504	      });
17505
17506	      renderEventContent(element, parentGfx);
17507
17508	      return outer;
17509	    },
17510	    'bpmn:IntermediateCatchEvent': as('bpmn:IntermediateEvent'),
17511	    'bpmn:IntermediateThrowEvent': as('bpmn:IntermediateEvent'),
17512
17513	    'bpmn:Activity': function(parentGfx, element, attrs) {
17514
17515	      attrs = attrs || {};
17516
17517	      if (!('fillOpacity' in attrs)) {
17518	        attrs.fillOpacity = DEFAULT_FILL_OPACITY;
17519	      }
17520
17521	      return drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, attrs);
17522	    },
17523
17524	    'bpmn:Task': function(parentGfx, element) {
17525	      var attrs = {
17526	        fill: getFillColor(element, defaultFillColor),
17527	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17528	      };
17529
17530	      var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
17531
17532	      renderEmbeddedLabel(parentGfx, element, 'center-middle');
17533	      attachTaskMarkers(parentGfx, element);
17534
17535	      return rect;
17536	    },
17537	    'bpmn:ServiceTask': function(parentGfx, element) {
17538	      var task = renderer('bpmn:Task')(parentGfx, element);
17539
17540	      var pathDataBG = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
17541	        abspos: {
17542	          x: 12,
17543	          y: 18
17544	        }
17545	      });
17546
17547	      /* service bg */ drawPath(parentGfx, pathDataBG, {
17548	        strokeWidth: 1,
17549	        fill: getFillColor(element, defaultFillColor),
17550	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17551	      });
17552
17553	      var fillPathData = pathMap.getScaledPath('TASK_TYPE_SERVICE_FILL', {
17554	        abspos: {
17555	          x: 17.2,
17556	          y: 18
17557	        }
17558	      });
17559
17560	      /* service fill */ drawPath(parentGfx, fillPathData, {
17561	        strokeWidth: 0,
17562	        fill: getFillColor(element, defaultFillColor)
17563	      });
17564
17565	      var pathData = pathMap.getScaledPath('TASK_TYPE_SERVICE', {
17566	        abspos: {
17567	          x: 17,
17568	          y: 22
17569	        }
17570	      });
17571
17572	      /* service */ drawPath(parentGfx, pathData, {
17573	        strokeWidth: 1,
17574	        fill: getFillColor(element, defaultFillColor),
17575	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17576	      });
17577
17578	      return task;
17579	    },
17580	    'bpmn:UserTask': function(parentGfx, element) {
17581	      var task = renderer('bpmn:Task')(parentGfx, element);
17582
17583	      var x = 15;
17584	      var y = 12;
17585
17586	      var pathData = pathMap.getScaledPath('TASK_TYPE_USER_1', {
17587	        abspos: {
17588	          x: x,
17589	          y: y
17590	        }
17591	      });
17592
17593	      /* user path */ drawPath(parentGfx, pathData, {
17594	        strokeWidth: 0.5,
17595	        fill: getFillColor(element, defaultFillColor),
17596	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17597	      });
17598
17599	      var pathData2 = pathMap.getScaledPath('TASK_TYPE_USER_2', {
17600	        abspos: {
17601	          x: x,
17602	          y: y
17603	        }
17604	      });
17605
17606	      /* user2 path */ drawPath(parentGfx, pathData2, {
17607	        strokeWidth: 0.5,
17608	        fill: getFillColor(element, defaultFillColor),
17609	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17610	      });
17611
17612	      var pathData3 = pathMap.getScaledPath('TASK_TYPE_USER_3', {
17613	        abspos: {
17614	          x: x,
17615	          y: y
17616	        }
17617	      });
17618
17619	      /* user3 path */ drawPath(parentGfx, pathData3, {
17620	        strokeWidth: 0.5,
17621	        fill: getStrokeColor$1(element, defaultStrokeColor),
17622	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17623	      });
17624
17625	      return task;
17626	    },
17627	    'bpmn:ManualTask': function(parentGfx, element) {
17628	      var task = renderer('bpmn:Task')(parentGfx, element);
17629
17630	      var pathData = pathMap.getScaledPath('TASK_TYPE_MANUAL', {
17631	        abspos: {
17632	          x: 17,
17633	          y: 15
17634	        }
17635	      });
17636
17637	      /* manual path */ drawPath(parentGfx, pathData, {
17638	        strokeWidth: 0.5, // 0.25,
17639	        fill: getFillColor(element, defaultFillColor),
17640	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17641	      });
17642
17643	      return task;
17644	    },
17645	    'bpmn:SendTask': function(parentGfx, element) {
17646	      var task = renderer('bpmn:Task')(parentGfx, element);
17647
17648	      var pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
17649	        xScaleFactor: 1,
17650	        yScaleFactor: 1,
17651	        containerWidth: 21,
17652	        containerHeight: 14,
17653	        position: {
17654	          mx: 0.285,
17655	          my: 0.357
17656	        }
17657	      });
17658
17659	      /* send path */ drawPath(parentGfx, pathData, {
17660	        strokeWidth: 1,
17661	        fill: getStrokeColor$1(element, defaultStrokeColor),
17662	        stroke: getFillColor(element, defaultFillColor)
17663	      });
17664
17665	      return task;
17666	    },
17667	    'bpmn:ReceiveTask' : function(parentGfx, element) {
17668	      var semantic = getSemantic(element);
17669
17670	      var task = renderer('bpmn:Task')(parentGfx, element);
17671	      var pathData;
17672
17673	      if (semantic.instantiate) {
17674	        drawCircle(parentGfx, 28, 28, 20 * 0.22, { strokeWidth: 1 });
17675
17676	        pathData = pathMap.getScaledPath('TASK_TYPE_INSTANTIATING_SEND', {
17677	          abspos: {
17678	            x: 7.77,
17679	            y: 9.52
17680	          }
17681	        });
17682	      } else {
17683
17684	        pathData = pathMap.getScaledPath('TASK_TYPE_SEND', {
17685	          xScaleFactor: 0.9,
17686	          yScaleFactor: 0.9,
17687	          containerWidth: 21,
17688	          containerHeight: 14,
17689	          position: {
17690	            mx: 0.3,
17691	            my: 0.4
17692	          }
17693	        });
17694	      }
17695
17696	      /* receive path */ drawPath(parentGfx, pathData, {
17697	        strokeWidth: 1,
17698	        fill: getFillColor(element, defaultFillColor),
17699	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17700	      });
17701
17702	      return task;
17703	    },
17704	    'bpmn:ScriptTask': function(parentGfx, element) {
17705	      var task = renderer('bpmn:Task')(parentGfx, element);
17706
17707	      var pathData = pathMap.getScaledPath('TASK_TYPE_SCRIPT', {
17708	        abspos: {
17709	          x: 15,
17710	          y: 20
17711	        }
17712	      });
17713
17714	      /* script path */ drawPath(parentGfx, pathData, {
17715	        strokeWidth: 1,
17716	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17717	      });
17718
17719	      return task;
17720	    },
17721	    'bpmn:BusinessRuleTask': function(parentGfx, element) {
17722	      var task = renderer('bpmn:Task')(parentGfx, element);
17723
17724	      var headerPathData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_HEADER', {
17725	        abspos: {
17726	          x: 8,
17727	          y: 8
17728	        }
17729	      });
17730
17731	      var businessHeaderPath = drawPath(parentGfx, headerPathData);
17732	      attr(businessHeaderPath, {
17733	        strokeWidth: 1,
17734	        fill: getFillColor(element, '#aaaaaa'),
17735	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17736	      });
17737
17738	      var headerData = pathMap.getScaledPath('TASK_TYPE_BUSINESS_RULE_MAIN', {
17739	        abspos: {
17740	          x: 8,
17741	          y: 8
17742	        }
17743	      });
17744
17745	      var businessPath = drawPath(parentGfx, headerData);
17746	      attr(businessPath, {
17747	        strokeWidth: 1,
17748	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17749	      });
17750
17751	      return task;
17752	    },
17753	    'bpmn:SubProcess': function(parentGfx, element, attrs) {
17754	      attrs = assign({
17755	        fill: getFillColor(element, defaultFillColor),
17756	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17757	      }, attrs);
17758
17759	      var rect = renderer('bpmn:Activity')(parentGfx, element, attrs);
17760
17761	      var expanded = isExpanded(element);
17762
17763	      if (isEventSubProcess(element)) {
17764	        attr(rect, {
17765	          strokeDasharray: '1,2'
17766	        });
17767	      }
17768
17769	      renderEmbeddedLabel(parentGfx, element, expanded ? 'center-top' : 'center-middle');
17770
17771	      if (expanded) {
17772	        attachTaskMarkers(parentGfx, element);
17773	      } else {
17774	        attachTaskMarkers(parentGfx, element, ['SubProcessMarker']);
17775	      }
17776
17777	      return rect;
17778	    },
17779	    'bpmn:AdHocSubProcess': function(parentGfx, element) {
17780	      return renderer('bpmn:SubProcess')(parentGfx, element);
17781	    },
17782	    'bpmn:Transaction': function(parentGfx, element) {
17783	      var outer = renderer('bpmn:SubProcess')(parentGfx, element);
17784
17785	      var innerAttrs = styles.style([ 'no-fill', 'no-events' ], {
17786	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17787	      });
17788
17789	      /* inner path */ drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS - 2, INNER_OUTER_DIST, innerAttrs);
17790
17791	      return outer;
17792	    },
17793	    'bpmn:CallActivity': function(parentGfx, element) {
17794	      return renderer('bpmn:SubProcess')(parentGfx, element, {
17795	        strokeWidth: 5
17796	      });
17797	    },
17798	    'bpmn:Participant': function(parentGfx, element) {
17799
17800	      var attrs = {
17801	        fillOpacity: DEFAULT_FILL_OPACITY,
17802	        fill: getFillColor(element, defaultFillColor),
17803	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17804	      };
17805
17806	      var lane = renderer('bpmn:Lane')(parentGfx, element, attrs);
17807
17808	      var expandedPool = isExpanded(element);
17809
17810	      if (expandedPool) {
17811	        drawLine(parentGfx, [
17812	          { x: 30, y: 0 },
17813	          { x: 30, y: element.height }
17814	        ], {
17815	          stroke: getStrokeColor$1(element, defaultStrokeColor)
17816	        });
17817	        var text = getSemantic(element).name;
17818	        renderLaneLabel(parentGfx, text, element);
17819	      } else {
17820
17821	        // Collapsed pool draw text inline
17822	        var text2 = getSemantic(element).name;
17823	        renderLabel(parentGfx, text2, {
17824	          box: element, align: 'center-middle',
17825	          style: {
17826	            fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
17827	          }
17828	        });
17829	      }
17830
17831	      var participantMultiplicity = !!(getSemantic(element).participantMultiplicity);
17832
17833	      if (participantMultiplicity) {
17834	        renderer('ParticipantMultiplicityMarker')(parentGfx, element);
17835	      }
17836
17837	      return lane;
17838	    },
17839	    'bpmn:Lane': function(parentGfx, element, attrs) {
17840	      var rect = drawRect(parentGfx, element.width, element.height, 0, assign({
17841	        fill: getFillColor(element, defaultFillColor),
17842	        fillOpacity: HIGH_FILL_OPACITY,
17843	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17844	      }, attrs));
17845
17846	      var semantic = getSemantic(element);
17847
17848	      if (semantic.$type === 'bpmn:Lane') {
17849	        var text = semantic.name;
17850	        renderLaneLabel(parentGfx, text, element);
17851	      }
17852
17853	      return rect;
17854	    },
17855	    'bpmn:InclusiveGateway': function(parentGfx, element) {
17856	      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
17857
17858	      /* circle path */
17859	      drawCircle(parentGfx, element.width, element.height, element.height * 0.24, {
17860	        strokeWidth: 2.5,
17861	        fill: getFillColor(element, defaultFillColor),
17862	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17863	      });
17864
17865	      return diamond;
17866	    },
17867	    'bpmn:ExclusiveGateway': function(parentGfx, element) {
17868	      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
17869
17870	      var pathData = pathMap.getScaledPath('GATEWAY_EXCLUSIVE', {
17871	        xScaleFactor: 0.4,
17872	        yScaleFactor: 0.4,
17873	        containerWidth: element.width,
17874	        containerHeight: element.height,
17875	        position: {
17876	          mx: 0.32,
17877	          my: 0.3
17878	        }
17879	      });
17880
17881	      if ((getDi(element).isMarkerVisible)) {
17882	        drawPath(parentGfx, pathData, {
17883	          strokeWidth: 1,
17884	          fill: getStrokeColor$1(element, defaultStrokeColor),
17885	          stroke: getStrokeColor$1(element, defaultStrokeColor)
17886	        });
17887	      }
17888
17889	      return diamond;
17890	    },
17891	    'bpmn:ComplexGateway': function(parentGfx, element) {
17892	      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
17893
17894	      var pathData = pathMap.getScaledPath('GATEWAY_COMPLEX', {
17895	        xScaleFactor: 0.5,
17896	        yScaleFactor:0.5,
17897	        containerWidth: element.width,
17898	        containerHeight: element.height,
17899	        position: {
17900	          mx: 0.46,
17901	          my: 0.26
17902	        }
17903	      });
17904
17905	      /* complex path */ drawPath(parentGfx, pathData, {
17906	        strokeWidth: 1,
17907	        fill: getStrokeColor$1(element, defaultStrokeColor),
17908	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17909	      });
17910
17911	      return diamond;
17912	    },
17913	    'bpmn:ParallelGateway': function(parentGfx, element) {
17914	      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
17915
17916	      var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
17917	        xScaleFactor: 0.6,
17918	        yScaleFactor:0.6,
17919	        containerWidth: element.width,
17920	        containerHeight: element.height,
17921	        position: {
17922	          mx: 0.46,
17923	          my: 0.2
17924	        }
17925	      });
17926
17927	      /* parallel path */ drawPath(parentGfx, pathData, {
17928	        strokeWidth: 1,
17929	        fill: getStrokeColor$1(element, defaultStrokeColor),
17930	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17931	      });
17932
17933	      return diamond;
17934	    },
17935	    'bpmn:EventBasedGateway': function(parentGfx, element) {
17936
17937	      var semantic = getSemantic(element);
17938
17939	      var diamond = renderer('bpmn:Gateway')(parentGfx, element);
17940
17941	      /* outer circle path */ drawCircle(parentGfx, element.width, element.height, element.height * 0.20, {
17942	        strokeWidth: 1,
17943	        fill: 'none',
17944	        stroke: getStrokeColor$1(element, defaultStrokeColor)
17945	      });
17946
17947	      var type = semantic.eventGatewayType;
17948	      var instantiate = !!semantic.instantiate;
17949
17950	      function drawEvent() {
17951
17952	        var pathData = pathMap.getScaledPath('GATEWAY_EVENT_BASED', {
17953	          xScaleFactor: 0.18,
17954	          yScaleFactor: 0.18,
17955	          containerWidth: element.width,
17956	          containerHeight: element.height,
17957	          position: {
17958	            mx: 0.36,
17959	            my: 0.44
17960	          }
17961	        });
17962
17963	        var attrs = {
17964	          strokeWidth: 2,
17965	          fill: getFillColor(element, 'none'),
17966	          stroke: getStrokeColor$1(element, defaultStrokeColor)
17967	        };
17968
17969	        /* event path */ drawPath(parentGfx, pathData, attrs);
17970	      }
17971
17972	      if (type === 'Parallel') {
17973
17974	        var pathData = pathMap.getScaledPath('GATEWAY_PARALLEL', {
17975	          xScaleFactor: 0.4,
17976	          yScaleFactor:0.4,
17977	          containerWidth: element.width,
17978	          containerHeight: element.height,
17979	          position: {
17980	            mx: 0.474,
17981	            my: 0.296
17982	          }
17983	        });
17984
17985	        var parallelPath = drawPath(parentGfx, pathData);
17986	        attr(parallelPath, {
17987	          strokeWidth: 1,
17988	          fill: 'none'
17989	        });
17990	      } else if (type === 'Exclusive') {
17991
17992	        if (!instantiate) {
17993	          var innerCircle = drawCircle(parentGfx, element.width, element.height, element.height * 0.26);
17994	          attr(innerCircle, {
17995	            strokeWidth: 1,
17996	            fill: 'none',
17997	            stroke: getStrokeColor$1(element, defaultStrokeColor)
17998	          });
17999	        }
18000
18001	        drawEvent();
18002	      }
18003
18004
18005	      return diamond;
18006	    },
18007	    'bpmn:Gateway': function(parentGfx, element) {
18008	      var attrs = {
18009	        fill: getFillColor(element, defaultFillColor),
18010	        fillOpacity: DEFAULT_FILL_OPACITY,
18011	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18012	      };
18013
18014	      return drawDiamond(parentGfx, element.width, element.height, attrs);
18015	    },
18016	    'bpmn:SequenceFlow': function(parentGfx, element) {
18017	      var pathData = createPathFromConnection(element);
18018
18019	      var fill = getFillColor(element, defaultFillColor),
18020	          stroke = getStrokeColor$1(element, defaultStrokeColor);
18021
18022	      var attrs = {
18023	        strokeLinejoin: 'round',
18024	        markerEnd: marker('sequenceflow-end', fill, stroke),
18025	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18026	      };
18027
18028	      var path = drawPath(parentGfx, pathData, attrs);
18029
18030	      var sequenceFlow = getSemantic(element);
18031
18032	      var source;
18033
18034	      if (element.source) {
18035	        source = element.source.businessObject;
18036
18037	        // conditional flow marker
18038	        if (sequenceFlow.conditionExpression && source.$instanceOf('bpmn:Activity')) {
18039	          attr(path, {
18040	            markerStart: marker('conditional-flow-marker', fill, stroke)
18041	          });
18042	        }
18043
18044	        // default marker
18045	        if (source.default && (source.$instanceOf('bpmn:Gateway') || source.$instanceOf('bpmn:Activity')) &&
18046	            source.default === sequenceFlow) {
18047	          attr(path, {
18048	            markerStart: marker('conditional-default-flow-marker', fill, stroke)
18049	          });
18050	        }
18051	      }
18052
18053	      return path;
18054	    },
18055	    'bpmn:Association': function(parentGfx, element, attrs) {
18056
18057	      var semantic = getSemantic(element);
18058
18059	      var fill = getFillColor(element, defaultFillColor),
18060	          stroke = getStrokeColor$1(element, defaultStrokeColor);
18061
18062	      attrs = assign({
18063	        strokeDasharray: '0.5, 5',
18064	        strokeLinecap: 'round',
18065	        strokeLinejoin: 'round',
18066	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18067	      }, attrs || {});
18068
18069	      if (semantic.associationDirection === 'One' ||
18070	          semantic.associationDirection === 'Both') {
18071	        attrs.markerEnd = marker('association-end', fill, stroke);
18072	      }
18073
18074	      if (semantic.associationDirection === 'Both') {
18075	        attrs.markerStart = marker('association-start', fill, stroke);
18076	      }
18077
18078	      return drawLine(parentGfx, element.waypoints, attrs);
18079	    },
18080	    'bpmn:DataInputAssociation': function(parentGfx, element) {
18081	      var fill = getFillColor(element, defaultFillColor),
18082	          stroke = getStrokeColor$1(element, defaultStrokeColor);
18083
18084	      return renderer('bpmn:Association')(parentGfx, element, {
18085	        markerEnd: marker('association-end', fill, stroke)
18086	      });
18087	    },
18088	    'bpmn:DataOutputAssociation': function(parentGfx, element) {
18089	      var fill = getFillColor(element, defaultFillColor),
18090	          stroke = getStrokeColor$1(element, defaultStrokeColor);
18091
18092	      return renderer('bpmn:Association')(parentGfx, element, {
18093	        markerEnd: marker('association-end', fill, stroke)
18094	      });
18095	    },
18096	    'bpmn:MessageFlow': function(parentGfx, element) {
18097
18098	      var semantic = getSemantic(element),
18099	          di = getDi(element);
18100
18101	      var fill = getFillColor(element, defaultFillColor),
18102	          stroke = getStrokeColor$1(element, defaultStrokeColor);
18103
18104	      var pathData = createPathFromConnection(element);
18105
18106	      var attrs = {
18107	        markerEnd: marker('messageflow-end', fill, stroke),
18108	        markerStart: marker('messageflow-start', fill, stroke),
18109	        strokeDasharray: '10, 12',
18110	        strokeLinecap: 'round',
18111	        strokeLinejoin: 'round',
18112	        strokeWidth: '1.5px',
18113	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18114	      };
18115
18116	      var path = drawPath(parentGfx, pathData, attrs);
18117
18118	      if (semantic.messageRef) {
18119	        var midPoint = path.getPointAtLength(path.getTotalLength() / 2);
18120
18121	        var markerPathData = pathMap.getScaledPath('MESSAGE_FLOW_MARKER', {
18122	          abspos: {
18123	            x: midPoint.x,
18124	            y: midPoint.y
18125	          }
18126	        });
18127
18128	        var messageAttrs = { strokeWidth: 1 };
18129
18130	        if (di.messageVisibleKind === 'initiating') {
18131	          messageAttrs.fill = 'white';
18132	          messageAttrs.stroke = 'black';
18133	        } else {
18134	          messageAttrs.fill = '#888';
18135	          messageAttrs.stroke = 'white';
18136	        }
18137
18138	        var message = drawPath(parentGfx, markerPathData, messageAttrs);
18139
18140	        var labelText = semantic.messageRef.name;
18141	        var label = renderLabel(parentGfx, labelText, {
18142	          align: 'center-top',
18143	          fitBox: true,
18144	          style: {
18145	            fill: getStrokeColor$1(element, defaultLabelColor)
18146	          }
18147	        });
18148
18149	        var messageBounds = message.getBBox(),
18150	            labelBounds = label.getBBox();
18151
18152	        var translateX = midPoint.x - labelBounds.width / 2,
18153	            translateY = midPoint.y + messageBounds.height / 2 + ELEMENT_LABEL_DISTANCE$1;
18154
18155	        transform(label, translateX, translateY, 0);
18156
18157	      }
18158
18159	      return path;
18160	    },
18161	    'bpmn:DataObject': function(parentGfx, element) {
18162	      var pathData = pathMap.getScaledPath('DATA_OBJECT_PATH', {
18163	        xScaleFactor: 1,
18164	        yScaleFactor: 1,
18165	        containerWidth: element.width,
18166	        containerHeight: element.height,
18167	        position: {
18168	          mx: 0.474,
18169	          my: 0.296
18170	        }
18171	      });
18172
18173	      var elementObject = drawPath(parentGfx, pathData, {
18174	        fill: getFillColor(element, defaultFillColor),
18175	        fillOpacity: DEFAULT_FILL_OPACITY,
18176	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18177	      });
18178
18179	      var semantic = getSemantic(element);
18180
18181	      if (isCollection(semantic)) {
18182	        renderDataItemCollection(parentGfx, element);
18183	      }
18184
18185	      return elementObject;
18186	    },
18187	    'bpmn:DataObjectReference': as('bpmn:DataObject'),
18188	    'bpmn:DataInput': function(parentGfx, element) {
18189
18190	      var arrowPathData = pathMap.getRawPath('DATA_ARROW');
18191
18192	      // page
18193	      var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
18194
18195	      /* input arrow path */ drawPath(parentGfx, arrowPathData, { strokeWidth: 1 });
18196
18197	      return elementObject;
18198	    },
18199	    'bpmn:DataOutput': function(parentGfx, element) {
18200	      var arrowPathData = pathMap.getRawPath('DATA_ARROW');
18201
18202	      // page
18203	      var elementObject = renderer('bpmn:DataObject')(parentGfx, element);
18204
18205	      /* output arrow path */ drawPath(parentGfx, arrowPathData, {
18206	        strokeWidth: 1,
18207	        fill: 'black'
18208	      });
18209
18210	      return elementObject;
18211	    },
18212	    'bpmn:DataStoreReference': function(parentGfx, element) {
18213	      var DATA_STORE_PATH = pathMap.getScaledPath('DATA_STORE', {
18214	        xScaleFactor: 1,
18215	        yScaleFactor: 1,
18216	        containerWidth: element.width,
18217	        containerHeight: element.height,
18218	        position: {
18219	          mx: 0,
18220	          my: 0.133
18221	        }
18222	      });
18223
18224	      var elementStore = drawPath(parentGfx, DATA_STORE_PATH, {
18225	        strokeWidth: 2,
18226	        fill: getFillColor(element, defaultFillColor),
18227	        fillOpacity: DEFAULT_FILL_OPACITY,
18228	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18229	      });
18230
18231	      return elementStore;
18232	    },
18233	    'bpmn:BoundaryEvent': function(parentGfx, element) {
18234
18235	      var semantic = getSemantic(element),
18236	          cancel = semantic.cancelActivity;
18237
18238	      var attrs = {
18239	        strokeWidth: 1,
18240	        fill: getFillColor(element, defaultFillColor),
18241	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18242	      };
18243
18244	      if (!cancel) {
18245	        attrs.strokeDasharray = '6';
18246	        attrs.strokeLinecap = 'round';
18247	      }
18248
18249	      // apply fillOpacity
18250	      var outerAttrs = assign({}, attrs, {
18251	        fillOpacity: 1
18252	      });
18253
18254	      // apply no-fill
18255	      var innerAttrs = assign({}, attrs, {
18256	        fill: 'none'
18257	      });
18258
18259	      var outer = renderer('bpmn:Event')(parentGfx, element, outerAttrs);
18260
18261	      /* inner path */ drawCircle(parentGfx, element.width, element.height, INNER_OUTER_DIST, innerAttrs);
18262
18263	      renderEventContent(element, parentGfx);
18264
18265	      return outer;
18266	    },
18267	    'bpmn:Group': function(parentGfx, element) {
18268
18269	      var group = drawRect(parentGfx, element.width, element.height, TASK_BORDER_RADIUS, {
18270	        stroke: getStrokeColor$1(element, defaultStrokeColor),
18271	        strokeWidth: 1,
18272	        strokeDasharray: '8,3,1,3',
18273	        fill: 'none',
18274	        pointerEvents: 'none'
18275	      });
18276
18277	      return group;
18278	    },
18279	    'label': function(parentGfx, element) {
18280	      return renderExternalLabel(parentGfx, element);
18281	    },
18282	    'bpmn:TextAnnotation': function(parentGfx, element) {
18283	      var style = {
18284	        'fill': 'none',
18285	        'stroke': 'none'
18286	      };
18287
18288	      var textElement = drawRect(parentGfx, element.width, element.height, 0, 0, style);
18289
18290	      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
18291	        xScaleFactor: 1,
18292	        yScaleFactor: 1,
18293	        containerWidth: element.width,
18294	        containerHeight: element.height,
18295	        position: {
18296	          mx: 0.0,
18297	          my: 0.0
18298	        }
18299	      });
18300
18301	      drawPath(parentGfx, textPathData, {
18302	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18303	      });
18304
18305	      var text = getSemantic(element).text || '';
18306	      renderLabel(parentGfx, text, {
18307	        box: element,
18308	        align: 'left-top',
18309	        padding: 5,
18310	        style: {
18311	          fill: getLabelColor(element, defaultLabelColor, defaultStrokeColor)
18312	        }
18313	      });
18314
18315	      return textElement;
18316	    },
18317	    'ParticipantMultiplicityMarker': function(parentGfx, element) {
18318	      var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
18319	        xScaleFactor: 1,
18320	        yScaleFactor: 1,
18321	        containerWidth: element.width,
18322	        containerHeight: element.height,
18323	        position: {
18324	          mx: ((element.width / 2) / element.width),
18325	          my: (element.height - 15) / element.height
18326	        }
18327	      });
18328
18329	      drawMarker('participant-multiplicity', parentGfx, markerPath, {
18330	        strokeWidth: 2,
18331	        fill: getFillColor(element, defaultFillColor),
18332	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18333	      });
18334	    },
18335	    'SubProcessMarker': function(parentGfx, element) {
18336	      var markerRect = drawRect(parentGfx, 14, 14, 0, {
18337	        strokeWidth: 1,
18338	        fill: getFillColor(element, defaultFillColor),
18339	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18340	      });
18341
18342	      // Process marker is placed in the middle of the box
18343	      // therefore fixed values can be used here
18344	      translate$2(markerRect, element.width / 2 - 7.5, element.height - 20);
18345
18346	      var markerPath = pathMap.getScaledPath('MARKER_SUB_PROCESS', {
18347	        xScaleFactor: 1.5,
18348	        yScaleFactor: 1.5,
18349	        containerWidth: element.width,
18350	        containerHeight: element.height,
18351	        position: {
18352	          mx: (element.width / 2 - 7.5) / element.width,
18353	          my: (element.height - 20) / element.height
18354	        }
18355	      });
18356
18357	      drawMarker('sub-process', parentGfx, markerPath, {
18358	        fill: getFillColor(element, defaultFillColor),
18359	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18360	      });
18361	    },
18362	    'ParallelMarker': function(parentGfx, element, position) {
18363	      var markerPath = pathMap.getScaledPath('MARKER_PARALLEL', {
18364	        xScaleFactor: 1,
18365	        yScaleFactor: 1,
18366	        containerWidth: element.width,
18367	        containerHeight: element.height,
18368	        position: {
18369	          mx: ((element.width / 2 + position.parallel) / element.width),
18370	          my: (element.height - 20) / element.height
18371	        }
18372	      });
18373
18374	      drawMarker('parallel', parentGfx, markerPath, {
18375	        fill: getFillColor(element, defaultFillColor),
18376	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18377	      });
18378	    },
18379	    'SequentialMarker': function(parentGfx, element, position) {
18380	      var markerPath = pathMap.getScaledPath('MARKER_SEQUENTIAL', {
18381	        xScaleFactor: 1,
18382	        yScaleFactor: 1,
18383	        containerWidth: element.width,
18384	        containerHeight: element.height,
18385	        position: {
18386	          mx: ((element.width / 2 + position.seq) / element.width),
18387	          my: (element.height - 19) / element.height
18388	        }
18389	      });
18390
18391	      drawMarker('sequential', parentGfx, markerPath, {
18392	        fill: getFillColor(element, defaultFillColor),
18393	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18394	      });
18395	    },
18396	    'CompensationMarker': function(parentGfx, element, position) {
18397	      var markerMath = pathMap.getScaledPath('MARKER_COMPENSATION', {
18398	        xScaleFactor: 1,
18399	        yScaleFactor: 1,
18400	        containerWidth: element.width,
18401	        containerHeight: element.height,
18402	        position: {
18403	          mx: ((element.width / 2 + position.compensation) / element.width),
18404	          my: (element.height - 13) / element.height
18405	        }
18406	      });
18407
18408	      drawMarker('compensation', parentGfx, markerMath, {
18409	        strokeWidth: 1,
18410	        fill: getFillColor(element, defaultFillColor),
18411	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18412	      });
18413	    },
18414	    'LoopMarker': function(parentGfx, element, position) {
18415	      var markerPath = pathMap.getScaledPath('MARKER_LOOP', {
18416	        xScaleFactor: 1,
18417	        yScaleFactor: 1,
18418	        containerWidth: element.width,
18419	        containerHeight: element.height,
18420	        position: {
18421	          mx: ((element.width / 2 + position.loop) / element.width),
18422	          my: (element.height - 7) / element.height
18423	        }
18424	      });
18425
18426	      drawMarker('loop', parentGfx, markerPath, {
18427	        strokeWidth: 1,
18428	        fill: getFillColor(element, defaultFillColor),
18429	        stroke: getStrokeColor$1(element, defaultStrokeColor),
18430	        strokeLinecap: 'round',
18431	        strokeMiterlimit: 0.5
18432	      });
18433	    },
18434	    'AdhocMarker': function(parentGfx, element, position) {
18435	      var markerPath = pathMap.getScaledPath('MARKER_ADHOC', {
18436	        xScaleFactor: 1,
18437	        yScaleFactor: 1,
18438	        containerWidth: element.width,
18439	        containerHeight: element.height,
18440	        position: {
18441	          mx: ((element.width / 2 + position.adhoc) / element.width),
18442	          my: (element.height - 15) / element.height
18443	        }
18444	      });
18445
18446	      drawMarker('adhoc', parentGfx, markerPath, {
18447	        strokeWidth: 1,
18448	        fill: getStrokeColor$1(element, defaultStrokeColor),
18449	        stroke: getStrokeColor$1(element, defaultStrokeColor)
18450	      });
18451	    }
18452	  };
18453
18454	  function attachTaskMarkers(parentGfx, element, taskMarkers) {
18455	    var obj = getSemantic(element);
18456
18457	    var subprocess = taskMarkers && taskMarkers.indexOf('SubProcessMarker') !== -1;
18458	    var position;
18459
18460	    if (subprocess) {
18461	      position = {
18462	        seq: -21,
18463	        parallel: -22,
18464	        compensation: -42,
18465	        loop: -18,
18466	        adhoc: 10
18467	      };
18468	    } else {
18469	      position = {
18470	        seq: -3,
18471	        parallel: -6,
18472	        compensation: -27,
18473	        loop: 0,
18474	        adhoc: 10
18475	      };
18476	    }
18477
18478	    forEach(taskMarkers, function(marker) {
18479	      renderer(marker)(parentGfx, element, position);
18480	    });
18481
18482	    if (obj.isForCompensation) {
18483	      renderer('CompensationMarker')(parentGfx, element, position);
18484	    }
18485
18486	    if (obj.$type === 'bpmn:AdHocSubProcess') {
18487	      renderer('AdhocMarker')(parentGfx, element, position);
18488	    }
18489
18490	    var loopCharacteristics = obj.loopCharacteristics,
18491	        isSequential = loopCharacteristics && loopCharacteristics.isSequential;
18492
18493	    if (loopCharacteristics) {
18494
18495	      if (isSequential === undefined) {
18496	        renderer('LoopMarker')(parentGfx, element, position);
18497	      }
18498
18499	      if (isSequential === false) {
18500	        renderer('ParallelMarker')(parentGfx, element, position);
18501	      }
18502
18503	      if (isSequential === true) {
18504	        renderer('SequentialMarker')(parentGfx, element, position);
18505	      }
18506	    }
18507	  }
18508
18509	  function renderDataItemCollection(parentGfx, element) {
18510
18511	    var yPosition = (element.height - 18) / element.height;
18512
18513	    var pathData = pathMap.getScaledPath('DATA_OBJECT_COLLECTION_PATH', {
18514	      xScaleFactor: 1,
18515	      yScaleFactor: 1,
18516	      containerWidth: element.width,
18517	      containerHeight: element.height,
18518	      position: {
18519	        mx: 0.33,
18520	        my: yPosition
18521	      }
18522	    });
18523
18524	    /* collection path */ drawPath(parentGfx, pathData, {
18525	      strokeWidth: 2
18526	    });
18527	  }
18528
18529
18530	  // extension API, use at your own risk
18531	  this._drawPath = drawPath;
18532
18533	}
18534
18535
18536	inherits$1(BpmnRenderer, BaseRenderer);
18537
18538	BpmnRenderer.$inject = [
18539	  'config.bpmnRenderer',
18540	  'eventBus',
18541	  'styles',
18542	  'pathMap',
18543	  'canvas',
18544	  'textRenderer'
18545	];
18546
18547
18548	BpmnRenderer.prototype.canRender = function(element) {
18549	  return is$1(element, 'bpmn:BaseElement');
18550	};
18551
18552	BpmnRenderer.prototype.drawShape = function(parentGfx, element) {
18553	  var type = element.type;
18554	  var h = this.handlers[type];
18555
18556	  /* jshint -W040 */
18557	  return h(parentGfx, element);
18558	};
18559
18560	BpmnRenderer.prototype.drawConnection = function(parentGfx, element) {
18561	  var type = element.type;
18562	  var h = this.handlers[type];
18563
18564	  /* jshint -W040 */
18565	  return h(parentGfx, element);
18566	};
18567
18568	BpmnRenderer.prototype.getShapePath = function(element) {
18569
18570	  if (is$1(element, 'bpmn:Event')) {
18571	    return getCirclePath(element);
18572	  }
18573
18574	  if (is$1(element, 'bpmn:Activity')) {
18575	    return getRoundRectPath(element, TASK_BORDER_RADIUS);
18576	  }
18577
18578	  if (is$1(element, 'bpmn:Gateway')) {
18579	    return getDiamondPath(element);
18580	  }
18581
18582	  return getRectPath(element);
18583	};
18584
18585	var DEFAULT_BOX_PADDING = 0;
18586
18587	var DEFAULT_LABEL_SIZE$1 = {
18588	  width: 150,
18589	  height: 50
18590	};
18591
18592
18593	function parseAlign(align) {
18594
18595	  var parts = align.split('-');
18596
18597	  return {
18598	    horizontal: parts[0] || 'center',
18599	    vertical: parts[1] || 'top'
18600	  };
18601	}
18602
18603	function parsePadding(padding) {
18604
18605	  if (isObject(padding)) {
18606	    return assign({ top: 0, left: 0, right: 0, bottom: 0 }, padding);
18607	  } else {
18608	    return {
18609	      top: padding,
18610	      left: padding,
18611	      right: padding,
18612	      bottom: padding
18613	    };
18614	  }
18615	}
18616
18617	function getTextBBox(text, fakeText) {
18618
18619	  fakeText.textContent = text;
18620
18621	  var textBBox;
18622
18623	  try {
18624	    var bbox,
18625	        emptyLine = text === '';
18626
18627	    // add dummy text, when line is empty to
18628	    // determine correct height
18629	    fakeText.textContent = emptyLine ? 'dummy' : text;
18630
18631	    textBBox = fakeText.getBBox();
18632
18633	    // take text rendering related horizontal
18634	    // padding into account
18635	    bbox = {
18636	      width: textBBox.width + textBBox.x * 2,
18637	      height: textBBox.height
18638	    };
18639
18640	    if (emptyLine) {
18641
18642	      // correct width
18643	      bbox.width = 0;
18644	    }
18645
18646	    return bbox;
18647	  } catch (e) {
18648	    return { width: 0, height: 0 };
18649	  }
18650	}
18651
18652
18653	/**
18654	 * Layout the next line and return the layouted element.
18655	 *
18656	 * Alters the lines passed.
18657	 *
18658	 * @param  {Array<string>} lines
18659	 * @return {Object} the line descriptor, an object { width, height, text }
18660	 */
18661	function layoutNext(lines, maxWidth, fakeText) {
18662
18663	  var originalLine = lines.shift(),
18664	      fitLine = originalLine;
18665
18666	  var textBBox;
18667
18668	  for (;;) {
18669	    textBBox = getTextBBox(fitLine, fakeText);
18670
18671	    textBBox.width = fitLine ? textBBox.width : 0;
18672
18673	    // try to fit
18674	    if (fitLine === ' ' || fitLine === '' || textBBox.width < Math.round(maxWidth) || fitLine.length < 2) {
18675	      return fit(lines, fitLine, originalLine, textBBox);
18676	    }
18677
18678	    fitLine = shortenLine(fitLine, textBBox.width, maxWidth);
18679	  }
18680	}
18681
18682	function fit(lines, fitLine, originalLine, textBBox) {
18683	  if (fitLine.length < originalLine.length) {
18684	    var remainder = originalLine.slice(fitLine.length).trim();
18685
18686	    lines.unshift(remainder);
18687	  }
18688
18689	  return {
18690	    width: textBBox.width,
18691	    height: textBBox.height,
18692	    text: fitLine
18693	  };
18694	}
18695
18696	var SOFT_BREAK = '\u00AD';
18697
18698
18699	/**
18700	 * Shortens a line based on spacing and hyphens.
18701	 * Returns the shortened result on success.
18702	 *
18703	 * @param  {string} line
18704	 * @param  {number} maxLength the maximum characters of the string
18705	 * @return {string} the shortened string
18706	 */
18707	function semanticShorten(line, maxLength) {
18708
18709	  var parts = line.split(/(\s|-|\u00AD)/g),
18710	      part,
18711	      shortenedParts = [],
18712	      length = 0;
18713
18714	  // try to shorten via break chars
18715	  if (parts.length > 1) {
18716
18717	    while ((part = parts.shift())) {
18718	      if (part.length + length < maxLength) {
18719	        shortenedParts.push(part);
18720	        length += part.length;
18721	      } else {
18722
18723	        // remove previous part, too if hyphen does not fit anymore
18724	        if (part === '-' || part === SOFT_BREAK) {
18725	          shortenedParts.pop();
18726	        }
18727
18728	        break;
18729	      }
18730	    }
18731	  }
18732
18733	  var last = shortenedParts[shortenedParts.length - 1];
18734
18735	  // translate trailing soft break to actual hyphen
18736	  if (last && last === SOFT_BREAK) {
18737	    shortenedParts[shortenedParts.length - 1] = '-';
18738	  }
18739
18740	  return shortenedParts.join('');
18741	}
18742
18743
18744	function shortenLine(line, width, maxWidth) {
18745	  var length = Math.max(line.length * (maxWidth / width), 1);
18746
18747	  // try to shorten semantically (i.e. based on spaces and hyphens)
18748	  var shortenedLine = semanticShorten(line, length);
18749
18750	  if (!shortenedLine) {
18751
18752	    // force shorten by cutting the long word
18753	    shortenedLine = line.slice(0, Math.max(Math.round(length - 1), 1));
18754	  }
18755
18756	  return shortenedLine;
18757	}
18758
18759
18760	function getHelperSvg() {
18761	  var helperSvg = document.getElementById('helper-svg');
18762
18763	  if (!helperSvg) {
18764	    helperSvg = create$1('svg');
18765
18766	    attr(helperSvg, {
18767	      id: 'helper-svg',
18768	      width: 0,
18769	      height: 0,
18770	      style: 'visibility: hidden; position: fixed'
18771	    });
18772
18773	    document.body.appendChild(helperSvg);
18774	  }
18775
18776	  return helperSvg;
18777	}
18778
18779
18780	/**
18781	 * Creates a new label utility
18782	 *
18783	 * @param {Object} config
18784	 * @param {Dimensions} config.size
18785	 * @param {number} config.padding
18786	 * @param {Object} config.style
18787	 * @param {string} config.align
18788	 */
18789	function Text(config) {
18790
18791	  this._config = assign({}, {
18792	    size: DEFAULT_LABEL_SIZE$1,
18793	    padding: DEFAULT_BOX_PADDING,
18794	    style: {},
18795	    align: 'center-top'
18796	  }, config || {});
18797	}
18798
18799	/**
18800	 * Returns the layouted text as an SVG element.
18801	 *
18802	 * @param {string} text
18803	 * @param {Object} options
18804	 *
18805	 * @return {SVGElement}
18806	 */
18807	Text.prototype.createText = function(text, options) {
18808	  return this.layoutText(text, options).element;
18809	};
18810
18811	/**
18812	 * Returns a labels layouted dimensions.
18813	 *
18814	 * @param {string} text to layout
18815	 * @param {Object} options
18816	 *
18817	 * @return {Dimensions}
18818	 */
18819	Text.prototype.getDimensions = function(text, options) {
18820	  return this.layoutText(text, options).dimensions;
18821	};
18822
18823	/**
18824	 * Creates and returns a label and its bounding box.
18825	 *
18826	 * @method Text#createText
18827	 *
18828	 * @param {string} text the text to render on the label
18829	 * @param {Object} options
18830	 * @param {string} options.align how to align in the bounding box.
18831	 *                               Any of { 'center-middle', 'center-top' },
18832	 *                               defaults to 'center-top'.
18833	 * @param {string} options.style style to be applied to the text
18834	 * @param {boolean} options.fitBox indicates if box will be recalculated to
18835	 *                                 fit text
18836	 *
18837	 * @return {Object} { element, dimensions }
18838	 */
18839	Text.prototype.layoutText = function(text, options) {
18840	  var box = assign({}, this._config.size, options.box),
18841	      style = assign({}, this._config.style, options.style),
18842	      align = parseAlign(options.align || this._config.align),
18843	      padding = parsePadding(options.padding !== undefined ? options.padding : this._config.padding),
18844	      fitBox = options.fitBox || false;
18845
18846	  var lineHeight = getLineHeight(style);
18847
18848	  // we split text by lines and normalize
18849	  // {soft break} + {line break} => { line break }
18850	  var lines = text.split(/\u00AD?\r?\n/),
18851	      layouted = [];
18852
18853	  var maxWidth = box.width - padding.left - padding.right;
18854
18855	  // ensure correct rendering by attaching helper text node to invisible SVG
18856	  var helperText = create$1('text');
18857	  attr(helperText, { x: 0, y: 0 });
18858	  attr(helperText, style);
18859
18860	  var helperSvg = getHelperSvg();
18861
18862	  append(helperSvg, helperText);
18863
18864	  while (lines.length) {
18865	    layouted.push(layoutNext(lines, maxWidth, helperText));
18866	  }
18867
18868	  if (align.vertical === 'middle') {
18869	    padding.top = padding.bottom = 0;
18870	  }
18871
18872	  var totalHeight = reduce(layouted, function(sum, line, idx) {
18873	    return sum + (lineHeight || line.height);
18874	  }, 0) + padding.top + padding.bottom;
18875
18876	  var maxLineWidth = reduce(layouted, function(sum, line, idx) {
18877	    return line.width > sum ? line.width : sum;
18878	  }, 0);
18879
18880	  // the y position of the next line
18881	  var y = padding.top;
18882
18883	  if (align.vertical === 'middle') {
18884	    y += (box.height - totalHeight) / 2;
18885	  }
18886
18887	  // magic number initial offset
18888	  y -= (lineHeight || layouted[0].height) / 4;
18889
18890
18891	  var textElement = create$1('text');
18892
18893	  attr(textElement, style);
18894
18895	  // layout each line taking into account that parent
18896	  // shape might resize to fit text size
18897	  forEach(layouted, function(line) {
18898
18899	    var x;
18900
18901	    y += (lineHeight || line.height);
18902
18903	    switch (align.horizontal) {
18904	    case 'left':
18905	      x = padding.left;
18906	      break;
18907
18908	    case 'right':
18909	      x = ((fitBox ? maxLineWidth : maxWidth)
18910	        - padding.right - line.width);
18911	      break;
18912
18913	    default:
18914
18915	      // aka center
18916	      x = Math.max((((fitBox ? maxLineWidth : maxWidth)
18917	        - line.width) / 2 + padding.left), 0);
18918	    }
18919
18920	    var tspan = create$1('tspan');
18921	    attr(tspan, { x: x, y: y });
18922
18923	    tspan.textContent = line.text;
18924
18925	    append(textElement, tspan);
18926	  });
18927
18928	  remove$1(helperText);
18929
18930	  var dimensions = {
18931	    width: maxLineWidth,
18932	    height: totalHeight
18933	  };
18934
18935	  return {
18936	    dimensions: dimensions,
18937	    element: textElement
18938	  };
18939	};
18940
18941
18942	function getLineHeight(style) {
18943	  if ('fontSize' in style && 'lineHeight' in style) {
18944	    return style.lineHeight * parseInt(style.fontSize, 10);
18945	  }
18946	}
18947
18948	var DEFAULT_FONT_SIZE = 12;
18949	var LINE_HEIGHT_RATIO = 1.2;
18950
18951	var MIN_TEXT_ANNOTATION_HEIGHT = 30;
18952
18953
18954	function TextRenderer(config) {
18955
18956	  var defaultStyle = assign({
18957	    fontFamily: 'Arial, sans-serif',
18958	    fontSize: DEFAULT_FONT_SIZE,
18959	    fontWeight: 'normal',
18960	    lineHeight: LINE_HEIGHT_RATIO
18961	  }, config && config.defaultStyle || {});
18962
18963	  var fontSize = parseInt(defaultStyle.fontSize, 10) - 1;
18964
18965	  var externalStyle = assign({}, defaultStyle, {
18966	    fontSize: fontSize
18967	  }, config && config.externalStyle || {});
18968
18969	  var textUtil = new Text({
18970	    style: defaultStyle
18971	  });
18972
18973	  /**
18974	   * Get the new bounds of an externally rendered,
18975	   * layouted label.
18976	   *
18977	   * @param  {Bounds} bounds
18978	   * @param  {string} text
18979	   *
18980	   * @return {Bounds}
18981	   */
18982	  this.getExternalLabelBounds = function(bounds, text) {
18983
18984	    var layoutedDimensions = textUtil.getDimensions(text, {
18985	      box: {
18986	        width: 90,
18987	        height: 30,
18988	        x: bounds.width / 2 + bounds.x,
18989	        y: bounds.height / 2 + bounds.y
18990	      },
18991	      style: externalStyle
18992	    });
18993
18994	    // resize label shape to fit label text
18995	    return {
18996	      x: Math.round(bounds.x + bounds.width / 2 - layoutedDimensions.width / 2),
18997	      y: Math.round(bounds.y),
18998	      width: Math.ceil(layoutedDimensions.width),
18999	      height: Math.ceil(layoutedDimensions.height)
19000	    };
19001
19002	  };
19003
19004	  /**
19005	   * Get the new bounds of text annotation.
19006	   *
19007	   * @param  {Bounds} bounds
19008	   * @param  {string} text
19009	   *
19010	   * @return {Bounds}
19011	   */
19012	  this.getTextAnnotationBounds = function(bounds, text) {
19013
19014	    var layoutedDimensions = textUtil.getDimensions(text, {
19015	      box: bounds,
19016	      style: defaultStyle,
19017	      align: 'left-top',
19018	      padding: 5
19019	    });
19020
19021	    return {
19022	      x: bounds.x,
19023	      y: bounds.y,
19024	      width: bounds.width,
19025	      height: Math.max(MIN_TEXT_ANNOTATION_HEIGHT, Math.round(layoutedDimensions.height))
19026	    };
19027	  };
19028
19029	  /**
19030	   * Create a layouted text element.
19031	   *
19032	   * @param {string} text
19033	   * @param {Object} [options]
19034	   *
19035	   * @return {SVGElement} rendered text
19036	   */
19037	  this.createText = function(text, options) {
19038	    return textUtil.createText(text, options || {});
19039	  };
19040
19041	  /**
19042	   * Get default text style.
19043	   */
19044	  this.getDefaultStyle = function() {
19045	    return defaultStyle;
19046	  };
19047
19048	  /**
19049	   * Get the external text style.
19050	   */
19051	  this.getExternalStyle = function() {
19052	    return externalStyle;
19053	  };
19054
19055	}
19056
19057	TextRenderer.$inject = [
19058	  'config.textRenderer'
19059	];
19060
19061	/**
19062	 * Map containing SVG paths needed by BpmnRenderer.
19063	 */
19064
19065	function PathMap() {
19066
19067	  /**
19068	   * Contains a map of path elements
19069	   *
19070	   * <h1>Path definition</h1>
19071	   * A parameterized path is defined like this:
19072	   * <pre>
19073	   * 'GATEWAY_PARALLEL': {
19074	   *   d: 'm {mx},{my} {e.x0},0 0,{e.x1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
19075	          '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
19076	   *   height: 17.5,
19077	   *   width:  17.5,
19078	   *   heightElements: [2.5, 7.5],
19079	   *   widthElements: [2.5, 7.5]
19080	   * }
19081	   * </pre>
19082	   * <p>It's important to specify a correct <b>height and width</b> for the path as the scaling
19083	   * is based on the ratio between the specified height and width in this object and the
19084	   * height and width that is set as scale target (Note x,y coordinates will be scaled with
19085	   * individual ratios).</p>
19086	   * <p>The '<b>heightElements</b>' and '<b>widthElements</b>' array must contain the values that will be scaled.
19087	   * The scaling is based on the computed ratios.
19088	   * Coordinates on the y axis should be in the <b>heightElement</b>'s array, they will be scaled using
19089	   * the computed ratio coefficient.
19090	   * In the parameterized path the scaled values can be accessed through the 'e' object in {} brackets.
19091	   *   <ul>
19092	   *    <li>The values for the y axis can be accessed in the path string using {e.y0}, {e.y1}, ....</li>
19093	   *    <li>The values for the x axis can be accessed in the path string using {e.x0}, {e.x1}, ....</li>
19094	   *   </ul>
19095	   *   The numbers x0, x1 respectively y0, y1, ... map to the corresponding array index.
19096	   * </p>
19097	   */
19098	  this.pathMap = {
19099	    'EVENT_MESSAGE': {
19100	      d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
19101	      height: 36,
19102	      width:  36,
19103	      heightElements: [6, 14],
19104	      widthElements: [10.5, 21]
19105	    },
19106	    'EVENT_SIGNAL': {
19107	      d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x1},0 Z',
19108	      height: 36,
19109	      width: 36,
19110	      heightElements: [18],
19111	      widthElements: [10, 20]
19112	    },
19113	    'EVENT_ESCALATION': {
19114	      d: 'M {mx},{my} l {e.x0},{e.y0} l -{e.x0},-{e.y1} l -{e.x0},{e.y1} Z',
19115	      height: 36,
19116	      width: 36,
19117	      heightElements: [20, 7],
19118	      widthElements: [8]
19119	    },
19120	    'EVENT_CONDITIONAL': {
19121	      d: 'M {e.x0},{e.y0} l {e.x1},0 l 0,{e.y2} l -{e.x1},0 Z ' +
19122	         'M {e.x2},{e.y3} l {e.x0},0 ' +
19123	         'M {e.x2},{e.y4} l {e.x0},0 ' +
19124	         'M {e.x2},{e.y5} l {e.x0},0 ' +
19125	         'M {e.x2},{e.y6} l {e.x0},0 ' +
19126	         'M {e.x2},{e.y7} l {e.x0},0 ' +
19127	         'M {e.x2},{e.y8} l {e.x0},0 ',
19128	      height: 36,
19129	      width:  36,
19130	      heightElements: [8.5, 14.5, 18, 11.5, 14.5, 17.5, 20.5, 23.5, 26.5],
19131	      widthElements:  [10.5, 14.5, 12.5]
19132	    },
19133	    'EVENT_LINK': {
19134	      d: 'm {mx},{my} 0,{e.y0} -{e.x1},0 0,{e.y1} {e.x1},0 0,{e.y0} {e.x0},-{e.y2} -{e.x0},-{e.y2} z',
19135	      height: 36,
19136	      width: 36,
19137	      heightElements: [4.4375, 6.75, 7.8125],
19138	      widthElements: [9.84375, 13.5]
19139	    },
19140	    'EVENT_ERROR': {
19141	      d: 'm {mx},{my} {e.x0},-{e.y0} {e.x1},-{e.y1} {e.x2},{e.y2} {e.x3},-{e.y3} -{e.x4},{e.y4} -{e.x5},-{e.y5} z',
19142	      height: 36,
19143	      width: 36,
19144	      heightElements: [0.023, 8.737, 8.151, 16.564, 10.591, 8.714],
19145	      widthElements: [0.085, 6.672, 6.97, 4.273, 5.337, 6.636]
19146	    },
19147	    'EVENT_CANCEL_45': {
19148	      d: 'm {mx},{my} -{e.x1},0 0,{e.x0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
19149	        '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
19150	      height: 36,
19151	      width: 36,
19152	      heightElements: [4.75, 8.5],
19153	      widthElements: [4.75, 8.5]
19154	    },
19155	    'EVENT_COMPENSATION': {
19156	      d: 'm {mx},{my} {e.x0},-{e.y0} 0,{e.y1} z m {e.x1},-{e.y2} {e.x2},-{e.y3} 0,{e.y1} -{e.x2},-{e.y3} z',
19157	      height: 36,
19158	      width: 36,
19159	      heightElements: [6.5, 13, 0.4, 6.1],
19160	      widthElements: [9, 9.3, 8.7]
19161	    },
19162	    'EVENT_TIMER_WH': {
19163	      d: 'M {mx},{my} l {e.x0},-{e.y0} m -{e.x0},{e.y0} l {e.x1},{e.y1} ',
19164	      height: 36,
19165	      width:  36,
19166	      heightElements: [10, 2],
19167	      widthElements: [3, 7]
19168	    },
19169	    'EVENT_TIMER_LINE': {
19170	      d:  'M {mx},{my} ' +
19171	          'm {e.x0},{e.y0} l -{e.x1},{e.y1} ',
19172	      height: 36,
19173	      width:  36,
19174	      heightElements: [10, 3],
19175	      widthElements: [0, 0]
19176	    },
19177	    'EVENT_MULTIPLE': {
19178	      d:'m {mx},{my} {e.x1},-{e.y0} {e.x1},{e.y0} -{e.x0},{e.y1} -{e.x2},0 z',
19179	      height: 36,
19180	      width:  36,
19181	      heightElements: [6.28099, 12.56199],
19182	      widthElements: [3.1405, 9.42149, 12.56198]
19183	    },
19184	    'EVENT_PARALLEL_MULTIPLE': {
19185	      d:'m {mx},{my} {e.x0},0 0,{e.y1} {e.x1},0 0,{e.y0} -{e.x1},0 0,{e.y1} ' +
19186	        '-{e.x0},0 0,-{e.y1} -{e.x1},0 0,-{e.y0} {e.x1},0 z',
19187	      height: 36,
19188	      width:  36,
19189	      heightElements: [2.56228, 7.68683],
19190	      widthElements: [2.56228, 7.68683]
19191	    },
19192	    'GATEWAY_EXCLUSIVE': {
19193	      d:'m {mx},{my} {e.x0},{e.y0} {e.x1},{e.y0} {e.x2},0 {e.x4},{e.y2} ' +
19194	                    '{e.x4},{e.y1} {e.x2},0 {e.x1},{e.y3} {e.x0},{e.y3} ' +
19195	                    '{e.x3},0 {e.x5},{e.y1} {e.x5},{e.y2} {e.x3},0 z',
19196	      height: 17.5,
19197	      width:  17.5,
19198	      heightElements: [8.5, 6.5312, -6.5312, -8.5],
19199	      widthElements:  [6.5, -6.5, 3, -3, 5, -5]
19200	    },
19201	    'GATEWAY_PARALLEL': {
19202	      d:'m {mx},{my} 0,{e.y1} -{e.x1},0 0,{e.y0} {e.x1},0 0,{e.y1} {e.x0},0 ' +
19203	        '0,-{e.y1} {e.x1},0 0,-{e.y0} -{e.x1},0 0,-{e.y1} -{e.x0},0 z',
19204	      height: 30,
19205	      width:  30,
19206	      heightElements: [5, 12.5],
19207	      widthElements: [5, 12.5]
19208	    },
19209	    'GATEWAY_EVENT_BASED': {
19210	      d:'m {mx},{my} {e.x0},{e.y0} {e.x0},{e.y1} {e.x1},{e.y2} {e.x2},0 z',
19211	      height: 11,
19212	      width:  11,
19213	      heightElements: [-6, 6, 12, -12],
19214	      widthElements: [9, -3, -12]
19215	    },
19216	    'GATEWAY_COMPLEX': {
19217	      d:'m {mx},{my} 0,{e.y0} -{e.x0},-{e.y1} -{e.x1},{e.y2} {e.x0},{e.y1} -{e.x2},0 0,{e.y3} ' +
19218	        '{e.x2},0  -{e.x0},{e.y1} l {e.x1},{e.y2} {e.x0},-{e.y1} 0,{e.y0} {e.x3},0 0,-{e.y0} {e.x0},{e.y1} ' +
19219	        '{e.x1},-{e.y2} -{e.x0},-{e.y1} {e.x2},0 0,-{e.y3} -{e.x2},0 {e.x0},-{e.y1} -{e.x1},-{e.y2} ' +
19220	        '-{e.x0},{e.y1} 0,-{e.y0} -{e.x3},0 z',
19221	      height: 17.125,
19222	      width:  17.125,
19223	      heightElements: [4.875, 3.4375, 2.125, 3],
19224	      widthElements: [3.4375, 2.125, 4.875, 3]
19225	    },
19226	    'DATA_OBJECT_PATH': {
19227	      d:'m 0,0 {e.x1},0 {e.x0},{e.y0} 0,{e.y1} -{e.x2},0 0,-{e.y2} {e.x1},0 0,{e.y0} {e.x0},0',
19228	      height: 61,
19229	      width:  51,
19230	      heightElements: [10, 50, 60],
19231	      widthElements: [10, 40, 50, 60]
19232	    },
19233	    'DATA_OBJECT_COLLECTION_PATH': {
19234	      d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
19235	      height: 10,
19236	      width: 10,
19237	      heightElements: [],
19238	      widthElements: []
19239	    },
19240	    'DATA_ARROW': {
19241	      d:'m 5,9 9,0 0,-3 5,5 -5,5 0,-3 -9,0 z',
19242	      height: 61,
19243	      width:  51,
19244	      heightElements: [],
19245	      widthElements: []
19246	    },
19247	    'DATA_STORE': {
19248	      d:'m  {mx},{my} ' +
19249	        'l  0,{e.y2} ' +
19250	        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0 ' +
19251	        'l  0,-{e.y2} ' +
19252	        'c -{e.x0},-{e.y1} -{e.x1},-{e.y1} -{e.x2},0' +
19253	        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0 ' +
19254	        'm  -{e.x2},{e.y0}' +
19255	        'c  {e.x0},{e.y1} {e.x1},{e.y1} {e.x2},0' +
19256	        'm  -{e.x2},{e.y0}' +
19257	        'c  {e.x0},{e.y1} {e.x1},{e.y1}  {e.x2},0',
19258	      height: 61,
19259	      width:  61,
19260	      heightElements: [7, 10, 45],
19261	      widthElements:  [2, 58, 60]
19262	    },
19263	    'TEXT_ANNOTATION': {
19264	      d: 'm {mx}, {my} m 10,0 l -10,0 l 0,{e.y0} l 10,0',
19265	      height: 30,
19266	      width: 10,
19267	      heightElements: [30],
19268	      widthElements: [10]
19269	    },
19270	    'MARKER_SUB_PROCESS': {
19271	      d: 'm{mx},{my} m 7,2 l 0,10 m -5,-5 l 10,0',
19272	      height: 10,
19273	      width: 10,
19274	      heightElements: [],
19275	      widthElements: []
19276	    },
19277	    'MARKER_PARALLEL': {
19278	      d: 'm{mx},{my} m 3,2 l 0,10 m 3,-10 l 0,10 m 3,-10 l 0,10',
19279	      height: 10,
19280	      width: 10,
19281	      heightElements: [],
19282	      widthElements: []
19283	    },
19284	    'MARKER_SEQUENTIAL': {
19285	      d: 'm{mx},{my} m 0,3 l 10,0 m -10,3 l 10,0 m -10,3 l 10,0',
19286	      height: 10,
19287	      width: 10,
19288	      heightElements: [],
19289	      widthElements: []
19290	    },
19291	    'MARKER_COMPENSATION': {
19292	      d: 'm {mx},{my} 7,-5 0,10 z m 7.1,-0.3 6.9,-4.7 0,10 -6.9,-4.7 z',
19293	      height: 10,
19294	      width: 21,
19295	      heightElements: [],
19296	      widthElements: []
19297	    },
19298	    'MARKER_LOOP': {
19299	      d: 'm {mx},{my} c 3.526979,0 6.386161,-2.829858 6.386161,-6.320661 0,-3.490806 -2.859182,-6.320661 ' +
19300	        '-6.386161,-6.320661 -3.526978,0 -6.38616,2.829855 -6.38616,6.320661 0,1.745402 ' +
19301	        '0.714797,3.325567 1.870463,4.469381 0.577834,0.571908 1.265885,1.034728 2.029916,1.35457 ' +
19302	        'l -0.718163,-3.909793 m 0.718163,3.909793 -3.885211,0.802902',
19303	      height: 13.9,
19304	      width: 13.7,
19305	      heightElements: [],
19306	      widthElements: []
19307	    },
19308	    'MARKER_ADHOC': {
19309	      d: 'm {mx},{my} m 0.84461,2.64411 c 1.05533,-1.23780996 2.64337,-2.07882 4.29653,-1.97997996 2.05163,0.0805 ' +
19310	        '3.85579,1.15803 5.76082,1.79107 1.06385,0.34139996 2.24454,0.1438 3.18759,-0.43767 0.61743,-0.33642 ' +
19311	        '1.2775,-0.64078 1.7542,-1.17511 0,0.56023 0,1.12046 0,1.6807 -0.98706,0.96237996 -2.29792,1.62393996 ' +
19312	        '-3.6918,1.66181996 -1.24459,0.0927 -2.46671,-0.2491 -3.59505,-0.74812 -1.35789,-0.55965 ' +
19313	        '-2.75133,-1.33436996 -4.27027,-1.18121996 -1.37741,0.14601 -2.41842,1.13685996 -3.44288,1.96782996 z',
19314	      height: 4,
19315	      width: 15,
19316	      heightElements: [],
19317	      widthElements: []
19318	    },
19319	    'TASK_TYPE_SEND': {
19320	      d: 'm {mx},{my} l 0,{e.y1} l {e.x1},0 l 0,-{e.y1} z l {e.x0},{e.y0} l {e.x0},-{e.y0}',
19321	      height: 14,
19322	      width:  21,
19323	      heightElements: [6, 14],
19324	      widthElements: [10.5, 21]
19325	    },
19326	    'TASK_TYPE_SCRIPT': {
19327	      d: 'm {mx},{my} c 9.966553,-6.27276 -8.000926,-7.91932 2.968968,-14.938 l -8.802728,0 ' +
19328	        'c -10.969894,7.01868 6.997585,8.66524 -2.968967,14.938 z ' +
19329	        'm -7,-12 l 5,0 ' +
19330	        'm -4.5,3 l 4.5,0 ' +
19331	        'm -3,3 l 5,0' +
19332	        'm -4,3 l 5,0',
19333	      height: 15,
19334	      width:  12.6,
19335	      heightElements: [6, 14],
19336	      widthElements: [10.5, 21]
19337	    },
19338	    'TASK_TYPE_USER_1': {
19339	      d: 'm {mx},{my} c 0.909,-0.845 1.594,-2.049 1.594,-3.385 0,-2.554 -1.805,-4.62199999 ' +
19340	        '-4.357,-4.62199999 -2.55199998,0 -4.28799998,2.06799999 -4.28799998,4.62199999 0,1.348 ' +
19341	        '0.974,2.562 1.89599998,3.405 -0.52899998,0.187 -5.669,2.097 -5.794,4.7560005 v 6.718 ' +
19342	        'h 17 v -6.718 c 0,-2.2980005 -5.5279996,-4.5950005 -6.0509996,-4.7760005 z' +
19343	        'm -8,6 l 0,5.5 m 11,0 l 0,-5'
19344	    },
19345	    'TASK_TYPE_USER_2': {
19346	      d: 'm {mx},{my} m 2.162,1.009 c 0,2.4470005 -2.158,4.4310005 -4.821,4.4310005 ' +
19347	        '-2.66499998,0 -4.822,-1.981 -4.822,-4.4310005 '
19348	    },
19349	    'TASK_TYPE_USER_3': {
19350	      d: 'm {mx},{my} m -6.9,-3.80 c 0,0 2.25099998,-2.358 4.27399998,-1.177 2.024,1.181 4.221,1.537 ' +
19351	        '4.124,0.965 -0.098,-0.57 -0.117,-3.79099999 -4.191,-4.13599999 -3.57499998,0.001 ' +
19352	        '-4.20799998,3.36699999 -4.20699998,4.34799999 z'
19353	    },
19354	    'TASK_TYPE_MANUAL': {
19355	      d: 'm {mx},{my} c 0.234,-0.01 5.604,0.008 8.029,0.004 0.808,0 1.271,-0.172 1.417,-0.752 0.227,-0.898 ' +
19356	        '-0.334,-1.314 -1.338,-1.316 -2.467,-0.01 -7.886,-0.004 -8.108,-0.004 -0.014,-0.079 0.016,-0.533 0,-0.61 ' +
19357	        '0.195,-0.042 8.507,0.006 9.616,0.002 0.877,-0.007 1.35,-0.438 1.353,-1.208 0.003,-0.768 -0.479,-1.09 ' +
19358	        '-1.35,-1.091 -2.968,-0.002 -9.619,-0.013 -9.619,-0.013 v -0.591 c 0,0 5.052,-0.016 7.225,-0.016 ' +
19359	        '0.888,-0.002 1.354,-0.416 1.351,-1.193 -0.006,-0.761 -0.492,-1.196 -1.361,-1.196 -3.473,-0.005 ' +
19360	        '-10.86,-0.003 -11.0829995,-0.003 -0.022,-0.047 -0.045,-0.094 -0.069,-0.139 0.3939995,-0.319 ' +
19361	        '2.0409995,-1.626 2.4149995,-2.017 0.469,-0.4870005 0.519,-1.1650005 0.162,-1.6040005 -0.414,-0.511 ' +
19362	        '-0.973,-0.5 -1.48,-0.236 -1.4609995,0.764 -6.5999995,3.6430005 -7.7329995,4.2710005 -0.9,0.499 ' +
19363	        '-1.516,1.253 -1.882,2.19 -0.37000002,0.95 -0.17,2.01 -0.166,2.979 0.004,0.718 -0.27300002,1.345 ' +
19364	        '-0.055,2.063 0.629,2.087 2.425,3.312 4.859,3.318 4.6179995,0.014 9.2379995,-0.139 13.8569995,-0.158 ' +
19365	        '0.755,-0.004 1.171,-0.301 1.182,-1.033 0.012,-0.754 -0.423,-0.969 -1.183,-0.973 -1.778,-0.01 ' +
19366	        '-5.824,-0.004 -6.04,-0.004 10e-4,-0.084 0.003,-0.586 10e-4,-0.67 z'
19367	    },
19368	    'TASK_TYPE_INSTANTIATING_SEND': {
19369	      d: 'm {mx},{my} l 0,8.4 l 12.6,0 l 0,-8.4 z l 6.3,3.6 l 6.3,-3.6'
19370	    },
19371	    'TASK_TYPE_SERVICE': {
19372	      d: 'm {mx},{my} v -1.71335 c 0.352326,-0.0705 0.703932,-0.17838 1.047628,-0.32133 ' +
19373	        '0.344416,-0.14465 0.665822,-0.32133 0.966377,-0.52145 l 1.19431,1.18005 1.567487,-1.57688 ' +
19374	        '-1.195028,-1.18014 c 0.403376,-0.61394 0.683079,-1.29908 0.825447,-2.01824 l 1.622133,-0.01 ' +
19375	        'v -2.2196 l -1.636514,0.01 c -0.07333,-0.35153 -0.178319,-0.70024 -0.323564,-1.04372 ' +
19376	        '-0.145244,-0.34406 -0.321407,-0.6644 -0.522735,-0.96217 l 1.131035,-1.13631 -1.583305,-1.56293 ' +
19377	        '-1.129598,1.13589 c -0.614052,-0.40108 -1.302883,-0.68093 -2.022633,-0.82247 l 0.0093,-1.61852 ' +
19378	        'h -2.241173 l 0.0042,1.63124 c -0.353763,0.0736 -0.705369,0.17977 -1.049785,0.32371 -0.344415,0.14437 ' +
19379	        '-0.665102,0.32092 -0.9635006,0.52046 l -1.1698628,-1.15823 -1.5667691,1.5792 1.1684265,1.15669 ' +
19380	        'c -0.4026573,0.61283 -0.68308,1.29797 -0.8247287,2.01713 l -1.6588041,0.003 v 2.22174 ' +
19381	        'l 1.6724648,-0.006 c 0.073327,0.35077 0.1797598,0.70243 0.3242851,1.04472 0.1452428,0.34448 ' +
19382	        '0.3214064,0.6644 0.5227339,0.96066 l -1.1993431,1.19723 1.5840256,1.56011 1.1964668,-1.19348 ' +
19383	        'c 0.6140517,0.40346 1.3028827,0.68232 2.0233517,0.82331 l 7.19e-4,1.69892 h 2.226848 z ' +
19384	        'm 0.221462,-3.9957 c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
19385	        '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
19386	        '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
19387	    },
19388	    'TASK_TYPE_SERVICE_FILL': {
19389	      d: 'm {mx},{my} c -1.788948,0.7502 -3.8576,-0.0928 -4.6097055,-1.87438 -0.7521065,-1.78321 ' +
19390	        '0.090598,-3.84627 1.8802645,-4.59604 1.78823,-0.74936 3.856881,0.0929 4.608987,1.87437 ' +
19391	        '0.752106,1.78165 -0.0906,3.84612 -1.879546,4.59605 z'
19392	    },
19393	    'TASK_TYPE_BUSINESS_RULE_HEADER': {
19394	      d: 'm {mx},{my} 0,4 20,0 0,-4 z'
19395	    },
19396	    'TASK_TYPE_BUSINESS_RULE_MAIN': {
19397	      d: 'm {mx},{my} 0,12 20,0 0,-12 z' +
19398	        'm 0,8 l 20,0 ' +
19399	        'm -13,-4 l 0,8'
19400	    },
19401	    'MESSAGE_FLOW_MARKER': {
19402	      d: 'm {mx},{my} m -10.5 ,-7 l 0,14 l 21,0 l 0,-14 z l 10.5,6 l 10.5,-6'
19403	    }
19404	  };
19405
19406	  this.getRawPath = function getRawPath(pathId) {
19407	    return this.pathMap[pathId].d;
19408	  };
19409
19410	  /**
19411	   * Scales the path to the given height and width.
19412	   * <h1>Use case</h1>
19413	   * <p>Use case is to scale the content of elements (event, gateways) based
19414	   * on the element bounding box's size.
19415	   * </p>
19416	   * <h1>Why not transform</h1>
19417	   * <p>Scaling a path with transform() will also scale the stroke and IE does not support
19418	   * the option 'non-scaling-stroke' to prevent this.
19419	   * Also there are use cases where only some parts of a path should be
19420	   * scaled.</p>
19421	   *
19422	   * @param {string} pathId The ID of the path.
19423	   * @param {Object} param <p>
19424	   *   Example param object scales the path to 60% size of the container (data.width, data.height).
19425	   *   <pre>
19426	   *   {
19427	   *     xScaleFactor: 0.6,
19428	   *     yScaleFactor:0.6,
19429	   *     containerWidth: data.width,
19430	   *     containerHeight: data.height,
19431	   *     position: {
19432	   *       mx: 0.46,
19433	   *       my: 0.2,
19434	   *     }
19435	   *   }
19436	   *   </pre>
19437	   *   <ul>
19438	   *    <li>targetpathwidth = xScaleFactor * containerWidth</li>
19439	   *    <li>targetpathheight = yScaleFactor * containerHeight</li>
19440	   *    <li>Position is used to set the starting coordinate of the path. M is computed:
19441	    *    <ul>
19442	    *      <li>position.x * containerWidth</li>
19443	    *      <li>position.y * containerHeight</li>
19444	    *    </ul>
19445	    *    Center of the container <pre> position: {
19446	   *       mx: 0.5,
19447	   *       my: 0.5,
19448	   *     }</pre>
19449	   *     Upper left corner of the container
19450	   *     <pre> position: {
19451	   *       mx: 0.0,
19452	   *       my: 0.0,
19453	   *     }</pre>
19454	   *    </li>
19455	   *   </ul>
19456	   * </p>
19457	   *
19458	   */
19459	  this.getScaledPath = function getScaledPath(pathId, param) {
19460	    var rawPath = this.pathMap[pathId];
19461
19462	    // positioning
19463	    // compute the start point of the path
19464	    var mx, my;
19465
19466	    if (param.abspos) {
19467	      mx = param.abspos.x;
19468	      my = param.abspos.y;
19469	    } else {
19470	      mx = param.containerWidth * param.position.mx;
19471	      my = param.containerHeight * param.position.my;
19472	    }
19473
19474	    var coordinates = {}; // map for the scaled coordinates
19475	    if (param.position) {
19476
19477	      // path
19478	      var heightRatio = (param.containerHeight / rawPath.height) * param.yScaleFactor;
19479	      var widthRatio = (param.containerWidth / rawPath.width) * param.xScaleFactor;
19480
19481
19482	      // Apply height ratio
19483	      for (var heightIndex = 0; heightIndex < rawPath.heightElements.length; heightIndex++) {
19484	        coordinates['y' + heightIndex] = rawPath.heightElements[heightIndex] * heightRatio;
19485	      }
19486
19487	      // Apply width ratio
19488	      for (var widthIndex = 0; widthIndex < rawPath.widthElements.length; widthIndex++) {
19489	        coordinates['x' + widthIndex] = rawPath.widthElements[widthIndex] * widthRatio;
19490	      }
19491	    }
19492
19493	    // Apply value to raw path
19494	    var path = format(
19495	      rawPath.d, {
19496	        mx: mx,
19497	        my: my,
19498	        e: coordinates
19499	      }
19500	    );
19501	    return path;
19502	  };
19503	}
19504
19505	// helpers //////////////////////
19506
19507	// copied and adjusted from https://github.com/adobe-webplatform/Snap.svg/blob/master/src/svg.js
19508	var tokenRegex = /\{([^{}]+)\}/g,
19509	    objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g; // matches .xxxxx or ["xxxxx"] to run over object properties
19510
19511	function replacer(all, key, obj) {
19512	  var res = obj;
19513	  key.replace(objNotationRegex, function(all, name, quote, quotedName, isFunc) {
19514	    name = name || quotedName;
19515	    if (res) {
19516	      if (name in res) {
19517	        res = res[name];
19518	      }
19519	      typeof res == 'function' && isFunc && (res = res());
19520	    }
19521	  });
19522	  res = (res == null || res == obj ? all : res) + '';
19523
19524	  return res;
19525	}
19526
19527	function format(str, obj) {
19528	  return String(str).replace(tokenRegex, function(all, key) {
19529	    return replacer(all, key, obj);
19530	  });
19531	}
19532
19533	var DrawModule = {
19534	  __init__: [ 'bpmnRenderer' ],
19535	  bpmnRenderer: [ 'type', BpmnRenderer ],
19536	  textRenderer: [ 'type', TextRenderer ],
19537	  pathMap: [ 'type', PathMap ]
19538	};
19539
19540	/**
19541	 * A simple translation stub to be used for multi-language support
19542	 * in diagrams. Can be easily replaced with a more sophisticated
19543	 * solution.
19544	 *
19545	 * @example
19546	 *
19547	 * // use it inside any diagram component by injecting `translate`.
19548	 *
19549	 * function MyService(translate) {
19550	 *   alert(translate('HELLO {you}', { you: 'You!' }));
19551	 * }
19552	 *
19553	 * @param {string} template to interpolate
19554	 * @param {Object} [replacements] a map with substitutes
19555	 *
19556	 * @return {string} the translated string
19557	 */
19558	function translate$1(template, replacements) {
19559
19560	  replacements = replacements || {};
19561
19562	  return template.replace(/{([^}]+)}/g, function(_, key) {
19563	    return replacements[key] || '{' + key + '}';
19564	  });
19565	}
19566
19567	var translate = {
19568	  translate: [ 'value', translate$1 ]
19569	};
19570
19571	var DEFAULT_LABEL_SIZE = {
19572	  width: 90,
19573	  height: 20
19574	};
19575
19576	var FLOW_LABEL_INDENT = 15;
19577
19578
19579	/**
19580	 * Returns true if the given semantic has an external label
19581	 *
19582	 * @param {BpmnElement} semantic
19583	 * @return {boolean} true if has label
19584	 */
19585	function isLabelExternal(semantic) {
19586	  return is$1(semantic, 'bpmn:Event') ||
19587	         is$1(semantic, 'bpmn:Gateway') ||
19588	         is$1(semantic, 'bpmn:DataStoreReference') ||
19589	         is$1(semantic, 'bpmn:DataObjectReference') ||
19590	         is$1(semantic, 'bpmn:DataInput') ||
19591	         is$1(semantic, 'bpmn:DataOutput') ||
19592	         is$1(semantic, 'bpmn:SequenceFlow') ||
19593	         is$1(semantic, 'bpmn:MessageFlow') ||
19594	         is$1(semantic, 'bpmn:Group');
19595	}
19596
19597	/**
19598	 * Returns true if the given element has an external label
19599	 *
19600	 * @param {djs.model.shape} element
19601	 * @return {boolean} true if has label
19602	 */
19603	function hasExternalLabel(element) {
19604	  return isLabel$6(element.label);
19605	}
19606
19607	/**
19608	 * Get the position for sequence flow labels
19609	 *
19610	 * @param  {Array<Point>} waypoints
19611	 * @return {Point} the label position
19612	 */
19613	function getFlowLabelPosition(waypoints) {
19614
19615	  // get the waypoints mid
19616	  var mid = waypoints.length / 2 - 1;
19617
19618	  var first = waypoints[Math.floor(mid)];
19619	  var second = waypoints[Math.ceil(mid + 0.01)];
19620
19621	  // get position
19622	  var position = getWaypointsMid(waypoints);
19623
19624	  // calculate angle
19625	  var angle = Math.atan((second.y - first.y) / (second.x - first.x));
19626
19627	  var x = position.x,
19628	      y = position.y;
19629
19630	  if (Math.abs(angle) < Math.PI / 2) {
19631	    y -= FLOW_LABEL_INDENT;
19632	  } else {
19633	    x += FLOW_LABEL_INDENT;
19634	  }
19635
19636	  return { x: x, y: y };
19637	}
19638
19639
19640	/**
19641	 * Get the middle of a number of waypoints
19642	 *
19643	 * @param  {Array<Point>} waypoints
19644	 * @return {Point} the mid point
19645	 */
19646	function getWaypointsMid(waypoints) {
19647
19648	  var mid = waypoints.length / 2 - 1;
19649
19650	  var first = waypoints[Math.floor(mid)];
19651	  var second = waypoints[Math.ceil(mid + 0.01)];
19652
19653	  return {
19654	    x: first.x + (second.x - first.x) / 2,
19655	    y: first.y + (second.y - first.y) / 2
19656	  };
19657	}
19658
19659
19660	function getExternalLabelMid(element) {
19661
19662	  if (element.waypoints) {
19663	    return getFlowLabelPosition(element.waypoints);
19664	  } else if (is$1(element, 'bpmn:Group')) {
19665	    return {
19666	      x: element.x + element.width / 2,
19667	      y: element.y + DEFAULT_LABEL_SIZE.height / 2
19668	    };
19669	  } else {
19670	    return {
19671	      x: element.x + element.width / 2,
19672	      y: element.y + element.height + DEFAULT_LABEL_SIZE.height / 2
19673	    };
19674	  }
19675	}
19676
19677
19678	/**
19679	 * Returns the bounds of an elements label, parsed from the elements DI or
19680	 * generated from its bounds.
19681	 *
19682	 * @param {BpmnElement} semantic
19683	 * @param {djs.model.Base} element
19684	 */
19685	function getExternalLabelBounds(semantic, element) {
19686
19687	  var mid,
19688	      size,
19689	      bounds,
19690	      di = semantic.di,
19691	      label = di.label;
19692
19693	  if (label && label.bounds) {
19694	    bounds = label.bounds;
19695
19696	    size = {
19697	      width: Math.max(DEFAULT_LABEL_SIZE.width, bounds.width),
19698	      height: bounds.height
19699	    };
19700
19701	    mid = {
19702	      x: bounds.x + bounds.width / 2,
19703	      y: bounds.y + bounds.height / 2
19704	    };
19705	  } else {
19706
19707	    mid = getExternalLabelMid(element);
19708
19709	    size = DEFAULT_LABEL_SIZE;
19710	  }
19711
19712	  return assign({
19713	    x: mid.x - size.width / 2,
19714	    y: mid.y - size.height / 2
19715	  }, size);
19716	}
19717
19718	function isLabel$6(element) {
19719	  return element && !!element.labelTarget;
19720	}
19721
19722	function elementData(semantic, attrs) {
19723	  return assign({
19724	    id: semantic.id,
19725	    type: semantic.$type,
19726	    businessObject: semantic
19727	  }, attrs);
19728	}
19729
19730	function getWaypoints(bo, source, target) {
19731
19732	  var waypoints = bo.di.waypoint;
19733
19734	  if (!waypoints || waypoints.length < 2) {
19735	    return [ getMid(source), getMid(target) ];
19736	  }
19737
19738	  return waypoints.map(function(p) {
19739	    return { x: p.x, y: p.y };
19740	  });
19741	}
19742
19743	function notYetDrawn(translate, semantic, refSemantic, property) {
19744	  return new Error(translate('element {element} referenced by {referenced}#{property} not yet drawn', {
19745	    element: elementToString(refSemantic),
19746	    referenced: elementToString(semantic),
19747	    property: property
19748	  }));
19749	}
19750
19751
19752	/**
19753	 * An importer that adds bpmn elements to the canvas
19754	 *
19755	 * @param {EventBus} eventBus
19756	 * @param {Canvas} canvas
19757	 * @param {ElementFactory} elementFactory
19758	 * @param {ElementRegistry} elementRegistry
19759	 * @param {Function} translate
19760	 * @param {TextRenderer} textRenderer
19761	 */
19762	function BpmnImporter(
19763	    eventBus, canvas, elementFactory,
19764	    elementRegistry, translate, textRenderer) {
19765
19766	  this._eventBus = eventBus;
19767	  this._canvas = canvas;
19768	  this._elementFactory = elementFactory;
19769	  this._elementRegistry = elementRegistry;
19770	  this._translate = translate;
19771	  this._textRenderer = textRenderer;
19772	}
19773
19774	BpmnImporter.$inject = [
19775	  'eventBus',
19776	  'canvas',
19777	  'elementFactory',
19778	  'elementRegistry',
19779	  'translate',
19780	  'textRenderer'
19781	];
19782
19783
19784	/**
19785	 * Add bpmn element (semantic) to the canvas onto the
19786	 * specified parent shape.
19787	 */
19788	BpmnImporter.prototype.add = function(semantic, parentElement) {
19789
19790	  var di = semantic.di,
19791	      element,
19792	      translate = this._translate,
19793	      hidden;
19794
19795	  var parentIndex;
19796
19797	  // ROOT ELEMENT
19798	  // handle the special case that we deal with a
19799	  // invisible root element (process or collaboration)
19800	  if (is$1(di, 'bpmndi:BPMNPlane')) {
19801
19802	    // add a virtual element (not being drawn)
19803	    element = this._elementFactory.createRoot(elementData(semantic));
19804
19805	    this._canvas.setRootElement(element);
19806	  }
19807
19808	  // SHAPE
19809	  else if (is$1(di, 'bpmndi:BPMNShape')) {
19810
19811	    var collapsed = !isExpanded(semantic),
19812	        isFrame = isFrameElement(semantic);
19813	    hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
19814
19815	    var bounds = semantic.di.bounds;
19816
19817	    element = this._elementFactory.createShape(elementData(semantic, {
19818	      collapsed: collapsed,
19819	      hidden: hidden,
19820	      x: Math.round(bounds.x),
19821	      y: Math.round(bounds.y),
19822	      width: Math.round(bounds.width),
19823	      height: Math.round(bounds.height),
19824	      isFrame: isFrame
19825	    }));
19826
19827	    if (is$1(semantic, 'bpmn:BoundaryEvent')) {
19828	      this._attachBoundary(semantic, element);
19829	    }
19830
19831	    // insert lanes behind other flow nodes (cf. #727)
19832	    if (is$1(semantic, 'bpmn:Lane')) {
19833	      parentIndex = 0;
19834	    }
19835
19836	    if (is$1(semantic, 'bpmn:DataStoreReference')) {
19837
19838	      // check whether data store is inside our outside of its semantic parent
19839	      if (!isPointInsideBBox$1(parentElement, getMid(bounds))) {
19840	        parentElement = this._canvas.getRootElement();
19841	      }
19842	    }
19843
19844	    this._canvas.addShape(element, parentElement, parentIndex);
19845	  }
19846
19847	  // CONNECTION
19848	  else if (is$1(di, 'bpmndi:BPMNEdge')) {
19849
19850	    var source = this._getSource(semantic),
19851	        target = this._getTarget(semantic);
19852
19853	    hidden = parentElement && (parentElement.hidden || parentElement.collapsed);
19854
19855	    element = this._elementFactory.createConnection(elementData(semantic, {
19856	      hidden: hidden,
19857	      source: source,
19858	      target: target,
19859	      waypoints: getWaypoints(semantic, source, target)
19860	    }));
19861
19862	    if (is$1(semantic, 'bpmn:DataAssociation')) {
19863
19864	      // render always on top; this ensures DataAssociations
19865	      // are rendered correctly across different "hacks" people
19866	      // love to model such as cross participant / sub process
19867	      // associations
19868	      parentElement = null;
19869	    }
19870
19871	    // insert sequence flows behind other flow nodes (cf. #727)
19872	    if (is$1(semantic, 'bpmn:SequenceFlow')) {
19873	      parentIndex = 0;
19874	    }
19875
19876	    this._canvas.addConnection(element, parentElement, parentIndex);
19877	  } else {
19878	    throw new Error(translate('unknown di {di} for element {semantic}', {
19879	      di: elementToString(di),
19880	      semantic: elementToString(semantic)
19881	    }));
19882	  }
19883
19884	  // (optional) LABEL
19885	  if (isLabelExternal(semantic) && getLabel(element)) {
19886	    this.addLabel(semantic, element);
19887	  }
19888
19889
19890	  this._eventBus.fire('bpmnElement.added', { element: element });
19891
19892	  return element;
19893	};
19894
19895
19896	/**
19897	 * Attach the boundary element to the given host
19898	 *
19899	 * @param {ModdleElement} boundarySemantic
19900	 * @param {djs.model.Base} boundaryElement
19901	 */
19902	BpmnImporter.prototype._attachBoundary = function(boundarySemantic, boundaryElement) {
19903	  var translate = this._translate;
19904	  var hostSemantic = boundarySemantic.attachedToRef;
19905
19906	  if (!hostSemantic) {
19907	    throw new Error(translate('missing {semantic}#attachedToRef', {
19908	      semantic: elementToString(boundarySemantic)
19909	    }));
19910	  }
19911
19912	  var host = this._elementRegistry.get(hostSemantic.id),
19913	      attachers = host && host.attachers;
19914
19915	  if (!host) {
19916	    throw notYetDrawn(translate, boundarySemantic, hostSemantic, 'attachedToRef');
19917	  }
19918
19919	  // wire element.host <> host.attachers
19920	  boundaryElement.host = host;
19921
19922	  if (!attachers) {
19923	    host.attachers = attachers = [];
19924	  }
19925
19926	  if (attachers.indexOf(boundaryElement) === -1) {
19927	    attachers.push(boundaryElement);
19928	  }
19929	};
19930
19931
19932	/**
19933	 * add label for an element
19934	 */
19935	BpmnImporter.prototype.addLabel = function(semantic, element) {
19936	  var bounds,
19937	      text,
19938	      label;
19939
19940	  bounds = getExternalLabelBounds(semantic, element);
19941
19942	  text = getLabel(element);
19943
19944	  if (text) {
19945
19946	    // get corrected bounds from actual layouted text
19947	    bounds = this._textRenderer.getExternalLabelBounds(bounds, text);
19948	  }
19949
19950	  label = this._elementFactory.createLabel(elementData(semantic, {
19951	    id: semantic.id + '_label',
19952	    labelTarget: element,
19953	    type: 'label',
19954	    hidden: element.hidden || !getLabel(element),
19955	    x: Math.round(bounds.x),
19956	    y: Math.round(bounds.y),
19957	    width: Math.round(bounds.width),
19958	    height: Math.round(bounds.height)
19959	  }));
19960
19961	  return this._canvas.addShape(label, element.parent);
19962	};
19963
19964	/**
19965	 * Return the drawn connection end based on the given side.
19966	 *
19967	 * @throws {Error} if the end is not yet drawn
19968	 */
19969	BpmnImporter.prototype._getEnd = function(semantic, side) {
19970
19971	  var element,
19972	      refSemantic,
19973	      type = semantic.$type,
19974	      translate = this._translate;
19975
19976	  refSemantic = semantic[side + 'Ref'];
19977
19978	  // handle mysterious isMany DataAssociation#sourceRef
19979	  if (side === 'source' && type === 'bpmn:DataInputAssociation') {
19980	    refSemantic = refSemantic && refSemantic[0];
19981	  }
19982
19983	  // fix source / target for DataInputAssociation / DataOutputAssociation
19984	  if (side === 'source' && type === 'bpmn:DataOutputAssociation' ||
19985	      side === 'target' && type === 'bpmn:DataInputAssociation') {
19986
19987	    refSemantic = semantic.$parent;
19988	  }
19989
19990	  element = refSemantic && this._getElement(refSemantic);
19991
19992	  if (element) {
19993	    return element;
19994	  }
19995
19996	  if (refSemantic) {
19997	    throw notYetDrawn(translate, semantic, refSemantic, side + 'Ref');
19998	  } else {
19999	    throw new Error(translate('{semantic}#{side} Ref not specified', {
20000	      semantic: elementToString(semantic),
20001	      side: side
20002	    }));
20003	  }
20004	};
20005
20006	BpmnImporter.prototype._getSource = function(semantic) {
20007	  return this._getEnd(semantic, 'source');
20008	};
20009
20010	BpmnImporter.prototype._getTarget = function(semantic) {
20011	  return this._getEnd(semantic, 'target');
20012	};
20013
20014
20015	BpmnImporter.prototype._getElement = function(semantic) {
20016	  return this._elementRegistry.get(semantic.id);
20017	};
20018
20019
20020	// helpers ////////////////////
20021
20022	function isPointInsideBBox$1(bbox, point) {
20023	  var x = point.x,
20024	      y = point.y;
20025
20026	  return x >= bbox.x &&
20027	    x <= bbox.x + bbox.width &&
20028	    y >= bbox.y &&
20029	    y <= bbox.y + bbox.height;
20030	}
20031
20032	function isFrameElement(semantic) {
20033	  return is$1(semantic, 'bpmn:Group');
20034	}
20035
20036	var ImportModule = {
20037	  __depends__: [
20038	    translate
20039	  ],
20040	  bpmnImporter: [ 'type', BpmnImporter ]
20041	};
20042
20043	var CoreModule = {
20044	  __depends__: [
20045	    DrawModule,
20046	    ImportModule
20047	  ]
20048	};
20049
20050	function __stopPropagation(event) {
20051	  if (!event || typeof event.stopPropagation !== 'function') {
20052	    return;
20053	  }
20054
20055	  event.stopPropagation();
20056	}
20057
20058
20059	function getOriginal$1(event) {
20060	  return event.originalEvent || event.srcEvent;
20061	}
20062
20063
20064	function stopPropagation$1(event, immediate) {
20065	  __stopPropagation(event);
20066	  __stopPropagation(getOriginal$1(event));
20067	}
20068
20069
20070	function toPoint(event) {
20071
20072	  if (event.pointers && event.pointers.length) {
20073	    event = event.pointers[0];
20074	  }
20075
20076	  if (event.touches && event.touches.length) {
20077	    event = event.touches[0];
20078	  }
20079
20080	  return event ? {
20081	    x: event.clientX,
20082	    y: event.clientY
20083	  } : null;
20084	}
20085
20086	function isMac() {
20087	  return (/mac/i).test(navigator.platform);
20088	}
20089
20090	function isButton(event, button) {
20091	  return (getOriginal$1(event) || event).button === button;
20092	}
20093
20094	function isPrimaryButton(event) {
20095
20096	  // button === 0 -> left áka primary mouse button
20097	  return isButton(event, 0);
20098	}
20099
20100	function isAuxiliaryButton(event) {
20101
20102	  // button === 1 -> auxiliary áka wheel button
20103	  return isButton(event, 1);
20104	}
20105
20106	function hasPrimaryModifier(event) {
20107	  var originalEvent = getOriginal$1(event) || event;
20108
20109	  if (!isPrimaryButton(event)) {
20110	    return false;
20111	  }
20112
20113	  // Use cmd as primary modifier key for mac OS
20114	  if (isMac()) {
20115	    return originalEvent.metaKey;
20116	  } else {
20117	    return originalEvent.ctrlKey;
20118	  }
20119	}
20120
20121
20122	function hasSecondaryModifier(event) {
20123	  var originalEvent = getOriginal$1(event) || event;
20124
20125	  return isPrimaryButton(event) && originalEvent.shiftKey;
20126	}
20127
20128	function allowAll(event) { return true; }
20129
20130	function allowPrimaryAndAuxiliary(event) {
20131	  return isPrimaryButton(event) || isAuxiliaryButton(event);
20132	}
20133
20134	var LOW_PRIORITY$m = 500;
20135
20136
20137	/**
20138	 * A plugin that provides interaction events for diagram elements.
20139	 *
20140	 * It emits the following events:
20141	 *
20142	 *   * element.click
20143	 *   * element.contextmenu
20144	 *   * element.dblclick
20145	 *   * element.hover
20146	 *   * element.mousedown
20147	 *   * element.mousemove
20148	 *   * element.mouseup
20149	 *   * element.out
20150	 *
20151	 * Each event is a tuple { element, gfx, originalEvent }.
20152	 *
20153	 * Canceling the event via Event#preventDefault()
20154	 * prevents the original DOM operation.
20155	 *
20156	 * @param {EventBus} eventBus
20157	 */
20158	function InteractionEvents(eventBus, elementRegistry, styles) {
20159
20160	  var self = this;
20161
20162	  /**
20163	   * Fire an interaction event.
20164	   *
20165	   * @param {string} type local event name, e.g. element.click.
20166	   * @param {DOMEvent} event native event
20167	   * @param {djs.model.Base} [element] the diagram element to emit the event on;
20168	   *                                   defaults to the event target
20169	   */
20170	  function fire(type, event, element) {
20171
20172	    if (isIgnored(type, event)) {
20173	      return;
20174	    }
20175
20176	    var target, gfx, returnValue;
20177
20178	    if (!element) {
20179	      target = event.delegateTarget || event.target;
20180
20181	      if (target) {
20182	        gfx = target;
20183	        element = elementRegistry.get(gfx);
20184	      }
20185	    } else {
20186	      gfx = elementRegistry.getGraphics(element);
20187	    }
20188
20189	    if (!gfx || !element) {
20190	      return;
20191	    }
20192
20193	    returnValue = eventBus.fire(type, {
20194	      element: element,
20195	      gfx: gfx,
20196	      originalEvent: event
20197	    });
20198
20199	    if (returnValue === false) {
20200	      event.stopPropagation();
20201	      event.preventDefault();
20202	    }
20203	  }
20204
20205	  // TODO(nikku): document this
20206	  var handlers = {};
20207
20208	  function mouseHandler(localEventName) {
20209	    return handlers[localEventName];
20210	  }
20211
20212	  function isIgnored(localEventName, event) {
20213
20214	    var filter = ignoredFilters[localEventName] || isPrimaryButton;
20215
20216	    // only react on left mouse button interactions
20217	    // except for interaction events that are enabled
20218	    // for secundary mouse button
20219	    return !filter(event);
20220	  }
20221
20222	  var bindings = {
20223	    click: 'element.click',
20224	    contextmenu: 'element.contextmenu',
20225	    dblclick: 'element.dblclick',
20226	    mousedown: 'element.mousedown',
20227	    mousemove: 'element.mousemove',
20228	    mouseover: 'element.hover',
20229	    mouseout: 'element.out',
20230	    mouseup: 'element.mouseup',
20231	  };
20232
20233	  var ignoredFilters = {
20234	    'element.contextmenu': allowAll,
20235	    'element.mousedown': allowPrimaryAndAuxiliary,
20236	    'element.mouseup': allowPrimaryAndAuxiliary,
20237	    'element.click': allowPrimaryAndAuxiliary,
20238	    'element.dblclick': allowPrimaryAndAuxiliary
20239	  };
20240
20241
20242	  // manual event trigger //////////
20243
20244	  /**
20245	   * Trigger an interaction event (based on a native dom event)
20246	   * on the target shape or connection.
20247	   *
20248	   * @param {string} eventName the name of the triggered DOM event
20249	   * @param {MouseEvent} event
20250	   * @param {djs.model.Base} targetElement
20251	   */
20252	  function triggerMouseEvent(eventName, event, targetElement) {
20253
20254	    // i.e. element.mousedown...
20255	    var localEventName = bindings[eventName];
20256
20257	    if (!localEventName) {
20258	      throw new Error('unmapped DOM event name <' + eventName + '>');
20259	    }
20260
20261	    return fire(localEventName, event, targetElement);
20262	  }
20263
20264
20265	  var ELEMENT_SELECTOR = 'svg, .djs-element';
20266
20267	  // event handling ///////
20268
20269	  function registerEvent(node, event, localEvent, ignoredFilter) {
20270
20271	    var handler = handlers[localEvent] = function(event) {
20272	      fire(localEvent, event);
20273	    };
20274
20275	    if (ignoredFilter) {
20276	      ignoredFilters[localEvent] = ignoredFilter;
20277	    }
20278
20279	    handler.$delegate = delegate.bind(node, ELEMENT_SELECTOR, event, handler);
20280	  }
20281
20282	  function unregisterEvent(node, event, localEvent) {
20283
20284	    var handler = mouseHandler(localEvent);
20285
20286	    if (!handler) {
20287	      return;
20288	    }
20289
20290	    delegate.unbind(node, event, handler.$delegate);
20291	  }
20292
20293	  function registerEvents(svg) {
20294	    forEach(bindings, function(val, key) {
20295	      registerEvent(svg, key, val);
20296	    });
20297	  }
20298
20299	  function unregisterEvents(svg) {
20300	    forEach(bindings, function(val, key) {
20301	      unregisterEvent(svg, key, val);
20302	    });
20303	  }
20304
20305	  eventBus.on('canvas.destroy', function(event) {
20306	    unregisterEvents(event.svg);
20307	  });
20308
20309	  eventBus.on('canvas.init', function(event) {
20310	    registerEvents(event.svg);
20311	  });
20312
20313
20314	  // hit box updating ////////////////
20315
20316	  eventBus.on([ 'shape.added', 'connection.added' ], function(event) {
20317	    var element = event.element,
20318	        gfx = event.gfx;
20319
20320	    eventBus.fire('interactionEvents.createHit', { element: element, gfx: gfx });
20321	  });
20322
20323	  // Update djs-hit on change.
20324	  // A low priortity is necessary, because djs-hit of labels has to be updated
20325	  // after the label bounds have been updated in the renderer.
20326	  eventBus.on([
20327	    'shape.changed',
20328	    'connection.changed'
20329	  ], LOW_PRIORITY$m, function(event) {
20330
20331	    var element = event.element,
20332	        gfx = event.gfx;
20333
20334	    eventBus.fire('interactionEvents.updateHit', { element: element, gfx: gfx });
20335	  });
20336
20337	  eventBus.on('interactionEvents.createHit', LOW_PRIORITY$m, function(event) {
20338	    var element = event.element,
20339	        gfx = event.gfx;
20340
20341	    self.createDefaultHit(element, gfx);
20342	  });
20343
20344	  eventBus.on('interactionEvents.updateHit', function(event) {
20345	    var element = event.element,
20346	        gfx = event.gfx;
20347
20348	    self.updateDefaultHit(element, gfx);
20349	  });
20350
20351
20352	  // hit styles ////////////
20353
20354	  var STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-stroke');
20355
20356	  var CLICK_STROKE_HIT_STYLE = createHitStyle('djs-hit djs-hit-click-stroke');
20357
20358	  var ALL_HIT_STYLE = createHitStyle('djs-hit djs-hit-all');
20359
20360	  var HIT_TYPES = {
20361	    'all': ALL_HIT_STYLE,
20362	    'click-stroke': CLICK_STROKE_HIT_STYLE,
20363	    'stroke': STROKE_HIT_STYLE
20364	  };
20365
20366	  function createHitStyle(classNames, attrs) {
20367
20368	    attrs = assign({
20369	      stroke: 'white',
20370	      strokeWidth: 15
20371	    }, attrs || {});
20372
20373	    return styles.cls(classNames, [ 'no-fill', 'no-border' ], attrs);
20374	  }
20375
20376
20377	  // style helpers ///////////////
20378
20379	  function applyStyle(hit, type) {
20380
20381	    var attrs = HIT_TYPES[type];
20382
20383	    if (!attrs) {
20384	      throw new Error('invalid hit type <' + type + '>');
20385	    }
20386
20387	    attr(hit, attrs);
20388
20389	    return hit;
20390	  }
20391
20392	  function appendHit(gfx, hit) {
20393	    append(gfx, hit);
20394	  }
20395
20396
20397	  // API
20398
20399	  /**
20400	   * Remove hints on the given graphics.
20401	   *
20402	   * @param {SVGElement} gfx
20403	   */
20404	  this.removeHits = function(gfx) {
20405	    var hits = all('.djs-hit', gfx);
20406
20407	    forEach(hits, remove$1);
20408	  };
20409
20410	  /**
20411	   * Create default hit for the given element.
20412	   *
20413	   * @param {djs.model.Base} element
20414	   * @param {SVGElement} gfx
20415	   *
20416	   * @return {SVGElement} created hit
20417	   */
20418	  this.createDefaultHit = function(element, gfx) {
20419	    var waypoints = element.waypoints,
20420	        isFrame = element.isFrame,
20421	        boxType;
20422
20423	    if (waypoints) {
20424	      return this.createWaypointsHit(gfx, waypoints);
20425	    } else {
20426
20427	      boxType = isFrame ? 'stroke' : 'all';
20428
20429	      return this.createBoxHit(gfx, boxType, {
20430	        width: element.width,
20431	        height: element.height
20432	      });
20433	    }
20434	  };
20435
20436	  /**
20437	   * Create hits for the given waypoints.
20438	   *
20439	   * @param {SVGElement} gfx
20440	   * @param {Array<Point>} waypoints
20441	   *
20442	   * @return {SVGElement}
20443	   */
20444	  this.createWaypointsHit = function(gfx, waypoints) {
20445
20446	    var hit = createLine(waypoints);
20447
20448	    applyStyle(hit, 'stroke');
20449
20450	    appendHit(gfx, hit);
20451
20452	    return hit;
20453	  };
20454
20455	  /**
20456	   * Create hits for a box.
20457	   *
20458	   * @param {SVGElement} gfx
20459	   * @param {string} hitType
20460	   * @param {Object} attrs
20461	   *
20462	   * @return {SVGElement}
20463	   */
20464	  this.createBoxHit = function(gfx, type, attrs) {
20465
20466	    attrs = assign({
20467	      x: 0,
20468	      y: 0
20469	    }, attrs);
20470
20471	    var hit = create$1('rect');
20472
20473	    applyStyle(hit, type);
20474
20475	    attr(hit, attrs);
20476
20477	    appendHit(gfx, hit);
20478
20479	    return hit;
20480	  };
20481
20482	  /**
20483	   * Update default hit of the element.
20484	   *
20485	   * @param  {djs.model.Base} element
20486	   * @param  {SVGElement} gfx
20487	   *
20488	   * @return {SVGElement} updated hit
20489	   */
20490	  this.updateDefaultHit = function(element, gfx) {
20491
20492	    var hit = query('.djs-hit', gfx);
20493
20494	    if (!hit) {
20495	      return;
20496	    }
20497
20498	    if (element.waypoints) {
20499	      updateLine(hit, element.waypoints);
20500	    } else {
20501	      attr(hit, {
20502	        width: element.width,
20503	        height: element.height
20504	      });
20505	    }
20506
20507	    return hit;
20508	  };
20509
20510	  this.fire = fire;
20511
20512	  this.triggerMouseEvent = triggerMouseEvent;
20513
20514	  this.mouseHandler = mouseHandler;
20515
20516	  this.registerEvent = registerEvent;
20517	  this.unregisterEvent = unregisterEvent;
20518	}
20519
20520
20521	InteractionEvents.$inject = [
20522	  'eventBus',
20523	  'elementRegistry',
20524	  'styles'
20525	];
20526
20527
20528	/**
20529	 * An event indicating that the mouse hovered over an element
20530	 *
20531	 * @event element.hover
20532	 *
20533	 * @type {Object}
20534	 * @property {djs.model.Base} element
20535	 * @property {SVGElement} gfx
20536	 * @property {Event} originalEvent
20537	 */
20538
20539	/**
20540	 * An event indicating that the mouse has left an element
20541	 *
20542	 * @event element.out
20543	 *
20544	 * @type {Object}
20545	 * @property {djs.model.Base} element
20546	 * @property {SVGElement} gfx
20547	 * @property {Event} originalEvent
20548	 */
20549
20550	/**
20551	 * An event indicating that the mouse has clicked an element
20552	 *
20553	 * @event element.click
20554	 *
20555	 * @type {Object}
20556	 * @property {djs.model.Base} element
20557	 * @property {SVGElement} gfx
20558	 * @property {Event} originalEvent
20559	 */
20560
20561	/**
20562	 * An event indicating that the mouse has double clicked an element
20563	 *
20564	 * @event element.dblclick
20565	 *
20566	 * @type {Object}
20567	 * @property {djs.model.Base} element
20568	 * @property {SVGElement} gfx
20569	 * @property {Event} originalEvent
20570	 */
20571
20572	/**
20573	 * An event indicating that the mouse has gone down on an element.
20574	 *
20575	 * @event element.mousedown
20576	 *
20577	 * @type {Object}
20578	 * @property {djs.model.Base} element
20579	 * @property {SVGElement} gfx
20580	 * @property {Event} originalEvent
20581	 */
20582
20583	/**
20584	 * An event indicating that the mouse has gone up on an element.
20585	 *
20586	 * @event element.mouseup
20587	 *
20588	 * @type {Object}
20589	 * @property {djs.model.Base} element
20590	 * @property {SVGElement} gfx
20591	 * @property {Event} originalEvent
20592	 */
20593
20594	/**
20595	 * An event indicating that the context menu action is triggered
20596	 * via mouse or touch controls.
20597	 *
20598	 * @event element.contextmenu
20599	 *
20600	 * @type {Object}
20601	 * @property {djs.model.Base} element
20602	 * @property {SVGElement} gfx
20603	 * @property {Event} originalEvent
20604	 */
20605
20606	var InteractionEventsModule$1 = {
20607	  __init__: [ 'interactionEvents' ],
20608	  interactionEvents: [ 'type', InteractionEvents ]
20609	};
20610
20611	var LOW_PRIORITY$l = 500;
20612
20613
20614	/**
20615	 * @class
20616	 *
20617	 * A plugin that adds an outline to shapes and connections that may be activated and styled
20618	 * via CSS classes.
20619	 *
20620	 * @param {EventBus} eventBus
20621	 * @param {Styles} styles
20622	 * @param {ElementRegistry} elementRegistry
20623	 */
20624	function Outline(eventBus, styles, elementRegistry) {
20625
20626	  this.offset = 6;
20627
20628	  var OUTLINE_STYLE = styles.cls('djs-outline', [ 'no-fill' ]);
20629
20630	  var self = this;
20631
20632	  function createOutline(gfx, bounds) {
20633	    var outline = create$1('rect');
20634
20635	    attr(outline, assign({
20636	      x: 10,
20637	      y: 10,
20638	      width: 100,
20639	      height: 100
20640	    }, OUTLINE_STYLE));
20641
20642	    append(gfx, outline);
20643
20644	    return outline;
20645	  }
20646
20647	  // A low priortity is necessary, because outlines of labels have to be updated
20648	  // after the label bounds have been updated in the renderer.
20649	  eventBus.on([ 'shape.added', 'shape.changed' ], LOW_PRIORITY$l, function(event) {
20650	    var element = event.element,
20651	        gfx = event.gfx;
20652
20653	    var outline = query('.djs-outline', gfx);
20654
20655	    if (!outline) {
20656	      outline = createOutline(gfx);
20657	    }
20658
20659	    self.updateShapeOutline(outline, element);
20660	  });
20661
20662	  eventBus.on([ 'connection.added', 'connection.changed' ], function(event) {
20663	    var element = event.element,
20664	        gfx = event.gfx;
20665
20666	    var outline = query('.djs-outline', gfx);
20667
20668	    if (!outline) {
20669	      outline = createOutline(gfx);
20670	    }
20671
20672	    self.updateConnectionOutline(outline, element);
20673	  });
20674	}
20675
20676
20677	/**
20678	 * Updates the outline of a shape respecting the dimension of the
20679	 * element and an outline offset.
20680	 *
20681	 * @param  {SVGElement} outline
20682	 * @param  {djs.model.Base} element
20683	 */
20684	Outline.prototype.updateShapeOutline = function(outline, element) {
20685
20686	  attr(outline, {
20687	    x: -this.offset,
20688	    y: -this.offset,
20689	    width: element.width + this.offset * 2,
20690	    height: element.height + this.offset * 2
20691	  });
20692
20693	};
20694
20695
20696	/**
20697	 * Updates the outline of a connection respecting the bounding box of
20698	 * the connection and an outline offset.
20699	 *
20700	 * @param  {SVGElement} outline
20701	 * @param  {djs.model.Base} element
20702	 */
20703	Outline.prototype.updateConnectionOutline = function(outline, connection) {
20704
20705	  var bbox = getBBox(connection);
20706
20707	  attr(outline, {
20708	    x: bbox.x - this.offset,
20709	    y: bbox.y - this.offset,
20710	    width: bbox.width + this.offset * 2,
20711	    height: bbox.height + this.offset * 2
20712	  });
20713
20714	};
20715
20716
20717	Outline.$inject = ['eventBus', 'styles', 'elementRegistry'];
20718
20719	var OutlineModule = {
20720	  __init__: [ 'outline' ],
20721	  outline: [ 'type', Outline ]
20722	};
20723
20724	/**
20725	 * A service that offers the current selection in a diagram.
20726	 * Offers the api to control the selection, too.
20727	 *
20728	 * @class
20729	 *
20730	 * @param {EventBus} eventBus the event bus
20731	 */
20732	function Selection(eventBus, canvas) {
20733
20734	  this._eventBus = eventBus;
20735	  this._canvas = canvas;
20736
20737	  this._selectedElements = [];
20738
20739	  var self = this;
20740
20741	  eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
20742	    var element = e.element;
20743	    self.deselect(element);
20744	  });
20745
20746	  eventBus.on([ 'diagram.clear', 'plane.set' ], function(e) {
20747	    self.select(null);
20748	  });
20749	}
20750
20751	Selection.$inject = [ 'eventBus', 'canvas' ];
20752
20753
20754	Selection.prototype.deselect = function(element) {
20755	  var selectedElements = this._selectedElements;
20756
20757	  var idx = selectedElements.indexOf(element);
20758
20759	  if (idx !== -1) {
20760	    var oldSelection = selectedElements.slice();
20761
20762	    selectedElements.splice(idx, 1);
20763
20764	    this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
20765	  }
20766	};
20767
20768
20769	Selection.prototype.get = function() {
20770	  return this._selectedElements;
20771	};
20772
20773	Selection.prototype.isSelected = function(element) {
20774	  return this._selectedElements.indexOf(element) !== -1;
20775	};
20776
20777
20778	/**
20779	 * This method selects one or more elements on the diagram.
20780	 *
20781	 * By passing an additional add parameter you can decide whether or not the element(s)
20782	 * should be added to the already existing selection or not.
20783	 *
20784	 * @method Selection#select
20785	 *
20786	 * @param  {Object|Object[]} elements element or array of elements to be selected
20787	 * @param  {boolean} [add] whether the element(s) should be appended to the current selection, defaults to false
20788	 */
20789	Selection.prototype.select = function(elements, add) {
20790	  var selectedElements = this._selectedElements,
20791	      oldSelection = selectedElements.slice();
20792
20793	  if (!isArray$2(elements)) {
20794	    elements = elements ? [ elements ] : [];
20795	  }
20796
20797	  var canvas = this._canvas;
20798
20799	  elements = elements.filter(function(element) {
20800	    var plane = canvas.findPlane(element);
20801
20802	    return plane === canvas.getActivePlane();
20803	  });
20804
20805	  // selection may be cleared by passing an empty array or null
20806	  // to the method
20807	  if (add) {
20808	    forEach(elements, function(element) {
20809	      if (selectedElements.indexOf(element) !== -1) {
20810
20811	        // already selected
20812	        return;
20813	      } else {
20814	        selectedElements.push(element);
20815	      }
20816	    });
20817	  } else {
20818	    this._selectedElements = selectedElements = elements.slice();
20819	  }
20820
20821	  this._eventBus.fire('selection.changed', { oldSelection: oldSelection, newSelection: selectedElements });
20822	};
20823
20824	var MARKER_HOVER = 'hover',
20825	    MARKER_SELECTED = 'selected';
20826
20827
20828	/**
20829	 * A plugin that adds a visible selection UI to shapes and connections
20830	 * by appending the <code>hover</code> and <code>selected</code> classes to them.
20831	 *
20832	 * @class
20833	 *
20834	 * Makes elements selectable, too.
20835	 *
20836	 * @param {EventBus} events
20837	 * @param {SelectionService} selection
20838	 * @param {Canvas} canvas
20839	 */
20840	function SelectionVisuals(events, canvas, selection, styles) {
20841
20842	  this._multiSelectionBox = null;
20843
20844	  function addMarker(e, cls) {
20845	    canvas.addMarker(e, cls);
20846	  }
20847
20848	  function removeMarker(e, cls) {
20849	    canvas.removeMarker(e, cls);
20850	  }
20851
20852	  events.on('element.hover', function(event) {
20853	    addMarker(event.element, MARKER_HOVER);
20854	  });
20855
20856	  events.on('element.out', function(event) {
20857	    removeMarker(event.element, MARKER_HOVER);
20858	  });
20859
20860	  events.on('selection.changed', function(event) {
20861
20862	    function deselect(s) {
20863	      removeMarker(s, MARKER_SELECTED);
20864	    }
20865
20866	    function select(s) {
20867	      addMarker(s, MARKER_SELECTED);
20868	    }
20869
20870	    var oldSelection = event.oldSelection,
20871	        newSelection = event.newSelection;
20872
20873	    forEach(oldSelection, function(e) {
20874	      if (newSelection.indexOf(e) === -1) {
20875	        deselect(e);
20876	      }
20877	    });
20878
20879	    forEach(newSelection, function(e) {
20880	      if (oldSelection.indexOf(e) === -1) {
20881	        select(e);
20882	      }
20883	    });
20884	  });
20885	}
20886
20887	SelectionVisuals.$inject = [
20888	  'eventBus',
20889	  'canvas',
20890	  'selection',
20891	  'styles'
20892	];
20893
20894	function SelectionBehavior(eventBus, selection, canvas, elementRegistry) {
20895
20896	  // Select elements on create
20897	  eventBus.on('create.end', 500, function(event) {
20898	    var context = event.context,
20899	        canExecute = context.canExecute,
20900	        elements = context.elements,
20901	        hints = context.hints || {},
20902	        autoSelect = hints.autoSelect;
20903
20904	    if (canExecute) {
20905	      if (autoSelect === false) {
20906
20907	        // Select no elements
20908	        return;
20909	      }
20910
20911	      if (isArray$2(autoSelect)) {
20912	        selection.select(autoSelect);
20913	      } else {
20914
20915	        // Select all elements by default
20916	        selection.select(elements.filter(isShown));
20917	      }
20918	    }
20919	  });
20920
20921	  // Select connection targets on connect
20922	  eventBus.on('connect.end', 500, function(event) {
20923	    var context = event.context,
20924	        canExecute = context.canExecute,
20925	        hover = context.hover;
20926
20927	    if (canExecute && hover) {
20928	      selection.select(hover);
20929	    }
20930	  });
20931
20932	  // Select shapes on move
20933	  eventBus.on('shape.move.end', 500, function(event) {
20934	    var previousSelection = event.previousSelection || [];
20935
20936	    var shape = elementRegistry.get(event.context.shape.id);
20937
20938	    // Always select main shape on move
20939	    var isSelected = find(previousSelection, function(selectedShape) {
20940	      return shape.id === selectedShape.id;
20941	    });
20942
20943	    if (!isSelected) {
20944	      selection.select(shape);
20945	    }
20946	  });
20947
20948	  // Select elements on click
20949	  eventBus.on('element.click', function(event) {
20950
20951	    if (!isPrimaryButton(event)) {
20952	      return;
20953	    }
20954
20955	    var element = event.element;
20956
20957	    if (element === canvas.getRootElement()) {
20958	      element = null;
20959	    }
20960
20961	    var isSelected = selection.isSelected(element),
20962	        isMultiSelect = selection.get().length > 1;
20963
20964	    // Add to selection if CTRL or SHIFT pressed
20965	    var add = hasPrimaryModifier(event) || hasSecondaryModifier(event);
20966
20967	    if (isSelected && isMultiSelect) {
20968	      if (add) {
20969
20970	        // Deselect element
20971	        return selection.deselect(element);
20972	      } else {
20973
20974	        // Select element only
20975	        return selection.select(element);
20976	      }
20977	    } else if (!isSelected) {
20978
20979	      // Select element
20980	      selection.select(element, add);
20981	    } else {
20982
20983	      // Deselect element
20984	      selection.deselect(element);
20985	    }
20986	  });
20987	}
20988
20989	SelectionBehavior.$inject = [
20990	  'eventBus',
20991	  'selection',
20992	  'canvas',
20993	  'elementRegistry'
20994	];
20995
20996
20997	function isShown(element) {
20998	  return !element.hidden;
20999	}
21000
21001	var SelectionModule = {
21002	  __init__: [ 'selectionVisuals', 'selectionBehavior' ],
21003	  __depends__: [
21004	    InteractionEventsModule$1,
21005	    OutlineModule
21006	  ],
21007	  selection: [ 'type', Selection ],
21008	  selectionVisuals: [ 'type', SelectionVisuals ],
21009	  selectionBehavior: [ 'type', SelectionBehavior ]
21010	};
21011
21012	/**
21013	 * Util that provides unique IDs.
21014	 *
21015	 * @class djs.util.IdGenerator
21016	 * @constructor
21017	 * @memberOf djs.util
21018	 *
21019	 * The ids can be customized via a given prefix and contain a random value to avoid collisions.
21020	 *
21021	 * @param {string} prefix a prefix to prepend to generated ids (for better readability)
21022	 */
21023	function IdGenerator(prefix) {
21024
21025	  this._counter = 0;
21026	  this._prefix = (prefix ? prefix + '-' : '') + Math.floor(Math.random() * 1000000000) + '-';
21027	}
21028
21029	/**
21030	 * Returns a next unique ID.
21031	 *
21032	 * @method djs.util.IdGenerator#next
21033	 *
21034	 * @returns {string} the id
21035	 */
21036	IdGenerator.prototype.next = function() {
21037	  return this._prefix + (++this._counter);
21038	};
21039
21040	// document wide unique overlay ids
21041	var ids$1 = new IdGenerator('ov');
21042
21043	var LOW_PRIORITY$k = 500;
21044
21045
21046	/**
21047	 * A service that allows users to attach overlays to diagram elements.
21048	 *
21049	 * The overlay service will take care of overlay positioning during updates.
21050	 *
21051	 * @example
21052	 *
21053	 * // add a pink badge on the top left of the shape
21054	 * overlays.add(someShape, {
21055	 *   position: {
21056	 *     top: -5,
21057	 *     left: -5
21058	 *   },
21059	 *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
21060	 * });
21061	 *
21062	 * // or add via shape id
21063	 *
21064	 * overlays.add('some-element-id', {
21065	 *   position: {
21066	 *     top: -5,
21067	 *     left: -5
21068	 *   }
21069	 *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
21070	 * });
21071	 *
21072	 * // or add with optional type
21073	 *
21074	 * overlays.add(someShape, 'badge', {
21075	 *   position: {
21076	 *     top: -5,
21077	 *     left: -5
21078	 *   }
21079	 *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
21080	 * });
21081	 *
21082	 *
21083	 * // remove an overlay
21084	 *
21085	 * var id = overlays.add(...);
21086	 * overlays.remove(id);
21087	 *
21088	 *
21089	 * You may configure overlay defaults during tool by providing a `config` module
21090	 * with `overlays.defaults` as an entry:
21091	 *
21092	 * {
21093	 *   overlays: {
21094	 *     defaults: {
21095	 *       show: {
21096	 *         minZoom: 0.7,
21097	 *         maxZoom: 5.0
21098	 *       },
21099	 *       scale: {
21100	 *         min: 1
21101	 *       }
21102	 *     }
21103	 * }
21104	 *
21105	 * @param {Object} config
21106	 * @param {EventBus} eventBus
21107	 * @param {Canvas} canvas
21108	 * @param {ElementRegistry} elementRegistry
21109	 */
21110	function Overlays(config, eventBus, canvas, elementRegistry) {
21111
21112	  this._eventBus = eventBus;
21113	  this._canvas = canvas;
21114	  this._elementRegistry = elementRegistry;
21115
21116	  this._ids = ids$1;
21117
21118	  this._overlayDefaults = assign({
21119
21120	    // no show constraints
21121	    show: null,
21122
21123	    // always scale
21124	    scale: true
21125	  }, config && config.defaults);
21126
21127	  /**
21128	   * Mapping overlayId -> overlay
21129	   */
21130	  this._overlays = {};
21131
21132	  /**
21133	   * Mapping elementId -> overlay container
21134	   */
21135	  this._overlayContainers = [];
21136
21137	  // root html element for all overlays
21138	  this._overlayRoot = createRoot$1(canvas.getContainer());
21139
21140	  this._init();
21141	}
21142
21143
21144	Overlays.$inject = [
21145	  'config.overlays',
21146	  'eventBus',
21147	  'canvas',
21148	  'elementRegistry'
21149	];
21150
21151
21152	/**
21153	 * Returns the overlay with the specified id or a list of overlays
21154	 * for an element with a given type.
21155	 *
21156	 * @example
21157	 *
21158	 * // return the single overlay with the given id
21159	 * overlays.get('some-id');
21160	 *
21161	 * // return all overlays for the shape
21162	 * overlays.get({ element: someShape });
21163	 *
21164	 * // return all overlays on shape with type 'badge'
21165	 * overlays.get({ element: someShape, type: 'badge' });
21166	 *
21167	 * // shape can also be specified as id
21168	 * overlays.get({ element: 'element-id', type: 'badge' });
21169	 *
21170	 *
21171	 * @param {Object} search
21172	 * @param {string} [search.id]
21173	 * @param {string|djs.model.Base} [search.element]
21174	 * @param {string} [search.type]
21175	 *
21176	 * @return {Object|Array<Object>} the overlay(s)
21177	 */
21178	Overlays.prototype.get = function(search) {
21179
21180	  if (isString(search)) {
21181	    search = { id: search };
21182	  }
21183
21184	  if (isString(search.element)) {
21185	    search.element = this._elementRegistry.get(search.element);
21186	  }
21187
21188	  if (search.element) {
21189	    var container = this._getOverlayContainer(search.element, true);
21190
21191	    // return a list of overlays when searching by element (+type)
21192	    if (container) {
21193	      return search.type ? filter(container.overlays, matchPattern({ type: search.type })) : container.overlays.slice();
21194	    } else {
21195	      return [];
21196	    }
21197	  } else
21198	  if (search.type) {
21199	    return filter(this._overlays, matchPattern({ type: search.type }));
21200	  } else {
21201
21202	    // return single element when searching by id
21203	    return search.id ? this._overlays[search.id] : null;
21204	  }
21205	};
21206
21207	/**
21208	 * Adds a HTML overlay to an element.
21209	 *
21210	 * @param {string|djs.model.Base}   element   attach overlay to this shape
21211	 * @param {string}                  [type]    optional type to assign to the overlay
21212	 * @param {Object}                  overlay   the overlay configuration
21213	 *
21214	 * @param {string|DOMElement}       overlay.html                 html element to use as an overlay
21215	 * @param {Object}                  [overlay.show]               show configuration
21216	 * @param {number}                  [overlay.show.minZoom]       minimal zoom level to show the overlay
21217	 * @param {number}                  [overlay.show.maxZoom]       maximum zoom level to show the overlay
21218	 * @param {Object}                  overlay.position             where to attach the overlay
21219	 * @param {number}                  [overlay.position.left]      relative to element bbox left attachment
21220	 * @param {number}                  [overlay.position.top]       relative to element bbox top attachment
21221	 * @param {number}                  [overlay.position.bottom]    relative to element bbox bottom attachment
21222	 * @param {number}                  [overlay.position.right]     relative to element bbox right attachment
21223	 * @param {boolean|Object}          [overlay.scale=true]         false to preserve the same size regardless of
21224	 *                                                               diagram zoom
21225	 * @param {number}                  [overlay.scale.min]
21226	 * @param {number}                  [overlay.scale.max]
21227	 *
21228	 * @return {string}                 id that may be used to reference the overlay for update or removal
21229	 */
21230	Overlays.prototype.add = function(element, type, overlay) {
21231
21232	  if (isObject(type)) {
21233	    overlay = type;
21234	    type = null;
21235	  }
21236
21237	  if (!element.id) {
21238	    element = this._elementRegistry.get(element);
21239	  }
21240
21241	  if (!overlay.position) {
21242	    throw new Error('must specifiy overlay position');
21243	  }
21244
21245	  if (!overlay.html) {
21246	    throw new Error('must specifiy overlay html');
21247	  }
21248
21249	  if (!element) {
21250	    throw new Error('invalid element specified');
21251	  }
21252
21253	  var id = this._ids.next();
21254
21255	  overlay = assign({}, this._overlayDefaults, overlay, {
21256	    id: id,
21257	    type: type,
21258	    element: element,
21259	    html: overlay.html
21260	  });
21261
21262	  this._addOverlay(overlay);
21263
21264	  return id;
21265	};
21266
21267
21268	/**
21269	 * Remove an overlay with the given id or all overlays matching the given filter.
21270	 *
21271	 * @see Overlays#get for filter options.
21272	 *
21273	 * @param {string} [id]
21274	 * @param {Object} [filter]
21275	 */
21276	Overlays.prototype.remove = function(filter) {
21277
21278	  var overlays = this.get(filter) || [];
21279
21280	  if (!isArray$2(overlays)) {
21281	    overlays = [ overlays ];
21282	  }
21283
21284	  var self = this;
21285
21286	  forEach(overlays, function(overlay) {
21287
21288	    var container = self._getOverlayContainer(overlay.element, true);
21289
21290	    if (overlay) {
21291	      remove$2(overlay.html);
21292	      remove$2(overlay.htmlContainer);
21293
21294	      delete overlay.htmlContainer;
21295	      delete overlay.element;
21296
21297	      delete self._overlays[overlay.id];
21298	    }
21299
21300	    if (container) {
21301	      var idx = container.overlays.indexOf(overlay);
21302	      if (idx !== -1) {
21303	        container.overlays.splice(idx, 1);
21304	      }
21305	    }
21306	  });
21307
21308	};
21309
21310
21311	Overlays.prototype.show = function() {
21312	  setVisible$1(this._overlayRoot);
21313	};
21314
21315
21316	Overlays.prototype.hide = function() {
21317	  setVisible$1(this._overlayRoot, false);
21318	};
21319
21320	Overlays.prototype.clear = function() {
21321	  this._overlays = {};
21322
21323	  this._overlayContainers = [];
21324
21325	  clear$1(this._overlayRoot);
21326	};
21327
21328	Overlays.prototype._updateOverlayContainer = function(container) {
21329	  var element = container.element,
21330	      html = container.html;
21331
21332	  // update container left,top according to the elements x,y coordinates
21333	  // this ensures we can attach child elements relative to this container
21334
21335	  var x = element.x,
21336	      y = element.y;
21337
21338	  if (element.waypoints) {
21339	    var bbox = getBBox(element);
21340	    x = bbox.x;
21341	    y = bbox.y;
21342	  }
21343
21344	  setPosition$1(html, x, y);
21345
21346	  attr$1(container.html, 'data-container-id', element.id);
21347	};
21348
21349
21350	Overlays.prototype._updateOverlay = function(overlay) {
21351
21352	  var position = overlay.position,
21353	      htmlContainer = overlay.htmlContainer,
21354	      element = overlay.element;
21355
21356	  // update overlay html relative to shape because
21357	  // it is already positioned on the element
21358
21359	  // update relative
21360	  var left = position.left,
21361	      top = position.top;
21362
21363	  if (position.right !== undefined) {
21364
21365	    var width;
21366
21367	    if (element.waypoints) {
21368	      width = getBBox(element).width;
21369	    } else {
21370	      width = element.width;
21371	    }
21372
21373	    left = position.right * -1 + width;
21374	  }
21375
21376	  if (position.bottom !== undefined) {
21377
21378	    var height;
21379
21380	    if (element.waypoints) {
21381	      height = getBBox(element).height;
21382	    } else {
21383	      height = element.height;
21384	    }
21385
21386	    top = position.bottom * -1 + height;
21387	  }
21388
21389	  setPosition$1(htmlContainer, left || 0, top || 0);
21390	};
21391
21392
21393	Overlays.prototype._createOverlayContainer = function(element) {
21394	  var html = domify('<div class="djs-overlays" style="position: absolute" />');
21395
21396	  this._overlayRoot.appendChild(html);
21397
21398	  var container = {
21399	    html: html,
21400	    element: element,
21401	    overlays: []
21402	  };
21403
21404	  this._updateOverlayContainer(container);
21405
21406	  this._overlayContainers.push(container);
21407
21408	  return container;
21409	};
21410
21411
21412	Overlays.prototype._updateRoot = function(viewbox) {
21413	  var scale = viewbox.scale || 1;
21414
21415	  var matrix = 'matrix(' +
21416	  [
21417	    scale,
21418	    0,
21419	    0,
21420	    scale,
21421	    -1 * viewbox.x * scale,
21422	    -1 * viewbox.y * scale
21423	  ].join(',') +
21424	  ')';
21425
21426	  setTransform$1(this._overlayRoot, matrix);
21427	};
21428
21429
21430	Overlays.prototype._getOverlayContainer = function(element, raw) {
21431	  var container = find(this._overlayContainers, function(c) {
21432	    return c.element === element;
21433	  });
21434
21435
21436	  if (!container && !raw) {
21437	    return this._createOverlayContainer(element);
21438	  }
21439
21440	  return container;
21441	};
21442
21443
21444	Overlays.prototype._addOverlay = function(overlay) {
21445
21446	  var id = overlay.id,
21447	      element = overlay.element,
21448	      html = overlay.html,
21449	      htmlContainer,
21450	      overlayContainer;
21451
21452	  // unwrap jquery (for those who need it)
21453	  if (html.get && html.constructor.prototype.jquery) {
21454	    html = html.get(0);
21455	  }
21456
21457	  // create proper html elements from
21458	  // overlay HTML strings
21459	  if (isString(html)) {
21460	    html = domify(html);
21461	  }
21462
21463	  overlayContainer = this._getOverlayContainer(element);
21464
21465	  htmlContainer = domify('<div class="djs-overlay" data-overlay-id="' + id + '" style="position: absolute">');
21466
21467	  htmlContainer.appendChild(html);
21468
21469	  if (overlay.type) {
21470	    classes$1(htmlContainer).add('djs-overlay-' + overlay.type);
21471	  }
21472
21473	  var plane = this._canvas.findPlane(element);
21474	  var activePlane = this._canvas.getActivePlane();
21475	  overlay.plane = plane;
21476	  if (plane !== activePlane) {
21477	    setVisible$1(htmlContainer, false);
21478	  }
21479
21480	  overlay.htmlContainer = htmlContainer;
21481
21482	  overlayContainer.overlays.push(overlay);
21483	  overlayContainer.html.appendChild(htmlContainer);
21484
21485	  this._overlays[id] = overlay;
21486
21487	  this._updateOverlay(overlay);
21488	  this._updateOverlayVisibilty(overlay, this._canvas.viewbox());
21489	};
21490
21491
21492	Overlays.prototype._updateOverlayVisibilty = function(overlay, viewbox) {
21493	  var show = overlay.show,
21494	      minZoom = show && show.minZoom,
21495	      maxZoom = show && show.maxZoom,
21496	      htmlContainer = overlay.htmlContainer,
21497	      visible = true;
21498
21499	  if (show) {
21500	    if (
21501	      (isDefined(minZoom) && minZoom > viewbox.scale) ||
21502	      (isDefined(maxZoom) && maxZoom < viewbox.scale)
21503	    ) {
21504	      visible = false;
21505	    }
21506
21507	    setVisible$1(htmlContainer, visible);
21508	  }
21509
21510	  this._updateOverlayScale(overlay, viewbox);
21511	};
21512
21513
21514	Overlays.prototype._updateOverlayScale = function(overlay, viewbox) {
21515	  var shouldScale = overlay.scale,
21516	      minScale,
21517	      maxScale,
21518	      htmlContainer = overlay.htmlContainer;
21519
21520	  var scale, transform = '';
21521
21522	  if (shouldScale !== true) {
21523
21524	    if (shouldScale === false) {
21525	      minScale = 1;
21526	      maxScale = 1;
21527	    } else {
21528	      minScale = shouldScale.min;
21529	      maxScale = shouldScale.max;
21530	    }
21531
21532	    if (isDefined(minScale) && viewbox.scale < minScale) {
21533	      scale = (1 / viewbox.scale || 1) * minScale;
21534	    }
21535
21536	    if (isDefined(maxScale) && viewbox.scale > maxScale) {
21537	      scale = (1 / viewbox.scale || 1) * maxScale;
21538	    }
21539	  }
21540
21541	  if (isDefined(scale)) {
21542	    transform = 'scale(' + scale + ',' + scale + ')';
21543	  }
21544
21545	  setTransform$1(htmlContainer, transform);
21546	};
21547
21548
21549	Overlays.prototype._updateOverlaysVisibilty = function(viewbox) {
21550
21551	  var self = this;
21552
21553	  forEach(this._overlays, function(overlay) {
21554	    self._updateOverlayVisibilty(overlay, viewbox);
21555	  });
21556	};
21557
21558
21559	Overlays.prototype._init = function() {
21560
21561	  var eventBus = this._eventBus;
21562
21563	  var self = this;
21564
21565
21566	  // scroll/zoom integration
21567
21568	  function updateViewbox(viewbox) {
21569	    self._updateRoot(viewbox);
21570	    self._updateOverlaysVisibilty(viewbox);
21571
21572	    self.show();
21573	  }
21574
21575	  eventBus.on('canvas.viewbox.changing', function(event) {
21576	    self.hide();
21577	  });
21578
21579	  eventBus.on('canvas.viewbox.changed', function(event) {
21580	    updateViewbox(event.viewbox);
21581	  });
21582
21583
21584	  // remove integration
21585
21586	  eventBus.on([ 'shape.remove', 'connection.remove' ], function(e) {
21587	    var element = e.element;
21588	    var overlays = self.get({ element: element });
21589
21590	    forEach(overlays, function(o) {
21591	      self.remove(o.id);
21592	    });
21593
21594	    var container = self._getOverlayContainer(element);
21595
21596	    if (container) {
21597	      remove$2(container.html);
21598	      var i = self._overlayContainers.indexOf(container);
21599	      if (i !== -1) {
21600	        self._overlayContainers.splice(i, 1);
21601	      }
21602	    }
21603	  });
21604
21605
21606	  // move integration
21607
21608	  eventBus.on('element.changed', LOW_PRIORITY$k, function(e) {
21609	    var element = e.element;
21610
21611	    var container = self._getOverlayContainer(element, true);
21612
21613	    if (container) {
21614	      forEach(container.overlays, function(overlay) {
21615	        self._updateOverlay(overlay);
21616	      });
21617
21618	      self._updateOverlayContainer(container);
21619	    }
21620	  });
21621
21622
21623	  // marker integration, simply add them on the overlays as classes, too.
21624
21625	  eventBus.on('element.marker.update', function(e) {
21626	    var container = self._getOverlayContainer(e.element, true);
21627	    if (container) {
21628	      classes$1(container.html)[e.add ? 'add' : 'remove'](e.marker);
21629	    }
21630	  });
21631
21632
21633	  eventBus.on('plane.set', function(e) {
21634	    forEach(self._overlays, function(el) {
21635	      setVisible$1(el.htmlContainer, el.plane === e.plane);
21636	    });
21637	  });
21638
21639	  // clear overlays with diagram
21640
21641	  eventBus.on('diagram.clear', this.clear, this);
21642	};
21643
21644
21645
21646	// helpers /////////////////////////////
21647
21648	function createRoot$1(parentNode) {
21649	  var root = domify(
21650	    '<div class="djs-overlay-container" style="position: absolute; width: 0; height: 0;" />'
21651	  );
21652
21653	  parentNode.insertBefore(root, parentNode.firstChild);
21654
21655	  return root;
21656	}
21657
21658	function setPosition$1(el, x, y) {
21659	  assign(el.style, { left: x + 'px', top: y + 'px' });
21660	}
21661
21662	function setVisible$1(el, visible) {
21663	  el.style.display = visible === false ? 'none' : '';
21664	}
21665
21666	function setTransform$1(el, transform) {
21667
21668	  el.style['transform-origin'] = 'top left';
21669
21670	  [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
21671	    el.style[prefix + 'transform'] = transform;
21672	  });
21673	}
21674
21675	var OverlaysModule = {
21676	  __init__: [ 'overlays' ],
21677	  overlays: [ 'type', Overlays ]
21678	};
21679
21680	/**
21681	 * A viewer for BPMN 2.0 diagrams.
21682	 *
21683	 * Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
21684	 * additional features.
21685	 *
21686	 *
21687	 * ## Extending the Viewer
21688	 *
21689	 * In order to extend the viewer pass extension modules to bootstrap via the
21690	 * `additionalModules` option. An extension module is an object that exposes
21691	 * named services.
21692	 *
21693	 * The following example depicts the integration of a simple
21694	 * logging component that integrates with interaction events:
21695	 *
21696	 *
21697	 * ```javascript
21698	 *
21699	 * // logging component
21700	 * function InteractionLogger(eventBus) {
21701	 *   eventBus.on('element.hover', function(event) {
21702	 *     console.log()
21703	 *   })
21704	 * }
21705	 *
21706	 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
21707	 *
21708	 * // extension module
21709	 * var extensionModule = {
21710	 *   __init__: [ 'interactionLogger' ],
21711	 *   interactionLogger: [ 'type', InteractionLogger ]
21712	 * };
21713	 *
21714	 * // extend the viewer
21715	 * var bpmnViewer = new Viewer({ additionalModules: [ extensionModule ] });
21716	 * bpmnViewer.importXML(...);
21717	 * ```
21718	 *
21719	 * @param {Object} [options] configuration options to pass to the viewer
21720	 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
21721	 * @param {string|number} [options.width] the width of the viewer
21722	 * @param {string|number} [options.height] the height of the viewer
21723	 * @param {Object} [options.moddleExtensions] extension packages to provide
21724	 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
21725	 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
21726	 */
21727	function Viewer(options) {
21728	  BaseViewer.call(this, options);
21729	}
21730
21731	inherits$1(Viewer, BaseViewer);
21732
21733	// modules the viewer is composed of
21734	Viewer.prototype._modules = [
21735	  CoreModule,
21736	  translate,
21737	  SelectionModule,
21738	  OverlaysModule
21739	];
21740
21741	// default moddle extensions the viewer is composed of
21742	Viewer.prototype._moddleExtensions = {};
21743
21744	/**
21745	 * Returns true if event was triggered with any modifier
21746	 * @param {KeyboardEvent} event
21747	 */
21748	function hasModifier(event) {
21749	  return (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey);
21750	}
21751
21752	/**
21753	 * @param {KeyboardEvent} event
21754	 */
21755	function isCmd(event) {
21756
21757	  // ensure we don't react to AltGr
21758	  // (mapped to CTRL + ALT)
21759	  if (event.altKey) {
21760	    return false;
21761	  }
21762
21763	  return event.ctrlKey || event.metaKey;
21764	}
21765
21766	/**
21767	 * Checks if key pressed is one of provided keys.
21768	 *
21769	 * @param {string|Array<string>} keys
21770	 * @param {KeyboardEvent} event
21771	 */
21772	function isKey(keys, event) {
21773	  keys = isArray$2(keys) ? keys : [ keys ];
21774
21775	  return keys.indexOf(event.key) !== -1 || keys.indexOf(event.keyCode) !== -1;
21776	}
21777
21778	/**
21779	 * @param {KeyboardEvent} event
21780	 */
21781	function isShift(event) {
21782	  return event.shiftKey;
21783	}
21784
21785	var KEYDOWN_EVENT = 'keyboard.keydown',
21786	    KEYUP_EVENT = 'keyboard.keyup';
21787
21788	var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
21789
21790	var DEFAULT_PRIORITY$4 = 1000;
21791
21792	/**
21793	 * A keyboard abstraction that may be activated and
21794	 * deactivated by users at will, consuming key events
21795	 * and triggering diagram actions.
21796	 *
21797	 * For keys pressed down, keyboard fires `keyboard.keydown` event.
21798	 * The event context contains one field which is `KeyboardEvent` event.
21799	 *
21800	 * The implementation fires the following key events that allow
21801	 * other components to hook into key handling:
21802	 *
21803	 *  - keyboard.bind
21804	 *  - keyboard.unbind
21805	 *  - keyboard.init
21806	 *  - keyboard.destroy
21807	 *
21808	 * All events contain one field which is node.
21809	 *
21810	 * A default binding for the keyboard may be specified via the
21811	 * `keyboard.bindTo` configuration option.
21812	 *
21813	 * @param {Config} config
21814	 * @param {EventBus} eventBus
21815	 */
21816	function Keyboard(config, eventBus) {
21817	  var self = this;
21818
21819	  this._config = config || {};
21820	  this._eventBus = eventBus;
21821
21822	  this._keydownHandler = this._keydownHandler.bind(this);
21823	  this._keyupHandler = this._keyupHandler.bind(this);
21824
21825	  // properly clean dom registrations
21826	  eventBus.on('diagram.destroy', function() {
21827	    self._fire('destroy');
21828
21829	    self.unbind();
21830	  });
21831
21832	  eventBus.on('diagram.init', function() {
21833	    self._fire('init');
21834	  });
21835
21836	  eventBus.on('attach', function() {
21837	    if (config && config.bindTo) {
21838	      self.bind(config.bindTo);
21839	    }
21840	  });
21841
21842	  eventBus.on('detach', function() {
21843	    self.unbind();
21844	  });
21845	}
21846
21847	Keyboard.$inject = [
21848	  'config.keyboard',
21849	  'eventBus'
21850	];
21851
21852	Keyboard.prototype._keydownHandler = function(event) {
21853	  this._keyHandler(event, KEYDOWN_EVENT);
21854	};
21855
21856	Keyboard.prototype._keyupHandler = function(event) {
21857	  this._keyHandler(event, KEYUP_EVENT);
21858	};
21859
21860	Keyboard.prototype._keyHandler = function(event, type) {
21861	  var eventBusResult;
21862
21863	  if (this._isEventIgnored(event)) {
21864	    return;
21865	  }
21866
21867	  var context = {
21868	    keyEvent: event
21869	  };
21870
21871	  eventBusResult = this._eventBus.fire(type || KEYDOWN_EVENT, context);
21872
21873	  if (eventBusResult) {
21874	    event.preventDefault();
21875	  }
21876	};
21877
21878	Keyboard.prototype._isEventIgnored = function(event) {
21879	  return isInput(event.target) && this._isModifiedKeyIgnored(event);
21880	};
21881
21882	Keyboard.prototype._isModifiedKeyIgnored = function(event) {
21883	  if (!isCmd(event)) {
21884	    return true;
21885	  }
21886
21887	  var allowedModifiers = this._getAllowedModifiers(event.target);
21888	  return !allowedModifiers.includes(event.key);
21889	};
21890
21891	Keyboard.prototype._getAllowedModifiers = function(element) {
21892	  var modifierContainer = closest(element, '[' + HANDLE_MODIFIER_ATTRIBUTE + ']', true);
21893
21894	  if (!modifierContainer || (this._node && !this._node.contains(modifierContainer))) {
21895	    return [];
21896	  }
21897
21898	  return modifierContainer.getAttribute(HANDLE_MODIFIER_ATTRIBUTE).split(',');
21899	};
21900
21901	Keyboard.prototype.bind = function(node) {
21902
21903	  // make sure that the keyboard is only bound once to the DOM
21904	  this.unbind();
21905
21906	  this._node = node;
21907
21908	  // bind key events
21909	  componentEvent.bind(node, 'keydown', this._keydownHandler, true);
21910	  componentEvent.bind(node, 'keyup', this._keyupHandler, true);
21911
21912	  this._fire('bind');
21913	};
21914
21915	Keyboard.prototype.getBinding = function() {
21916	  return this._node;
21917	};
21918
21919	Keyboard.prototype.unbind = function() {
21920	  var node = this._node;
21921
21922	  if (node) {
21923	    this._fire('unbind');
21924
21925	    // unbind key events
21926	    componentEvent.unbind(node, 'keydown', this._keydownHandler, true);
21927	    componentEvent.unbind(node, 'keyup', this._keyupHandler, true);
21928	  }
21929
21930	  this._node = null;
21931	};
21932
21933	Keyboard.prototype._fire = function(event) {
21934	  this._eventBus.fire('keyboard.' + event, { node: this._node });
21935	};
21936
21937	/**
21938	 * Add a listener function that is notified with `KeyboardEvent` whenever
21939	 * the keyboard is bound and the user presses a key. If no priority is
21940	 * provided, the default value of 1000 is used.
21941	 *
21942	 * @param {number} [priority]
21943	 * @param {Function} listener
21944	 * @param {string} type
21945	 */
21946	Keyboard.prototype.addListener = function(priority, listener, type) {
21947	  if (isFunction(priority)) {
21948	    type = listener;
21949	    listener = priority;
21950	    priority = DEFAULT_PRIORITY$4;
21951	  }
21952
21953	  this._eventBus.on(type || KEYDOWN_EVENT, priority, listener);
21954	};
21955
21956	Keyboard.prototype.removeListener = function(listener, type) {
21957	  this._eventBus.off(type || KEYDOWN_EVENT, listener);
21958	};
21959
21960	Keyboard.prototype.hasModifier = hasModifier;
21961	Keyboard.prototype.isCmd = isCmd;
21962	Keyboard.prototype.isShift = isShift;
21963	Keyboard.prototype.isKey = isKey;
21964
21965
21966
21967	// helpers ///////
21968
21969	function isInput(target) {
21970	  return target && (matchesSelector(target, 'input, textarea') || target.contentEditable === 'true');
21971	}
21972
21973	var LOW_PRIORITY$j = 500;
21974
21975	var KEYCODE_C = 67;
21976	var KEYCODE_V = 86;
21977	var KEYCODE_Y = 89;
21978	var KEYCODE_Z = 90;
21979
21980	var KEYS_COPY = ['c', 'C', KEYCODE_C ];
21981	var KEYS_PASTE = [ 'v', 'V', KEYCODE_V ];
21982	var KEYS_REDO = [ 'y', 'Y', KEYCODE_Y ];
21983	var KEYS_UNDO = [ 'z', 'Z', KEYCODE_Z ];
21984
21985
21986	/**
21987	 * Adds default keyboard bindings.
21988	 *
21989	 * This does not pull in any features will bind only actions that
21990	 * have previously been registered against the editorActions component.
21991	 *
21992	 * @param {EventBus} eventBus
21993	 * @param {Keyboard} keyboard
21994	 */
21995	function KeyboardBindings(eventBus, keyboard) {
21996
21997	  var self = this;
21998
21999	  eventBus.on('editorActions.init', LOW_PRIORITY$j, function(event) {
22000
22001	    var editorActions = event.editorActions;
22002
22003	    self.registerBindings(keyboard, editorActions);
22004	  });
22005	}
22006
22007	KeyboardBindings.$inject = [
22008	  'eventBus',
22009	  'keyboard'
22010	];
22011
22012
22013	/**
22014	 * Register available keyboard bindings.
22015	 *
22016	 * @param {Keyboard} keyboard
22017	 * @param {EditorActions} editorActions
22018	 */
22019	KeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
22020
22021	  /**
22022	   * Add keyboard binding if respective editor action
22023	   * is registered.
22024	   *
22025	   * @param {string} action name
22026	   * @param {Function} fn that implements the key binding
22027	   */
22028	  function addListener(action, fn) {
22029
22030	    if (editorActions.isRegistered(action)) {
22031	      keyboard.addListener(fn);
22032	    }
22033	  }
22034
22035
22036	  // undo
22037	  // (CTRL|CMD) + Z
22038	  addListener('undo', function(context) {
22039
22040	    var event = context.keyEvent;
22041
22042	    if (isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event)) {
22043	      editorActions.trigger('undo');
22044
22045	      return true;
22046	    }
22047	  });
22048
22049	  // redo
22050	  // CTRL + Y
22051	  // CMD + SHIFT + Z
22052	  addListener('redo', function(context) {
22053
22054	    var event = context.keyEvent;
22055
22056	    if (isCmd(event) && (isKey(KEYS_REDO, event) || (isKey(KEYS_UNDO, event) && isShift(event)))) {
22057	      editorActions.trigger('redo');
22058
22059	      return true;
22060	    }
22061	  });
22062
22063	  // copy
22064	  // CTRL/CMD + C
22065	  addListener('copy', function(context) {
22066
22067	    var event = context.keyEvent;
22068
22069	    if (isCmd(event) && isKey(KEYS_COPY, event)) {
22070	      editorActions.trigger('copy');
22071
22072	      return true;
22073	    }
22074	  });
22075
22076	  // paste
22077	  // CTRL/CMD + V
22078	  addListener('paste', function(context) {
22079
22080	    var event = context.keyEvent;
22081
22082	    if (isCmd(event) && isKey(KEYS_PASTE, event)) {
22083	      editorActions.trigger('paste');
22084
22085	      return true;
22086	    }
22087	  });
22088
22089	  // zoom in one step
22090	  // CTRL/CMD + +
22091	  addListener('stepZoom', function(context) {
22092
22093	    var event = context.keyEvent;
22094
22095	    // quirk: it has to be triggered by `=` as well to work on international keyboard layout
22096	    // cf: https://github.com/bpmn-io/bpmn-js/issues/1362#issuecomment-722989754
22097	    if (isKey([ '+', 'Add', '=' ], event) && isCmd(event)) {
22098	      editorActions.trigger('stepZoom', { value: 1 });
22099
22100	      return true;
22101	    }
22102	  });
22103
22104	  // zoom out one step
22105	  // CTRL + -
22106	  addListener('stepZoom', function(context) {
22107
22108	    var event = context.keyEvent;
22109
22110	    if (isKey([ '-', 'Subtract' ], event) && isCmd(event)) {
22111	      editorActions.trigger('stepZoom', { value: -1 });
22112
22113	      return true;
22114	    }
22115	  });
22116
22117	  // zoom to the default level
22118	  // CTRL + 0
22119	  addListener('zoom', function(context) {
22120
22121	    var event = context.keyEvent;
22122
22123	    if (isKey('0', event) && isCmd(event)) {
22124	      editorActions.trigger('zoom', { value: 1 });
22125
22126	      return true;
22127	    }
22128	  });
22129
22130	  // delete selected element
22131	  // DEL
22132	  addListener('removeSelection', function(context) {
22133
22134	    var event = context.keyEvent;
22135
22136	    if (isKey(['Backspace', 'Delete', 'Del' ], event)) {
22137	      editorActions.trigger('removeSelection');
22138
22139	      return true;
22140	    }
22141	  });
22142	};
22143
22144	var KeyboardModule$1 = {
22145	  __init__: [ 'keyboard', 'keyboardBindings' ],
22146	  keyboard: [ 'type', Keyboard ],
22147	  keyboardBindings: [ 'type', KeyboardBindings ]
22148	};
22149
22150	var DEFAULT_CONFIG$1 = {
22151	  moveSpeed: 50,
22152	  moveSpeedAccelerated: 200
22153	};
22154
22155
22156	/**
22157	 * A feature that allows users to move the canvas using the keyboard.
22158	 *
22159	 * @param {Object} config
22160	 * @param {number} [config.moveSpeed=50]
22161	 * @param {number} [config.moveSpeedAccelerated=200]
22162	 * @param {Keyboard} keyboard
22163	 * @param {Canvas} canvas
22164	 */
22165	function KeyboardMove(
22166	    config,
22167	    keyboard,
22168	    canvas
22169	) {
22170
22171	  var self = this;
22172
22173	  this._config = assign({}, DEFAULT_CONFIG$1, config || {});
22174
22175	  keyboard.addListener(arrowsListener);
22176
22177
22178	  function arrowsListener(context) {
22179
22180	    var event = context.keyEvent,
22181	        config = self._config;
22182
22183	    if (!keyboard.isCmd(event)) {
22184	      return;
22185	    }
22186
22187	    if (keyboard.isKey([
22188	      'ArrowLeft', 'Left',
22189	      'ArrowUp', 'Up',
22190	      'ArrowDown', 'Down',
22191	      'ArrowRight', 'Right'
22192	    ], event)) {
22193
22194	      var speed = (
22195	        keyboard.isShift(event) ?
22196	          config.moveSpeedAccelerated :
22197	          config.moveSpeed
22198	      );
22199
22200	      var direction;
22201
22202	      switch (event.key) {
22203	      case 'ArrowLeft':
22204	      case 'Left':
22205	        direction = 'left';
22206	        break;
22207	      case 'ArrowUp':
22208	      case 'Up':
22209	        direction = 'up';
22210	        break;
22211	      case 'ArrowRight':
22212	      case 'Right':
22213	        direction = 'right';
22214	        break;
22215	      case 'ArrowDown':
22216	      case 'Down':
22217	        direction = 'down';
22218	        break;
22219	      }
22220
22221	      self.moveCanvas({
22222	        speed: speed,
22223	        direction: direction
22224	      });
22225
22226	      return true;
22227	    }
22228	  }
22229
22230	  this.moveCanvas = function(opts) {
22231
22232	    var dx = 0,
22233	        dy = 0,
22234	        speed = opts.speed;
22235
22236	    var actualSpeed = speed / Math.min(Math.sqrt(canvas.viewbox().scale), 1);
22237
22238	    switch (opts.direction) {
22239	    case 'left': // Left
22240	      dx = actualSpeed;
22241	      break;
22242	    case 'up': // Up
22243	      dy = actualSpeed;
22244	      break;
22245	    case 'right': // Right
22246	      dx = -actualSpeed;
22247	      break;
22248	    case 'down': // Down
22249	      dy = -actualSpeed;
22250	      break;
22251	    }
22252
22253	    canvas.scroll({
22254	      dx: dx,
22255	      dy: dy
22256	    });
22257	  };
22258
22259	}
22260
22261
22262	KeyboardMove.$inject = [
22263	  'config.keyboardMove',
22264	  'keyboard',
22265	  'canvas'
22266	];
22267
22268	var KeyboardMoveModule = {
22269	  __depends__: [
22270	    KeyboardModule$1
22271	  ],
22272	  __init__: [ 'keyboardMove' ],
22273	  keyboardMove: [ 'type', KeyboardMove ]
22274	};
22275
22276	var CURSOR_CLS_PATTERN = /^djs-cursor-.*$/;
22277
22278
22279	function set(mode) {
22280	  var classes = classes$1(document.body);
22281
22282	  classes.removeMatching(CURSOR_CLS_PATTERN);
22283
22284	  if (mode) {
22285	    classes.add('djs-cursor-' + mode);
22286	  }
22287	}
22288
22289	function unset() {
22290	  set(null);
22291	}
22292
22293	var TRAP_PRIORITY = 5000;
22294
22295	/**
22296	 * Installs a click trap that prevents a ghost click following a dragging operation.
22297	 *
22298	 * @return {Function} a function to immediately remove the installed trap.
22299	 */
22300	function install(eventBus, eventName) {
22301
22302	  eventName = eventName || 'element.click';
22303
22304	  function trap() {
22305	    return false;
22306	  }
22307
22308	  eventBus.once(eventName, TRAP_PRIORITY, trap);
22309
22310	  return function() {
22311	    eventBus.off(eventName, trap);
22312	  };
22313	}
22314
22315	function center(bounds) {
22316	  return {
22317	    x: bounds.x + (bounds.width / 2),
22318	    y: bounds.y + (bounds.height / 2)
22319	  };
22320	}
22321
22322
22323	function delta(a, b) {
22324	  return {
22325	    x: a.x - b.x,
22326	    y: a.y - b.y
22327	  };
22328	}
22329
22330	var THRESHOLD$1 = 15;
22331
22332
22333	/**
22334	 * Move the canvas via mouse.
22335	 *
22336	 * @param {EventBus} eventBus
22337	 * @param {Canvas} canvas
22338	 */
22339	function MoveCanvas(eventBus, canvas) {
22340
22341	  var context;
22342
22343
22344	  // listen for move on element mouse down;
22345	  // allow others to hook into the event before us though
22346	  // (dragging / element moving will do this)
22347	  eventBus.on('element.mousedown', 500, function(e) {
22348	    return handleStart(e.originalEvent);
22349	  });
22350
22351
22352	  function handleMove(event) {
22353
22354	    var start = context.start,
22355	        button = context.button,
22356	        position = toPoint(event),
22357	        delta$1 = delta(position, start);
22358
22359	    if (!context.dragging && length(delta$1) > THRESHOLD$1) {
22360	      context.dragging = true;
22361
22362	      if (button === 0) {
22363	        install(eventBus);
22364	      }
22365
22366	      set('grab');
22367	    }
22368
22369	    if (context.dragging) {
22370
22371	      var lastPosition = context.last || context.start;
22372
22373	      delta$1 = delta(position, lastPosition);
22374
22375	      canvas.scroll({
22376	        dx: delta$1.x,
22377	        dy: delta$1.y
22378	      });
22379
22380	      context.last = position;
22381	    }
22382
22383	    // prevent select
22384	    event.preventDefault();
22385	  }
22386
22387
22388	  function handleEnd(event) {
22389	    componentEvent.unbind(document, 'mousemove', handleMove);
22390	    componentEvent.unbind(document, 'mouseup', handleEnd);
22391
22392	    context = null;
22393
22394	    unset();
22395	  }
22396
22397	  function handleStart(event) {
22398
22399	    // event is already handled by '.djs-draggable'
22400	    if (closest(event.target, '.djs-draggable')) {
22401	      return;
22402	    }
22403
22404	    var button = event.button;
22405
22406	    // reject right mouse button or modifier key
22407	    if (button >= 2 || event.ctrlKey || event.shiftKey || event.altKey) {
22408	      return;
22409	    }
22410
22411	    context = {
22412	      button: button,
22413	      start: toPoint(event)
22414	    };
22415
22416	    componentEvent.bind(document, 'mousemove', handleMove);
22417	    componentEvent.bind(document, 'mouseup', handleEnd);
22418
22419	    // we've handled the event
22420	    return true;
22421	  }
22422
22423	  this.isActive = function() {
22424	    return !!context;
22425	  };
22426
22427	}
22428
22429
22430	MoveCanvas.$inject = [
22431	  'eventBus',
22432	  'canvas'
22433	];
22434
22435
22436
22437	// helpers ///////
22438
22439	function length(point) {
22440	  return Math.sqrt(Math.pow(point.x, 2) + Math.pow(point.y, 2));
22441	}
22442
22443	var MoveCanvasModule = {
22444	  __init__: [ 'moveCanvas' ],
22445	  moveCanvas: [ 'type', MoveCanvas ]
22446	};
22447
22448	/**
22449	 * Get the logarithm of x with base 10
22450	 * @param  {Integer} value
22451	 */
22452	function log10(x) {
22453	  return Math.log(x) / Math.log(10);
22454	}
22455
22456	/**
22457	 * Get step size for given range and number of steps.
22458	 *
22459	 * @param {Object} range
22460	 * @param {number} range.min
22461	 * @param {number} range.max
22462	 */
22463	function getStepSize(range, steps) {
22464
22465	  var minLinearRange = log10(range.min),
22466	      maxLinearRange = log10(range.max);
22467
22468	  var absoluteLinearRange = Math.abs(minLinearRange) + Math.abs(maxLinearRange);
22469
22470	  return absoluteLinearRange / steps;
22471	}
22472
22473	function cap(range, scale) {
22474	  return Math.max(range.min, Math.min(range.max, scale));
22475	}
22476
22477	var sign = Math.sign || function(n) {
22478	  return n >= 0 ? 1 : -1;
22479	};
22480
22481	var RANGE = { min: 0.2, max: 4 },
22482	    NUM_STEPS = 10;
22483
22484	var DELTA_THRESHOLD = 0.1;
22485
22486	var DEFAULT_SCALE = 0.75;
22487
22488	/**
22489	 * An implementation of zooming and scrolling within the
22490	 * {@link Canvas} via the mouse wheel.
22491	 *
22492	 * Mouse wheel zooming / scrolling may be disabled using
22493	 * the {@link toggle(enabled)} method.
22494	 *
22495	 * @param {Object} [config]
22496	 * @param {boolean} [config.enabled=true] default enabled state
22497	 * @param {number} [config.scale=.75] scroll sensivity
22498	 * @param {EventBus} eventBus
22499	 * @param {Canvas} canvas
22500	 */
22501	function ZoomScroll(config, eventBus, canvas) {
22502
22503	  config = config || {};
22504
22505	  this._enabled = false;
22506
22507	  this._canvas = canvas;
22508	  this._container = canvas._container;
22509
22510	  this._handleWheel = bind$2(this._handleWheel, this);
22511
22512	  this._totalDelta = 0;
22513	  this._scale = config.scale || DEFAULT_SCALE;
22514
22515	  var self = this;
22516
22517	  eventBus.on('canvas.init', function(e) {
22518	    self._init(config.enabled !== false);
22519	  });
22520	}
22521
22522	ZoomScroll.$inject = [
22523	  'config.zoomScroll',
22524	  'eventBus',
22525	  'canvas'
22526	];
22527
22528	ZoomScroll.prototype.scroll = function scroll(delta) {
22529	  this._canvas.scroll(delta);
22530	};
22531
22532
22533	ZoomScroll.prototype.reset = function reset() {
22534	  this._canvas.zoom('fit-viewport');
22535	};
22536
22537	/**
22538	 * Zoom depending on delta.
22539	 *
22540	 * @param {number} delta
22541	 * @param {Object} position
22542	 */
22543	ZoomScroll.prototype.zoom = function zoom(delta, position) {
22544
22545	  // zoom with half the step size of stepZoom
22546	  var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
22547
22548	  // add until threshold reached
22549	  this._totalDelta += delta;
22550
22551	  if (Math.abs(this._totalDelta) > DELTA_THRESHOLD) {
22552	    this._zoom(delta, position, stepSize);
22553
22554	    // reset
22555	    this._totalDelta = 0;
22556	  }
22557	};
22558
22559
22560	ZoomScroll.prototype._handleWheel = function handleWheel(event) {
22561
22562	  // event is already handled by '.djs-scrollable'
22563	  if (closest(event.target, '.djs-scrollable', true)) {
22564	    return;
22565	  }
22566
22567	  var element = this._container;
22568
22569	  event.preventDefault();
22570
22571	  // pinch to zoom is mapped to wheel + ctrlKey = true
22572	  // in modern browsers (!)
22573
22574	  var isZoom = event.ctrlKey;
22575
22576	  var isHorizontalScroll = event.shiftKey;
22577
22578	  var factor = -1 * this._scale,
22579	      delta;
22580
22581	  if (isZoom) {
22582	    factor *= event.deltaMode === 0 ? 0.020 : 0.32;
22583	  } else {
22584	    factor *= event.deltaMode === 0 ? 1.0 : 16.0;
22585	  }
22586
22587	  if (isZoom) {
22588	    var elementRect = element.getBoundingClientRect();
22589
22590	    var offset = {
22591	      x: event.clientX - elementRect.left,
22592	      y: event.clientY - elementRect.top
22593	    };
22594
22595	    delta = (
22596	      Math.sqrt(
22597	        Math.pow(event.deltaY, 2) +
22598	        Math.pow(event.deltaX, 2)
22599	      ) * sign(event.deltaY) * factor
22600	    );
22601
22602	    // zoom in relative to diagram {x,y} coordinates
22603	    this.zoom(delta, offset);
22604	  } else {
22605
22606	    if (isHorizontalScroll) {
22607	      delta = {
22608	        dx: factor * event.deltaY,
22609	        dy: 0
22610	      };
22611	    } else {
22612	      delta = {
22613	        dx: factor * event.deltaX,
22614	        dy: factor * event.deltaY
22615	      };
22616	    }
22617
22618	    this.scroll(delta);
22619	  }
22620	};
22621
22622	/**
22623	 * Zoom with fixed step size.
22624	 *
22625	 * @param {number} delta - Zoom delta (1 for zooming in, -1 for out).
22626	 * @param {Object} position
22627	 */
22628	ZoomScroll.prototype.stepZoom = function stepZoom(delta, position) {
22629
22630	  var stepSize = getStepSize(RANGE, NUM_STEPS);
22631
22632	  this._zoom(delta, position, stepSize);
22633	};
22634
22635
22636	/**
22637	 * Zoom in/out given a step size.
22638	 *
22639	 * @param {number} delta
22640	 * @param {Object} position
22641	 * @param {number} stepSize
22642	 */
22643	ZoomScroll.prototype._zoom = function(delta, position, stepSize) {
22644	  var canvas = this._canvas;
22645
22646	  var direction = delta > 0 ? 1 : -1;
22647
22648	  var currentLinearZoomLevel = log10(canvas.zoom());
22649
22650	  // snap to a proximate zoom step
22651	  var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
22652
22653	  // increase or decrease one zoom step in the given direction
22654	  newLinearZoomLevel += stepSize * direction;
22655
22656	  // calculate the absolute logarithmic zoom level based on the linear zoom level
22657	  // (e.g. 2 for an absolute x2 zoom)
22658	  var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
22659
22660	  canvas.zoom(cap(RANGE, newLogZoomLevel), position);
22661	};
22662
22663
22664	/**
22665	 * Toggle the zoom scroll ability via mouse wheel.
22666	 *
22667	 * @param  {boolean} [newEnabled] new enabled state
22668	 */
22669	ZoomScroll.prototype.toggle = function toggle(newEnabled) {
22670
22671	  var element = this._container;
22672	  var handleWheel = this._handleWheel;
22673
22674	  var oldEnabled = this._enabled;
22675
22676	  if (typeof newEnabled === 'undefined') {
22677	    newEnabled = !oldEnabled;
22678	  }
22679
22680	  // only react on actual changes
22681	  if (oldEnabled !== newEnabled) {
22682
22683	    // add or remove wheel listener based on
22684	    // changed enabled state
22685	    componentEvent[newEnabled ? 'bind' : 'unbind'](element, 'wheel', handleWheel, false);
22686	  }
22687
22688	  this._enabled = newEnabled;
22689
22690	  return newEnabled;
22691	};
22692
22693
22694	ZoomScroll.prototype._init = function(newEnabled) {
22695	  this.toggle(newEnabled);
22696	};
22697
22698	var ZoomScrollModule = {
22699	  __init__: [ 'zoomScroll' ],
22700	  zoomScroll: [ 'type', ZoomScroll ]
22701	};
22702
22703	/**
22704	 * A viewer that includes mouse navigation facilities
22705	 *
22706	 * @param {Object} options
22707	 */
22708	function NavigatedViewer(options) {
22709	  Viewer.call(this, options);
22710	}
22711
22712	inherits$1(NavigatedViewer, Viewer);
22713
22714
22715	NavigatedViewer.prototype._navigationModules = [
22716	  KeyboardMoveModule,
22717	  MoveCanvasModule,
22718	  ZoomScrollModule
22719	];
22720
22721	NavigatedViewer.prototype._modules = [].concat(
22722	  Viewer.prototype._modules,
22723	  NavigatedViewer.prototype._navigationModules
22724	);
22725
22726	var hammer = {exports: {}};
22727
22728	/*! Hammer.JS - v2.0.7 - 2016-04-22
22729	 * http://hammerjs.github.io/
22730	 *
22731	 * Copyright (c) 2016 Jorik Tangelder;
22732	 * Licensed under the MIT license */
22733
22734	(function (module) {
22735	(function(window, document, exportName, undefined$1) {
22736
22737	var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
22738	var TEST_ELEMENT = document.createElement('div');
22739
22740	var TYPE_FUNCTION = 'function';
22741
22742	var round = Math.round;
22743	var abs = Math.abs;
22744	var now = Date.now;
22745
22746	/**
22747	 * set a timeout with a given scope
22748	 * @param {Function} fn
22749	 * @param {Number} timeout
22750	 * @param {Object} context
22751	 * @returns {number}
22752	 */
22753	function setTimeoutContext(fn, timeout, context) {
22754	    return setTimeout(bindFn(fn, context), timeout);
22755	}
22756
22757	/**
22758	 * if the argument is an array, we want to execute the fn on each entry
22759	 * if it aint an array we don't want to do a thing.
22760	 * this is used by all the methods that accept a single and array argument.
22761	 * @param {*|Array} arg
22762	 * @param {String} fn
22763	 * @param {Object} [context]
22764	 * @returns {Boolean}
22765	 */
22766	function invokeArrayArg(arg, fn, context) {
22767	    if (Array.isArray(arg)) {
22768	        each(arg, context[fn], context);
22769	        return true;
22770	    }
22771	    return false;
22772	}
22773
22774	/**
22775	 * walk objects and arrays
22776	 * @param {Object} obj
22777	 * @param {Function} iterator
22778	 * @param {Object} context
22779	 */
22780	function each(obj, iterator, context) {
22781	    var i;
22782
22783	    if (!obj) {
22784	        return;
22785	    }
22786
22787	    if (obj.forEach) {
22788	        obj.forEach(iterator, context);
22789	    } else if (obj.length !== undefined$1) {
22790	        i = 0;
22791	        while (i < obj.length) {
22792	            iterator.call(context, obj[i], i, obj);
22793	            i++;
22794	        }
22795	    } else {
22796	        for (i in obj) {
22797	            obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
22798	        }
22799	    }
22800	}
22801
22802	/**
22803	 * wrap a method with a deprecation warning and stack trace
22804	 * @param {Function} method
22805	 * @param {String} name
22806	 * @param {String} message
22807	 * @returns {Function} A new function wrapping the supplied method.
22808	 */
22809	function deprecate(method, name, message) {
22810	    var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
22811	    return function() {
22812	        var e = new Error('get-stack-trace');
22813	        var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
22814	            .replace(/^\s+at\s+/gm, '')
22815	            .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
22816
22817	        var log = window.console && (window.console.warn || window.console.log);
22818	        if (log) {
22819	            log.call(window.console, deprecationMessage, stack);
22820	        }
22821	        return method.apply(this, arguments);
22822	    };
22823	}
22824
22825	/**
22826	 * extend object.
22827	 * means that properties in dest will be overwritten by the ones in src.
22828	 * @param {Object} target
22829	 * @param {...Object} objects_to_assign
22830	 * @returns {Object} target
22831	 */
22832	var assign;
22833	if (typeof Object.assign !== 'function') {
22834	    assign = function assign(target) {
22835	        if (target === undefined$1 || target === null) {
22836	            throw new TypeError('Cannot convert undefined or null to object');
22837	        }
22838
22839	        var output = Object(target);
22840	        for (var index = 1; index < arguments.length; index++) {
22841	            var source = arguments[index];
22842	            if (source !== undefined$1 && source !== null) {
22843	                for (var nextKey in source) {
22844	                    if (source.hasOwnProperty(nextKey)) {
22845	                        output[nextKey] = source[nextKey];
22846	                    }
22847	                }
22848	            }
22849	        }
22850	        return output;
22851	    };
22852	} else {
22853	    assign = Object.assign;
22854	}
22855
22856	/**
22857	 * extend object.
22858	 * means that properties in dest will be overwritten by the ones in src.
22859	 * @param {Object} dest
22860	 * @param {Object} src
22861	 * @param {Boolean} [merge=false]
22862	 * @returns {Object} dest
22863	 */
22864	var extend = deprecate(function extend(dest, src, merge) {
22865	    var keys = Object.keys(src);
22866	    var i = 0;
22867	    while (i < keys.length) {
22868	        if (!merge || (merge && dest[keys[i]] === undefined$1)) {
22869	            dest[keys[i]] = src[keys[i]];
22870	        }
22871	        i++;
22872	    }
22873	    return dest;
22874	}, 'extend', 'Use `assign`.');
22875
22876	/**
22877	 * merge the values from src in the dest.
22878	 * means that properties that exist in dest will not be overwritten by src
22879	 * @param {Object} dest
22880	 * @param {Object} src
22881	 * @returns {Object} dest
22882	 */
22883	var merge = deprecate(function merge(dest, src) {
22884	    return extend(dest, src, true);
22885	}, 'merge', 'Use `assign`.');
22886
22887	/**
22888	 * simple class inheritance
22889	 * @param {Function} child
22890	 * @param {Function} base
22891	 * @param {Object} [properties]
22892	 */
22893	function inherit(child, base, properties) {
22894	    var baseP = base.prototype,
22895	        childP;
22896
22897	    childP = child.prototype = Object.create(baseP);
22898	    childP.constructor = child;
22899	    childP._super = baseP;
22900
22901	    if (properties) {
22902	        assign(childP, properties);
22903	    }
22904	}
22905
22906	/**
22907	 * simple function bind
22908	 * @param {Function} fn
22909	 * @param {Object} context
22910	 * @returns {Function}
22911	 */
22912	function bindFn(fn, context) {
22913	    return function boundFn() {
22914	        return fn.apply(context, arguments);
22915	    };
22916	}
22917
22918	/**
22919	 * let a boolean value also be a function that must return a boolean
22920	 * this first item in args will be used as the context
22921	 * @param {Boolean|Function} val
22922	 * @param {Array} [args]
22923	 * @returns {Boolean}
22924	 */
22925	function boolOrFn(val, args) {
22926	    if (typeof val == TYPE_FUNCTION) {
22927	        return val.apply(args ? args[0] || undefined$1 : undefined$1, args);
22928	    }
22929	    return val;
22930	}
22931
22932	/**
22933	 * use the val2 when val1 is undefined
22934	 * @param {*} val1
22935	 * @param {*} val2
22936	 * @returns {*}
22937	 */
22938	function ifUndefined(val1, val2) {
22939	    return (val1 === undefined$1) ? val2 : val1;
22940	}
22941
22942	/**
22943	 * addEventListener with multiple events at once
22944	 * @param {EventTarget} target
22945	 * @param {String} types
22946	 * @param {Function} handler
22947	 */
22948	function addEventListeners(target, types, handler) {
22949	    each(splitStr(types), function(type) {
22950	        target.addEventListener(type, handler, false);
22951	    });
22952	}
22953
22954	/**
22955	 * removeEventListener with multiple events at once
22956	 * @param {EventTarget} target
22957	 * @param {String} types
22958	 * @param {Function} handler
22959	 */
22960	function removeEventListeners(target, types, handler) {
22961	    each(splitStr(types), function(type) {
22962	        target.removeEventListener(type, handler, false);
22963	    });
22964	}
22965
22966	/**
22967	 * find if a node is in the given parent
22968	 * @method hasParent
22969	 * @param {HTMLElement} node
22970	 * @param {HTMLElement} parent
22971	 * @return {Boolean} found
22972	 */
22973	function hasParent(node, parent) {
22974	    while (node) {
22975	        if (node == parent) {
22976	            return true;
22977	        }
22978	        node = node.parentNode;
22979	    }
22980	    return false;
22981	}
22982
22983	/**
22984	 * small indexOf wrapper
22985	 * @param {String} str
22986	 * @param {String} find
22987	 * @returns {Boolean} found
22988	 */
22989	function inStr(str, find) {
22990	    return str.indexOf(find) > -1;
22991	}
22992
22993	/**
22994	 * split string on whitespace
22995	 * @param {String} str
22996	 * @returns {Array} words
22997	 */
22998	function splitStr(str) {
22999	    return str.trim().split(/\s+/g);
23000	}
23001
23002	/**
23003	 * find if a array contains the object using indexOf or a simple polyFill
23004	 * @param {Array} src
23005	 * @param {String} find
23006	 * @param {String} [findByKey]
23007	 * @return {Boolean|Number} false when not found, or the index
23008	 */
23009	function inArray(src, find, findByKey) {
23010	    if (src.indexOf && !findByKey) {
23011	        return src.indexOf(find);
23012	    } else {
23013	        var i = 0;
23014	        while (i < src.length) {
23015	            if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
23016	                return i;
23017	            }
23018	            i++;
23019	        }
23020	        return -1;
23021	    }
23022	}
23023
23024	/**
23025	 * convert array-like objects to real arrays
23026	 * @param {Object} obj
23027	 * @returns {Array}
23028	 */
23029	function toArray(obj) {
23030	    return Array.prototype.slice.call(obj, 0);
23031	}
23032
23033	/**
23034	 * unique array with objects based on a key (like 'id') or just by the array's value
23035	 * @param {Array} src [{id:1},{id:2},{id:1}]
23036	 * @param {String} [key]
23037	 * @param {Boolean} [sort=False]
23038	 * @returns {Array} [{id:1},{id:2}]
23039	 */
23040	function uniqueArray(src, key, sort) {
23041	    var results = [];
23042	    var values = [];
23043	    var i = 0;
23044
23045	    while (i < src.length) {
23046	        var val = key ? src[i][key] : src[i];
23047	        if (inArray(values, val) < 0) {
23048	            results.push(src[i]);
23049	        }
23050	        values[i] = val;
23051	        i++;
23052	    }
23053
23054	    if (sort) {
23055	        if (!key) {
23056	            results = results.sort();
23057	        } else {
23058	            results = results.sort(function sortUniqueArray(a, b) {
23059	                return a[key] > b[key];
23060	            });
23061	        }
23062	    }
23063
23064	    return results;
23065	}
23066
23067	/**
23068	 * get the prefixed property
23069	 * @param {Object} obj
23070	 * @param {String} property
23071	 * @returns {String|Undefined} prefixed
23072	 */
23073	function prefixed(obj, property) {
23074	    var prefix, prop;
23075	    var camelProp = property[0].toUpperCase() + property.slice(1);
23076
23077	    var i = 0;
23078	    while (i < VENDOR_PREFIXES.length) {
23079	        prefix = VENDOR_PREFIXES[i];
23080	        prop = (prefix) ? prefix + camelProp : property;
23081
23082	        if (prop in obj) {
23083	            return prop;
23084	        }
23085	        i++;
23086	    }
23087	    return undefined$1;
23088	}
23089
23090	/**
23091	 * get a unique id
23092	 * @returns {number} uniqueId
23093	 */
23094	var _uniqueId = 1;
23095	function uniqueId() {
23096	    return _uniqueId++;
23097	}
23098
23099	/**
23100	 * get the window object of an element
23101	 * @param {HTMLElement} element
23102	 * @returns {DocumentView|Window}
23103	 */
23104	function getWindowForElement(element) {
23105	    var doc = element.ownerDocument || element;
23106	    return (doc.defaultView || doc.parentWindow || window);
23107	}
23108
23109	var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
23110
23111	var SUPPORT_TOUCH = ('ontouchstart' in window);
23112	var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined$1;
23113	var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
23114
23115	var INPUT_TYPE_TOUCH = 'touch';
23116	var INPUT_TYPE_PEN = 'pen';
23117	var INPUT_TYPE_MOUSE = 'mouse';
23118	var INPUT_TYPE_KINECT = 'kinect';
23119
23120	var COMPUTE_INTERVAL = 25;
23121
23122	var INPUT_START = 1;
23123	var INPUT_MOVE = 2;
23124	var INPUT_END = 4;
23125	var INPUT_CANCEL = 8;
23126
23127	var DIRECTION_NONE = 1;
23128	var DIRECTION_LEFT = 2;
23129	var DIRECTION_RIGHT = 4;
23130	var DIRECTION_UP = 8;
23131	var DIRECTION_DOWN = 16;
23132
23133	var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
23134	var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
23135	var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
23136
23137	var PROPS_XY = ['x', 'y'];
23138	var PROPS_CLIENT_XY = ['clientX', 'clientY'];
23139
23140	/**
23141	 * create new input type manager
23142	 * @param {Manager} manager
23143	 * @param {Function} callback
23144	 * @returns {Input}
23145	 * @constructor
23146	 */
23147	function Input(manager, callback) {
23148	    var self = this;
23149	    this.manager = manager;
23150	    this.callback = callback;
23151	    this.element = manager.element;
23152	    this.target = manager.options.inputTarget;
23153
23154	    // smaller wrapper around the handler, for the scope and the enabled state of the manager,
23155	    // so when disabled the input events are completely bypassed.
23156	    this.domHandler = function(ev) {
23157	        if (boolOrFn(manager.options.enable, [manager])) {
23158	            self.handler(ev);
23159	        }
23160	    };
23161
23162	    this.init();
23163
23164	}
23165
23166	Input.prototype = {
23167	    /**
23168	     * should handle the inputEvent data and trigger the callback
23169	     * @virtual
23170	     */
23171	    handler: function() { },
23172
23173	    /**
23174	     * bind the events
23175	     */
23176	    init: function() {
23177	        this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
23178	        this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
23179	        this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
23180	    },
23181
23182	    /**
23183	     * unbind the events
23184	     */
23185	    destroy: function() {
23186	        this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
23187	        this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
23188	        this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
23189	    }
23190	};
23191
23192	/**
23193	 * create new input type manager
23194	 * called by the Manager constructor
23195	 * @param {Hammer} manager
23196	 * @returns {Input}
23197	 */
23198	function createInputInstance(manager) {
23199	    var Type;
23200	    var inputClass = manager.options.inputClass;
23201
23202	    if (inputClass) {
23203	        Type = inputClass;
23204	    } else if (SUPPORT_POINTER_EVENTS) {
23205	        Type = PointerEventInput;
23206	    } else if (SUPPORT_ONLY_TOUCH) {
23207	        Type = TouchInput;
23208	    } else if (!SUPPORT_TOUCH) {
23209	        Type = MouseInput;
23210	    } else {
23211	        Type = TouchMouseInput;
23212	    }
23213	    return new (Type)(manager, inputHandler);
23214	}
23215
23216	/**
23217	 * handle input events
23218	 * @param {Manager} manager
23219	 * @param {String} eventType
23220	 * @param {Object} input
23221	 */
23222	function inputHandler(manager, eventType, input) {
23223	    var pointersLen = input.pointers.length;
23224	    var changedPointersLen = input.changedPointers.length;
23225	    var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
23226	    var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
23227
23228	    input.isFirst = !!isFirst;
23229	    input.isFinal = !!isFinal;
23230
23231	    if (isFirst) {
23232	        manager.session = {};
23233	    }
23234
23235	    // source event is the normalized value of the domEvents
23236	    // like 'touchstart, mouseup, pointerdown'
23237	    input.eventType = eventType;
23238
23239	    // compute scale, rotation etc
23240	    computeInputData(manager, input);
23241
23242	    // emit secret event
23243	    manager.emit('hammer.input', input);
23244
23245	    manager.recognize(input);
23246	    manager.session.prevInput = input;
23247	}
23248
23249	/**
23250	 * extend the data with some usable properties like scale, rotate, velocity etc
23251	 * @param {Object} manager
23252	 * @param {Object} input
23253	 */
23254	function computeInputData(manager, input) {
23255	    var session = manager.session;
23256	    var pointers = input.pointers;
23257	    var pointersLength = pointers.length;
23258
23259	    // store the first input to calculate the distance and direction
23260	    if (!session.firstInput) {
23261	        session.firstInput = simpleCloneInputData(input);
23262	    }
23263
23264	    // to compute scale and rotation we need to store the multiple touches
23265	    if (pointersLength > 1 && !session.firstMultiple) {
23266	        session.firstMultiple = simpleCloneInputData(input);
23267	    } else if (pointersLength === 1) {
23268	        session.firstMultiple = false;
23269	    }
23270
23271	    var firstInput = session.firstInput;
23272	    var firstMultiple = session.firstMultiple;
23273	    var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
23274
23275	    var center = input.center = getCenter(pointers);
23276	    input.timeStamp = now();
23277	    input.deltaTime = input.timeStamp - firstInput.timeStamp;
23278
23279	    input.angle = getAngle(offsetCenter, center);
23280	    input.distance = getDistance(offsetCenter, center);
23281
23282	    computeDeltaXY(session, input);
23283	    input.offsetDirection = getDirection(input.deltaX, input.deltaY);
23284
23285	    var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
23286	    input.overallVelocityX = overallVelocity.x;
23287	    input.overallVelocityY = overallVelocity.y;
23288	    input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
23289
23290	    input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
23291	    input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
23292
23293	    input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
23294	        session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
23295
23296	    computeIntervalInputData(session, input);
23297
23298	    // find the correct target
23299	    var target = manager.element;
23300	    if (hasParent(input.srcEvent.target, target)) {
23301	        target = input.srcEvent.target;
23302	    }
23303	    input.target = target;
23304	}
23305
23306	function computeDeltaXY(session, input) {
23307	    var center = input.center;
23308	    var offset = session.offsetDelta || {};
23309	    var prevDelta = session.prevDelta || {};
23310	    var prevInput = session.prevInput || {};
23311
23312	    if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
23313	        prevDelta = session.prevDelta = {
23314	            x: prevInput.deltaX || 0,
23315	            y: prevInput.deltaY || 0
23316	        };
23317
23318	        offset = session.offsetDelta = {
23319	            x: center.x,
23320	            y: center.y
23321	        };
23322	    }
23323
23324	    input.deltaX = prevDelta.x + (center.x - offset.x);
23325	    input.deltaY = prevDelta.y + (center.y - offset.y);
23326	}
23327
23328	/**
23329	 * velocity is calculated every x ms
23330	 * @param {Object} session
23331	 * @param {Object} input
23332	 */
23333	function computeIntervalInputData(session, input) {
23334	    var last = session.lastInterval || input,
23335	        deltaTime = input.timeStamp - last.timeStamp,
23336	        velocity, velocityX, velocityY, direction;
23337
23338	    if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined$1)) {
23339	        var deltaX = input.deltaX - last.deltaX;
23340	        var deltaY = input.deltaY - last.deltaY;
23341
23342	        var v = getVelocity(deltaTime, deltaX, deltaY);
23343	        velocityX = v.x;
23344	        velocityY = v.y;
23345	        velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
23346	        direction = getDirection(deltaX, deltaY);
23347
23348	        session.lastInterval = input;
23349	    } else {
23350	        // use latest velocity info if it doesn't overtake a minimum period
23351	        velocity = last.velocity;
23352	        velocityX = last.velocityX;
23353	        velocityY = last.velocityY;
23354	        direction = last.direction;
23355	    }
23356
23357	    input.velocity = velocity;
23358	    input.velocityX = velocityX;
23359	    input.velocityY = velocityY;
23360	    input.direction = direction;
23361	}
23362
23363	/**
23364	 * create a simple clone from the input used for storage of firstInput and firstMultiple
23365	 * @param {Object} input
23366	 * @returns {Object} clonedInputData
23367	 */
23368	function simpleCloneInputData(input) {
23369	    // make a simple copy of the pointers because we will get a reference if we don't
23370	    // we only need clientXY for the calculations
23371	    var pointers = [];
23372	    var i = 0;
23373	    while (i < input.pointers.length) {
23374	        pointers[i] = {
23375	            clientX: round(input.pointers[i].clientX),
23376	            clientY: round(input.pointers[i].clientY)
23377	        };
23378	        i++;
23379	    }
23380
23381	    return {
23382	        timeStamp: now(),
23383	        pointers: pointers,
23384	        center: getCenter(pointers),
23385	        deltaX: input.deltaX,
23386	        deltaY: input.deltaY
23387	    };
23388	}
23389
23390	/**
23391	 * get the center of all the pointers
23392	 * @param {Array} pointers
23393	 * @return {Object} center contains `x` and `y` properties
23394	 */
23395	function getCenter(pointers) {
23396	    var pointersLength = pointers.length;
23397
23398	    // no need to loop when only one touch
23399	    if (pointersLength === 1) {
23400	        return {
23401	            x: round(pointers[0].clientX),
23402	            y: round(pointers[0].clientY)
23403	        };
23404	    }
23405
23406	    var x = 0, y = 0, i = 0;
23407	    while (i < pointersLength) {
23408	        x += pointers[i].clientX;
23409	        y += pointers[i].clientY;
23410	        i++;
23411	    }
23412
23413	    return {
23414	        x: round(x / pointersLength),
23415	        y: round(y / pointersLength)
23416	    };
23417	}
23418
23419	/**
23420	 * calculate the velocity between two points. unit is in px per ms.
23421	 * @param {Number} deltaTime
23422	 * @param {Number} x
23423	 * @param {Number} y
23424	 * @return {Object} velocity `x` and `y`
23425	 */
23426	function getVelocity(deltaTime, x, y) {
23427	    return {
23428	        x: x / deltaTime || 0,
23429	        y: y / deltaTime || 0
23430	    };
23431	}
23432
23433	/**
23434	 * get the direction between two points
23435	 * @param {Number} x
23436	 * @param {Number} y
23437	 * @return {Number} direction
23438	 */
23439	function getDirection(x, y) {
23440	    if (x === y) {
23441	        return DIRECTION_NONE;
23442	    }
23443
23444	    if (abs(x) >= abs(y)) {
23445	        return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
23446	    }
23447	    return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
23448	}
23449
23450	/**
23451	 * calculate the absolute distance between two points
23452	 * @param {Object} p1 {x, y}
23453	 * @param {Object} p2 {x, y}
23454	 * @param {Array} [props] containing x and y keys
23455	 * @return {Number} distance
23456	 */
23457	function getDistance(p1, p2, props) {
23458	    if (!props) {
23459	        props = PROPS_XY;
23460	    }
23461	    var x = p2[props[0]] - p1[props[0]],
23462	        y = p2[props[1]] - p1[props[1]];
23463
23464	    return Math.sqrt((x * x) + (y * y));
23465	}
23466
23467	/**
23468	 * calculate the angle between two coordinates
23469	 * @param {Object} p1
23470	 * @param {Object} p2
23471	 * @param {Array} [props] containing x and y keys
23472	 * @return {Number} angle
23473	 */
23474	function getAngle(p1, p2, props) {
23475	    if (!props) {
23476	        props = PROPS_XY;
23477	    }
23478	    var x = p2[props[0]] - p1[props[0]],
23479	        y = p2[props[1]] - p1[props[1]];
23480	    return Math.atan2(y, x) * 180 / Math.PI;
23481	}
23482
23483	/**
23484	 * calculate the rotation degrees between two pointersets
23485	 * @param {Array} start array of pointers
23486	 * @param {Array} end array of pointers
23487	 * @return {Number} rotation
23488	 */
23489	function getRotation(start, end) {
23490	    return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
23491	}
23492
23493	/**
23494	 * calculate the scale factor between two pointersets
23495	 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
23496	 * @param {Array} start array of pointers
23497	 * @param {Array} end array of pointers
23498	 * @return {Number} scale
23499	 */
23500	function getScale(start, end) {
23501	    return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
23502	}
23503
23504	var MOUSE_INPUT_MAP = {
23505	    mousedown: INPUT_START,
23506	    mousemove: INPUT_MOVE,
23507	    mouseup: INPUT_END
23508	};
23509
23510	var MOUSE_ELEMENT_EVENTS = 'mousedown';
23511	var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
23512
23513	/**
23514	 * Mouse events input
23515	 * @constructor
23516	 * @extends Input
23517	 */
23518	function MouseInput() {
23519	    this.evEl = MOUSE_ELEMENT_EVENTS;
23520	    this.evWin = MOUSE_WINDOW_EVENTS;
23521
23522	    this.pressed = false; // mousedown state
23523
23524	    Input.apply(this, arguments);
23525	}
23526
23527	inherit(MouseInput, Input, {
23528	    /**
23529	     * handle mouse events
23530	     * @param {Object} ev
23531	     */
23532	    handler: function MEhandler(ev) {
23533	        var eventType = MOUSE_INPUT_MAP[ev.type];
23534
23535	        // on start we want to have the left mouse button down
23536	        if (eventType & INPUT_START && ev.button === 0) {
23537	            this.pressed = true;
23538	        }
23539
23540	        if (eventType & INPUT_MOVE && ev.which !== 1) {
23541	            eventType = INPUT_END;
23542	        }
23543
23544	        // mouse must be down
23545	        if (!this.pressed) {
23546	            return;
23547	        }
23548
23549	        if (eventType & INPUT_END) {
23550	            this.pressed = false;
23551	        }
23552
23553	        this.callback(this.manager, eventType, {
23554	            pointers: [ev],
23555	            changedPointers: [ev],
23556	            pointerType: INPUT_TYPE_MOUSE,
23557	            srcEvent: ev
23558	        });
23559	    }
23560	});
23561
23562	var POINTER_INPUT_MAP = {
23563	    pointerdown: INPUT_START,
23564	    pointermove: INPUT_MOVE,
23565	    pointerup: INPUT_END,
23566	    pointercancel: INPUT_CANCEL,
23567	    pointerout: INPUT_CANCEL
23568	};
23569
23570	// in IE10 the pointer types is defined as an enum
23571	var IE10_POINTER_TYPE_ENUM = {
23572	    2: INPUT_TYPE_TOUCH,
23573	    3: INPUT_TYPE_PEN,
23574	    4: INPUT_TYPE_MOUSE,
23575	    5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
23576	};
23577
23578	var POINTER_ELEMENT_EVENTS = 'pointerdown';
23579	var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
23580
23581	// IE10 has prefixed support, and case-sensitive
23582	if (window.MSPointerEvent && !window.PointerEvent) {
23583	    POINTER_ELEMENT_EVENTS = 'MSPointerDown';
23584	    POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
23585	}
23586
23587	/**
23588	 * Pointer events input
23589	 * @constructor
23590	 * @extends Input
23591	 */
23592	function PointerEventInput() {
23593	    this.evEl = POINTER_ELEMENT_EVENTS;
23594	    this.evWin = POINTER_WINDOW_EVENTS;
23595
23596	    Input.apply(this, arguments);
23597
23598	    this.store = (this.manager.session.pointerEvents = []);
23599	}
23600
23601	inherit(PointerEventInput, Input, {
23602	    /**
23603	     * handle mouse events
23604	     * @param {Object} ev
23605	     */
23606	    handler: function PEhandler(ev) {
23607	        var store = this.store;
23608	        var removePointer = false;
23609
23610	        var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
23611	        var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
23612	        var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
23613
23614	        var isTouch = (pointerType == INPUT_TYPE_TOUCH);
23615
23616	        // get index of the event in the store
23617	        var storeIndex = inArray(store, ev.pointerId, 'pointerId');
23618
23619	        // start and mouse must be down
23620	        if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
23621	            if (storeIndex < 0) {
23622	                store.push(ev);
23623	                storeIndex = store.length - 1;
23624	            }
23625	        } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
23626	            removePointer = true;
23627	        }
23628
23629	        // it not found, so the pointer hasn't been down (so it's probably a hover)
23630	        if (storeIndex < 0) {
23631	            return;
23632	        }
23633
23634	        // update the event in the store
23635	        store[storeIndex] = ev;
23636
23637	        this.callback(this.manager, eventType, {
23638	            pointers: store,
23639	            changedPointers: [ev],
23640	            pointerType: pointerType,
23641	            srcEvent: ev
23642	        });
23643
23644	        if (removePointer) {
23645	            // remove from the store
23646	            store.splice(storeIndex, 1);
23647	        }
23648	    }
23649	});
23650
23651	var SINGLE_TOUCH_INPUT_MAP = {
23652	    touchstart: INPUT_START,
23653	    touchmove: INPUT_MOVE,
23654	    touchend: INPUT_END,
23655	    touchcancel: INPUT_CANCEL
23656	};
23657
23658	var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
23659	var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
23660
23661	/**
23662	 * Touch events input
23663	 * @constructor
23664	 * @extends Input
23665	 */
23666	function SingleTouchInput() {
23667	    this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
23668	    this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
23669	    this.started = false;
23670
23671	    Input.apply(this, arguments);
23672	}
23673
23674	inherit(SingleTouchInput, Input, {
23675	    handler: function TEhandler(ev) {
23676	        var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
23677
23678	        // should we handle the touch events?
23679	        if (type === INPUT_START) {
23680	            this.started = true;
23681	        }
23682
23683	        if (!this.started) {
23684	            return;
23685	        }
23686
23687	        var touches = normalizeSingleTouches.call(this, ev, type);
23688
23689	        // when done, reset the started state
23690	        if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
23691	            this.started = false;
23692	        }
23693
23694	        this.callback(this.manager, type, {
23695	            pointers: touches[0],
23696	            changedPointers: touches[1],
23697	            pointerType: INPUT_TYPE_TOUCH,
23698	            srcEvent: ev
23699	        });
23700	    }
23701	});
23702
23703	/**
23704	 * @this {TouchInput}
23705	 * @param {Object} ev
23706	 * @param {Number} type flag
23707	 * @returns {undefined|Array} [all, changed]
23708	 */
23709	function normalizeSingleTouches(ev, type) {
23710	    var all = toArray(ev.touches);
23711	    var changed = toArray(ev.changedTouches);
23712
23713	    if (type & (INPUT_END | INPUT_CANCEL)) {
23714	        all = uniqueArray(all.concat(changed), 'identifier', true);
23715	    }
23716
23717	    return [all, changed];
23718	}
23719
23720	var TOUCH_INPUT_MAP = {
23721	    touchstart: INPUT_START,
23722	    touchmove: INPUT_MOVE,
23723	    touchend: INPUT_END,
23724	    touchcancel: INPUT_CANCEL
23725	};
23726
23727	var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
23728
23729	/**
23730	 * Multi-user touch events input
23731	 * @constructor
23732	 * @extends Input
23733	 */
23734	function TouchInput() {
23735	    this.evTarget = TOUCH_TARGET_EVENTS;
23736	    this.targetIds = {};
23737
23738	    Input.apply(this, arguments);
23739	}
23740
23741	inherit(TouchInput, Input, {
23742	    handler: function MTEhandler(ev) {
23743	        var type = TOUCH_INPUT_MAP[ev.type];
23744	        var touches = getTouches.call(this, ev, type);
23745	        if (!touches) {
23746	            return;
23747	        }
23748
23749	        this.callback(this.manager, type, {
23750	            pointers: touches[0],
23751	            changedPointers: touches[1],
23752	            pointerType: INPUT_TYPE_TOUCH,
23753	            srcEvent: ev
23754	        });
23755	    }
23756	});
23757
23758	/**
23759	 * @this {TouchInput}
23760	 * @param {Object} ev
23761	 * @param {Number} type flag
23762	 * @returns {undefined|Array} [all, changed]
23763	 */
23764	function getTouches(ev, type) {
23765	    var allTouches = toArray(ev.touches);
23766	    var targetIds = this.targetIds;
23767
23768	    // when there is only one touch, the process can be simplified
23769	    if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
23770	        targetIds[allTouches[0].identifier] = true;
23771	        return [allTouches, allTouches];
23772	    }
23773
23774	    var i,
23775	        targetTouches,
23776	        changedTouches = toArray(ev.changedTouches),
23777	        changedTargetTouches = [],
23778	        target = this.target;
23779
23780	    // get target touches from touches
23781	    targetTouches = allTouches.filter(function(touch) {
23782	        return hasParent(touch.target, target);
23783	    });
23784
23785	    // collect touches
23786	    if (type === INPUT_START) {
23787	        i = 0;
23788	        while (i < targetTouches.length) {
23789	            targetIds[targetTouches[i].identifier] = true;
23790	            i++;
23791	        }
23792	    }
23793
23794	    // filter changed touches to only contain touches that exist in the collected target ids
23795	    i = 0;
23796	    while (i < changedTouches.length) {
23797	        if (targetIds[changedTouches[i].identifier]) {
23798	            changedTargetTouches.push(changedTouches[i]);
23799	        }
23800
23801	        // cleanup removed touches
23802	        if (type & (INPUT_END | INPUT_CANCEL)) {
23803	            delete targetIds[changedTouches[i].identifier];
23804	        }
23805	        i++;
23806	    }
23807
23808	    if (!changedTargetTouches.length) {
23809	        return;
23810	    }
23811
23812	    return [
23813	        // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
23814	        uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
23815	        changedTargetTouches
23816	    ];
23817	}
23818
23819	/**
23820	 * Combined touch and mouse input
23821	 *
23822	 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
23823	 * This because touch devices also emit mouse events while doing a touch.
23824	 *
23825	 * @constructor
23826	 * @extends Input
23827	 */
23828
23829	var DEDUP_TIMEOUT = 2500;
23830	var DEDUP_DISTANCE = 25;
23831
23832	function TouchMouseInput() {
23833	    Input.apply(this, arguments);
23834
23835	    var handler = bindFn(this.handler, this);
23836	    this.touch = new TouchInput(this.manager, handler);
23837	    this.mouse = new MouseInput(this.manager, handler);
23838
23839	    this.primaryTouch = null;
23840	    this.lastTouches = [];
23841	}
23842
23843	inherit(TouchMouseInput, Input, {
23844	    /**
23845	     * handle mouse and touch events
23846	     * @param {Hammer} manager
23847	     * @param {String} inputEvent
23848	     * @param {Object} inputData
23849	     */
23850	    handler: function TMEhandler(manager, inputEvent, inputData) {
23851	        var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
23852	            isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
23853
23854	        if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
23855	            return;
23856	        }
23857
23858	        // when we're in a touch event, record touches to  de-dupe synthetic mouse event
23859	        if (isTouch) {
23860	            recordTouches.call(this, inputEvent, inputData);
23861	        } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
23862	            return;
23863	        }
23864
23865	        this.callback(manager, inputEvent, inputData);
23866	    },
23867
23868	    /**
23869	     * remove the event listeners
23870	     */
23871	    destroy: function destroy() {
23872	        this.touch.destroy();
23873	        this.mouse.destroy();
23874	    }
23875	});
23876
23877	function recordTouches(eventType, eventData) {
23878	    if (eventType & INPUT_START) {
23879	        this.primaryTouch = eventData.changedPointers[0].identifier;
23880	        setLastTouch.call(this, eventData);
23881	    } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
23882	        setLastTouch.call(this, eventData);
23883	    }
23884	}
23885
23886	function setLastTouch(eventData) {
23887	    var touch = eventData.changedPointers[0];
23888
23889	    if (touch.identifier === this.primaryTouch) {
23890	        var lastTouch = {x: touch.clientX, y: touch.clientY};
23891	        this.lastTouches.push(lastTouch);
23892	        var lts = this.lastTouches;
23893	        var removeLastTouch = function() {
23894	            var i = lts.indexOf(lastTouch);
23895	            if (i > -1) {
23896	                lts.splice(i, 1);
23897	            }
23898	        };
23899	        setTimeout(removeLastTouch, DEDUP_TIMEOUT);
23900	    }
23901	}
23902
23903	function isSyntheticEvent(eventData) {
23904	    var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
23905	    for (var i = 0; i < this.lastTouches.length; i++) {
23906	        var t = this.lastTouches[i];
23907	        var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
23908	        if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
23909	            return true;
23910	        }
23911	    }
23912	    return false;
23913	}
23914
23915	var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
23916	var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined$1;
23917
23918	// magical touchAction value
23919	var TOUCH_ACTION_COMPUTE = 'compute';
23920	var TOUCH_ACTION_AUTO = 'auto';
23921	var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
23922	var TOUCH_ACTION_NONE = 'none';
23923	var TOUCH_ACTION_PAN_X = 'pan-x';
23924	var TOUCH_ACTION_PAN_Y = 'pan-y';
23925	var TOUCH_ACTION_MAP = getTouchActionProps();
23926
23927	/**
23928	 * Touch Action
23929	 * sets the touchAction property or uses the js alternative
23930	 * @param {Manager} manager
23931	 * @param {String} value
23932	 * @constructor
23933	 */
23934	function TouchAction(manager, value) {
23935	    this.manager = manager;
23936	    this.set(value);
23937	}
23938
23939	TouchAction.prototype = {
23940	    /**
23941	     * set the touchAction value on the element or enable the polyfill
23942	     * @param {String} value
23943	     */
23944	    set: function(value) {
23945	        // find out the touch-action by the event handlers
23946	        if (value == TOUCH_ACTION_COMPUTE) {
23947	            value = this.compute();
23948	        }
23949
23950	        if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
23951	            this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
23952	        }
23953	        this.actions = value.toLowerCase().trim();
23954	    },
23955
23956	    /**
23957	     * just re-set the touchAction value
23958	     */
23959	    update: function() {
23960	        this.set(this.manager.options.touchAction);
23961	    },
23962
23963	    /**
23964	     * compute the value for the touchAction property based on the recognizer's settings
23965	     * @returns {String} value
23966	     */
23967	    compute: function() {
23968	        var actions = [];
23969	        each(this.manager.recognizers, function(recognizer) {
23970	            if (boolOrFn(recognizer.options.enable, [recognizer])) {
23971	                actions = actions.concat(recognizer.getTouchAction());
23972	            }
23973	        });
23974	        return cleanTouchActions(actions.join(' '));
23975	    },
23976
23977	    /**
23978	     * this method is called on each input cycle and provides the preventing of the browser behavior
23979	     * @param {Object} input
23980	     */
23981	    preventDefaults: function(input) {
23982	        var srcEvent = input.srcEvent;
23983	        var direction = input.offsetDirection;
23984
23985	        // if the touch action did prevented once this session
23986	        if (this.manager.session.prevented) {
23987	            srcEvent.preventDefault();
23988	            return;
23989	        }
23990
23991	        var actions = this.actions;
23992	        var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
23993	        var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
23994	        var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
23995
23996	        if (hasNone) {
23997	            //do not prevent defaults if this is a tap gesture
23998
23999	            var isTapPointer = input.pointers.length === 1;
24000	            var isTapMovement = input.distance < 2;
24001	            var isTapTouchTime = input.deltaTime < 250;
24002
24003	            if (isTapPointer && isTapMovement && isTapTouchTime) {
24004	                return;
24005	            }
24006	        }
24007
24008	        if (hasPanX && hasPanY) {
24009	            // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
24010	            return;
24011	        }
24012
24013	        if (hasNone ||
24014	            (hasPanY && direction & DIRECTION_HORIZONTAL) ||
24015	            (hasPanX && direction & DIRECTION_VERTICAL)) {
24016	            return this.preventSrc(srcEvent);
24017	        }
24018	    },
24019
24020	    /**
24021	     * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
24022	     * @param {Object} srcEvent
24023	     */
24024	    preventSrc: function(srcEvent) {
24025	        this.manager.session.prevented = true;
24026	        srcEvent.preventDefault();
24027	    }
24028	};
24029
24030	/**
24031	 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
24032	 * @param {String} actions
24033	 * @returns {*}
24034	 */
24035	function cleanTouchActions(actions) {
24036	    // none
24037	    if (inStr(actions, TOUCH_ACTION_NONE)) {
24038	        return TOUCH_ACTION_NONE;
24039	    }
24040
24041	    var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
24042	    var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
24043
24044	    // if both pan-x and pan-y are set (different recognizers
24045	    // for different directions, e.g. horizontal pan but vertical swipe?)
24046	    // we need none (as otherwise with pan-x pan-y combined none of these
24047	    // recognizers will work, since the browser would handle all panning
24048	    if (hasPanX && hasPanY) {
24049	        return TOUCH_ACTION_NONE;
24050	    }
24051
24052	    // pan-x OR pan-y
24053	    if (hasPanX || hasPanY) {
24054	        return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
24055	    }
24056
24057	    // manipulation
24058	    if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
24059	        return TOUCH_ACTION_MANIPULATION;
24060	    }
24061
24062	    return TOUCH_ACTION_AUTO;
24063	}
24064
24065	function getTouchActionProps() {
24066	    if (!NATIVE_TOUCH_ACTION) {
24067	        return false;
24068	    }
24069	    var touchMap = {};
24070	    var cssSupports = window.CSS && window.CSS.supports;
24071	    ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
24072
24073	        // If css.supports is not supported but there is native touch-action assume it supports
24074	        // all values. This is the case for IE 10 and 11.
24075	        touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
24076	    });
24077	    return touchMap;
24078	}
24079
24080	/**
24081	 * Recognizer flow explained; *
24082	 * All recognizers have the initial state of POSSIBLE when a input session starts.
24083	 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
24084	 * Example session for mouse-input: mousedown -> mousemove -> mouseup
24085	 *
24086	 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
24087	 * which determines with state it should be.
24088	 *
24089	 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
24090	 * POSSIBLE to give it another change on the next cycle.
24091	 *
24092	 *               Possible
24093	 *                  |
24094	 *            +-----+---------------+
24095	 *            |                     |
24096	 *      +-----+-----+               |
24097	 *      |           |               |
24098	 *   Failed      Cancelled          |
24099	 *                          +-------+------+
24100	 *                          |              |
24101	 *                      Recognized       Began
24102	 *                                         |
24103	 *                                      Changed
24104	 *                                         |
24105	 *                                  Ended/Recognized
24106	 */
24107	var STATE_POSSIBLE = 1;
24108	var STATE_BEGAN = 2;
24109	var STATE_CHANGED = 4;
24110	var STATE_ENDED = 8;
24111	var STATE_RECOGNIZED = STATE_ENDED;
24112	var STATE_CANCELLED = 16;
24113	var STATE_FAILED = 32;
24114
24115	/**
24116	 * Recognizer
24117	 * Every recognizer needs to extend from this class.
24118	 * @constructor
24119	 * @param {Object} options
24120	 */
24121	function Recognizer(options) {
24122	    this.options = assign({}, this.defaults, options || {});
24123
24124	    this.id = uniqueId();
24125
24126	    this.manager = null;
24127
24128	    // default is enable true
24129	    this.options.enable = ifUndefined(this.options.enable, true);
24130
24131	    this.state = STATE_POSSIBLE;
24132
24133	    this.simultaneous = {};
24134	    this.requireFail = [];
24135	}
24136
24137	Recognizer.prototype = {
24138	    /**
24139	     * @virtual
24140	     * @type {Object}
24141	     */
24142	    defaults: {},
24143
24144	    /**
24145	     * set options
24146	     * @param {Object} options
24147	     * @return {Recognizer}
24148	     */
24149	    set: function(options) {
24150	        assign(this.options, options);
24151
24152	        // also update the touchAction, in case something changed about the directions/enabled state
24153	        this.manager && this.manager.touchAction.update();
24154	        return this;
24155	    },
24156
24157	    /**
24158	     * recognize simultaneous with an other recognizer.
24159	     * @param {Recognizer} otherRecognizer
24160	     * @returns {Recognizer} this
24161	     */
24162	    recognizeWith: function(otherRecognizer) {
24163	        if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
24164	            return this;
24165	        }
24166
24167	        var simultaneous = this.simultaneous;
24168	        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
24169	        if (!simultaneous[otherRecognizer.id]) {
24170	            simultaneous[otherRecognizer.id] = otherRecognizer;
24171	            otherRecognizer.recognizeWith(this);
24172	        }
24173	        return this;
24174	    },
24175
24176	    /**
24177	     * drop the simultaneous link. it doesnt remove the link on the other recognizer.
24178	     * @param {Recognizer} otherRecognizer
24179	     * @returns {Recognizer} this
24180	     */
24181	    dropRecognizeWith: function(otherRecognizer) {
24182	        if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
24183	            return this;
24184	        }
24185
24186	        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
24187	        delete this.simultaneous[otherRecognizer.id];
24188	        return this;
24189	    },
24190
24191	    /**
24192	     * recognizer can only run when an other is failing
24193	     * @param {Recognizer} otherRecognizer
24194	     * @returns {Recognizer} this
24195	     */
24196	    requireFailure: function(otherRecognizer) {
24197	        if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
24198	            return this;
24199	        }
24200
24201	        var requireFail = this.requireFail;
24202	        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
24203	        if (inArray(requireFail, otherRecognizer) === -1) {
24204	            requireFail.push(otherRecognizer);
24205	            otherRecognizer.requireFailure(this);
24206	        }
24207	        return this;
24208	    },
24209
24210	    /**
24211	     * drop the requireFailure link. it does not remove the link on the other recognizer.
24212	     * @param {Recognizer} otherRecognizer
24213	     * @returns {Recognizer} this
24214	     */
24215	    dropRequireFailure: function(otherRecognizer) {
24216	        if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
24217	            return this;
24218	        }
24219
24220	        otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
24221	        var index = inArray(this.requireFail, otherRecognizer);
24222	        if (index > -1) {
24223	            this.requireFail.splice(index, 1);
24224	        }
24225	        return this;
24226	    },
24227
24228	    /**
24229	     * has require failures boolean
24230	     * @returns {boolean}
24231	     */
24232	    hasRequireFailures: function() {
24233	        return this.requireFail.length > 0;
24234	    },
24235
24236	    /**
24237	     * if the recognizer can recognize simultaneous with an other recognizer
24238	     * @param {Recognizer} otherRecognizer
24239	     * @returns {Boolean}
24240	     */
24241	    canRecognizeWith: function(otherRecognizer) {
24242	        return !!this.simultaneous[otherRecognizer.id];
24243	    },
24244
24245	    /**
24246	     * You should use `tryEmit` instead of `emit` directly to check
24247	     * that all the needed recognizers has failed before emitting.
24248	     * @param {Object} input
24249	     */
24250	    emit: function(input) {
24251	        var self = this;
24252	        var state = this.state;
24253
24254	        function emit(event) {
24255	            self.manager.emit(event, input);
24256	        }
24257
24258	        // 'panstart' and 'panmove'
24259	        if (state < STATE_ENDED) {
24260	            emit(self.options.event + stateStr(state));
24261	        }
24262
24263	        emit(self.options.event); // simple 'eventName' events
24264
24265	        if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
24266	            emit(input.additionalEvent);
24267	        }
24268
24269	        // panend and pancancel
24270	        if (state >= STATE_ENDED) {
24271	            emit(self.options.event + stateStr(state));
24272	        }
24273	    },
24274
24275	    /**
24276	     * Check that all the require failure recognizers has failed,
24277	     * if true, it emits a gesture event,
24278	     * otherwise, setup the state to FAILED.
24279	     * @param {Object} input
24280	     */
24281	    tryEmit: function(input) {
24282	        if (this.canEmit()) {
24283	            return this.emit(input);
24284	        }
24285	        // it's failing anyway
24286	        this.state = STATE_FAILED;
24287	    },
24288
24289	    /**
24290	     * can we emit?
24291	     * @returns {boolean}
24292	     */
24293	    canEmit: function() {
24294	        var i = 0;
24295	        while (i < this.requireFail.length) {
24296	            if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
24297	                return false;
24298	            }
24299	            i++;
24300	        }
24301	        return true;
24302	    },
24303
24304	    /**
24305	     * update the recognizer
24306	     * @param {Object} inputData
24307	     */
24308	    recognize: function(inputData) {
24309	        // make a new copy of the inputData
24310	        // so we can change the inputData without messing up the other recognizers
24311	        var inputDataClone = assign({}, inputData);
24312
24313	        // is is enabled and allow recognizing?
24314	        if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
24315	            this.reset();
24316	            this.state = STATE_FAILED;
24317	            return;
24318	        }
24319
24320	        // reset when we've reached the end
24321	        if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
24322	            this.state = STATE_POSSIBLE;
24323	        }
24324
24325	        this.state = this.process(inputDataClone);
24326
24327	        // the recognizer has recognized a gesture
24328	        // so trigger an event
24329	        if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
24330	            this.tryEmit(inputDataClone);
24331	        }
24332	    },
24333
24334	    /**
24335	     * return the state of the recognizer
24336	     * the actual recognizing happens in this method
24337	     * @virtual
24338	     * @param {Object} inputData
24339	     * @returns {Const} STATE
24340	     */
24341	    process: function(inputData) { }, // jshint ignore:line
24342
24343	    /**
24344	     * return the preferred touch-action
24345	     * @virtual
24346	     * @returns {Array}
24347	     */
24348	    getTouchAction: function() { },
24349
24350	    /**
24351	     * called when the gesture isn't allowed to recognize
24352	     * like when another is being recognized or it is disabled
24353	     * @virtual
24354	     */
24355	    reset: function() { }
24356	};
24357
24358	/**
24359	 * get a usable string, used as event postfix
24360	 * @param {Const} state
24361	 * @returns {String} state
24362	 */
24363	function stateStr(state) {
24364	    if (state & STATE_CANCELLED) {
24365	        return 'cancel';
24366	    } else if (state & STATE_ENDED) {
24367	        return 'end';
24368	    } else if (state & STATE_CHANGED) {
24369	        return 'move';
24370	    } else if (state & STATE_BEGAN) {
24371	        return 'start';
24372	    }
24373	    return '';
24374	}
24375
24376	/**
24377	 * direction cons to string
24378	 * @param {Const} direction
24379	 * @returns {String}
24380	 */
24381	function directionStr(direction) {
24382	    if (direction == DIRECTION_DOWN) {
24383	        return 'down';
24384	    } else if (direction == DIRECTION_UP) {
24385	        return 'up';
24386	    } else if (direction == DIRECTION_LEFT) {
24387	        return 'left';
24388	    } else if (direction == DIRECTION_RIGHT) {
24389	        return 'right';
24390	    }
24391	    return '';
24392	}
24393
24394	/**
24395	 * get a recognizer by name if it is bound to a manager
24396	 * @param {Recognizer|String} otherRecognizer
24397	 * @param {Recognizer} recognizer
24398	 * @returns {Recognizer}
24399	 */
24400	function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
24401	    var manager = recognizer.manager;
24402	    if (manager) {
24403	        return manager.get(otherRecognizer);
24404	    }
24405	    return otherRecognizer;
24406	}
24407
24408	/**
24409	 * This recognizer is just used as a base for the simple attribute recognizers.
24410	 * @constructor
24411	 * @extends Recognizer
24412	 */
24413	function AttrRecognizer() {
24414	    Recognizer.apply(this, arguments);
24415	}
24416
24417	inherit(AttrRecognizer, Recognizer, {
24418	    /**
24419	     * @namespace
24420	     * @memberof AttrRecognizer
24421	     */
24422	    defaults: {
24423	        /**
24424	         * @type {Number}
24425	         * @default 1
24426	         */
24427	        pointers: 1
24428	    },
24429
24430	    /**
24431	     * Used to check if it the recognizer receives valid input, like input.distance > 10.
24432	     * @memberof AttrRecognizer
24433	     * @param {Object} input
24434	     * @returns {Boolean} recognized
24435	     */
24436	    attrTest: function(input) {
24437	        var optionPointers = this.options.pointers;
24438	        return optionPointers === 0 || input.pointers.length === optionPointers;
24439	    },
24440
24441	    /**
24442	     * Process the input and return the state for the recognizer
24443	     * @memberof AttrRecognizer
24444	     * @param {Object} input
24445	     * @returns {*} State
24446	     */
24447	    process: function(input) {
24448	        var state = this.state;
24449	        var eventType = input.eventType;
24450
24451	        var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
24452	        var isValid = this.attrTest(input);
24453
24454	        // on cancel input and we've recognized before, return STATE_CANCELLED
24455	        if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
24456	            return state | STATE_CANCELLED;
24457	        } else if (isRecognized || isValid) {
24458	            if (eventType & INPUT_END) {
24459	                return state | STATE_ENDED;
24460	            } else if (!(state & STATE_BEGAN)) {
24461	                return STATE_BEGAN;
24462	            }
24463	            return state | STATE_CHANGED;
24464	        }
24465	        return STATE_FAILED;
24466	    }
24467	});
24468
24469	/**
24470	 * Pan
24471	 * Recognized when the pointer is down and moved in the allowed direction.
24472	 * @constructor
24473	 * @extends AttrRecognizer
24474	 */
24475	function PanRecognizer() {
24476	    AttrRecognizer.apply(this, arguments);
24477
24478	    this.pX = null;
24479	    this.pY = null;
24480	}
24481
24482	inherit(PanRecognizer, AttrRecognizer, {
24483	    /**
24484	     * @namespace
24485	     * @memberof PanRecognizer
24486	     */
24487	    defaults: {
24488	        event: 'pan',
24489	        threshold: 10,
24490	        pointers: 1,
24491	        direction: DIRECTION_ALL
24492	    },
24493
24494	    getTouchAction: function() {
24495	        var direction = this.options.direction;
24496	        var actions = [];
24497	        if (direction & DIRECTION_HORIZONTAL) {
24498	            actions.push(TOUCH_ACTION_PAN_Y);
24499	        }
24500	        if (direction & DIRECTION_VERTICAL) {
24501	            actions.push(TOUCH_ACTION_PAN_X);
24502	        }
24503	        return actions;
24504	    },
24505
24506	    directionTest: function(input) {
24507	        var options = this.options;
24508	        var hasMoved = true;
24509	        var distance = input.distance;
24510	        var direction = input.direction;
24511	        var x = input.deltaX;
24512	        var y = input.deltaY;
24513
24514	        // lock to axis?
24515	        if (!(direction & options.direction)) {
24516	            if (options.direction & DIRECTION_HORIZONTAL) {
24517	                direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
24518	                hasMoved = x != this.pX;
24519	                distance = Math.abs(input.deltaX);
24520	            } else {
24521	                direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
24522	                hasMoved = y != this.pY;
24523	                distance = Math.abs(input.deltaY);
24524	            }
24525	        }
24526	        input.direction = direction;
24527	        return hasMoved && distance > options.threshold && direction & options.direction;
24528	    },
24529
24530	    attrTest: function(input) {
24531	        return AttrRecognizer.prototype.attrTest.call(this, input) &&
24532	            (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
24533	    },
24534
24535	    emit: function(input) {
24536
24537	        this.pX = input.deltaX;
24538	        this.pY = input.deltaY;
24539
24540	        var direction = directionStr(input.direction);
24541
24542	        if (direction) {
24543	            input.additionalEvent = this.options.event + direction;
24544	        }
24545	        this._super.emit.call(this, input);
24546	    }
24547	});
24548
24549	/**
24550	 * Pinch
24551	 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
24552	 * @constructor
24553	 * @extends AttrRecognizer
24554	 */
24555	function PinchRecognizer() {
24556	    AttrRecognizer.apply(this, arguments);
24557	}
24558
24559	inherit(PinchRecognizer, AttrRecognizer, {
24560	    /**
24561	     * @namespace
24562	     * @memberof PinchRecognizer
24563	     */
24564	    defaults: {
24565	        event: 'pinch',
24566	        threshold: 0,
24567	        pointers: 2
24568	    },
24569
24570	    getTouchAction: function() {
24571	        return [TOUCH_ACTION_NONE];
24572	    },
24573
24574	    attrTest: function(input) {
24575	        return this._super.attrTest.call(this, input) &&
24576	            (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
24577	    },
24578
24579	    emit: function(input) {
24580	        if (input.scale !== 1) {
24581	            var inOut = input.scale < 1 ? 'in' : 'out';
24582	            input.additionalEvent = this.options.event + inOut;
24583	        }
24584	        this._super.emit.call(this, input);
24585	    }
24586	});
24587
24588	/**
24589	 * Press
24590	 * Recognized when the pointer is down for x ms without any movement.
24591	 * @constructor
24592	 * @extends Recognizer
24593	 */
24594	function PressRecognizer() {
24595	    Recognizer.apply(this, arguments);
24596
24597	    this._timer = null;
24598	    this._input = null;
24599	}
24600
24601	inherit(PressRecognizer, Recognizer, {
24602	    /**
24603	     * @namespace
24604	     * @memberof PressRecognizer
24605	     */
24606	    defaults: {
24607	        event: 'press',
24608	        pointers: 1,
24609	        time: 251, // minimal time of the pointer to be pressed
24610	        threshold: 9 // a minimal movement is ok, but keep it low
24611	    },
24612
24613	    getTouchAction: function() {
24614	        return [TOUCH_ACTION_AUTO];
24615	    },
24616
24617	    process: function(input) {
24618	        var options = this.options;
24619	        var validPointers = input.pointers.length === options.pointers;
24620	        var validMovement = input.distance < options.threshold;
24621	        var validTime = input.deltaTime > options.time;
24622
24623	        this._input = input;
24624
24625	        // we only allow little movement
24626	        // and we've reached an end event, so a tap is possible
24627	        if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
24628	            this.reset();
24629	        } else if (input.eventType & INPUT_START) {
24630	            this.reset();
24631	            this._timer = setTimeoutContext(function() {
24632	                this.state = STATE_RECOGNIZED;
24633	                this.tryEmit();
24634	            }, options.time, this);
24635	        } else if (input.eventType & INPUT_END) {
24636	            return STATE_RECOGNIZED;
24637	        }
24638	        return STATE_FAILED;
24639	    },
24640
24641	    reset: function() {
24642	        clearTimeout(this._timer);
24643	    },
24644
24645	    emit: function(input) {
24646	        if (this.state !== STATE_RECOGNIZED) {
24647	            return;
24648	        }
24649
24650	        if (input && (input.eventType & INPUT_END)) {
24651	            this.manager.emit(this.options.event + 'up', input);
24652	        } else {
24653	            this._input.timeStamp = now();
24654	            this.manager.emit(this.options.event, this._input);
24655	        }
24656	    }
24657	});
24658
24659	/**
24660	 * Rotate
24661	 * Recognized when two or more pointer are moving in a circular motion.
24662	 * @constructor
24663	 * @extends AttrRecognizer
24664	 */
24665	function RotateRecognizer() {
24666	    AttrRecognizer.apply(this, arguments);
24667	}
24668
24669	inherit(RotateRecognizer, AttrRecognizer, {
24670	    /**
24671	     * @namespace
24672	     * @memberof RotateRecognizer
24673	     */
24674	    defaults: {
24675	        event: 'rotate',
24676	        threshold: 0,
24677	        pointers: 2
24678	    },
24679
24680	    getTouchAction: function() {
24681	        return [TOUCH_ACTION_NONE];
24682	    },
24683
24684	    attrTest: function(input) {
24685	        return this._super.attrTest.call(this, input) &&
24686	            (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
24687	    }
24688	});
24689
24690	/**
24691	 * Swipe
24692	 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
24693	 * @constructor
24694	 * @extends AttrRecognizer
24695	 */
24696	function SwipeRecognizer() {
24697	    AttrRecognizer.apply(this, arguments);
24698	}
24699
24700	inherit(SwipeRecognizer, AttrRecognizer, {
24701	    /**
24702	     * @namespace
24703	     * @memberof SwipeRecognizer
24704	     */
24705	    defaults: {
24706	        event: 'swipe',
24707	        threshold: 10,
24708	        velocity: 0.3,
24709	        direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
24710	        pointers: 1
24711	    },
24712
24713	    getTouchAction: function() {
24714	        return PanRecognizer.prototype.getTouchAction.call(this);
24715	    },
24716
24717	    attrTest: function(input) {
24718	        var direction = this.options.direction;
24719	        var velocity;
24720
24721	        if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
24722	            velocity = input.overallVelocity;
24723	        } else if (direction & DIRECTION_HORIZONTAL) {
24724	            velocity = input.overallVelocityX;
24725	        } else if (direction & DIRECTION_VERTICAL) {
24726	            velocity = input.overallVelocityY;
24727	        }
24728
24729	        return this._super.attrTest.call(this, input) &&
24730	            direction & input.offsetDirection &&
24731	            input.distance > this.options.threshold &&
24732	            input.maxPointers == this.options.pointers &&
24733	            abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
24734	    },
24735
24736	    emit: function(input) {
24737	        var direction = directionStr(input.offsetDirection);
24738	        if (direction) {
24739	            this.manager.emit(this.options.event + direction, input);
24740	        }
24741
24742	        this.manager.emit(this.options.event, input);
24743	    }
24744	});
24745
24746	/**
24747	 * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
24748	 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
24749	 * a single tap.
24750	 *
24751	 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
24752	 * multi-taps being recognized.
24753	 * @constructor
24754	 * @extends Recognizer
24755	 */
24756	function TapRecognizer() {
24757	    Recognizer.apply(this, arguments);
24758
24759	    // previous time and center,
24760	    // used for tap counting
24761	    this.pTime = false;
24762	    this.pCenter = false;
24763
24764	    this._timer = null;
24765	    this._input = null;
24766	    this.count = 0;
24767	}
24768
24769	inherit(TapRecognizer, Recognizer, {
24770	    /**
24771	     * @namespace
24772	     * @memberof PinchRecognizer
24773	     */
24774	    defaults: {
24775	        event: 'tap',
24776	        pointers: 1,
24777	        taps: 1,
24778	        interval: 300, // max time between the multi-tap taps
24779	        time: 250, // max time of the pointer to be down (like finger on the screen)
24780	        threshold: 9, // a minimal movement is ok, but keep it low
24781	        posThreshold: 10 // a multi-tap can be a bit off the initial position
24782	    },
24783
24784	    getTouchAction: function() {
24785	        return [TOUCH_ACTION_MANIPULATION];
24786	    },
24787
24788	    process: function(input) {
24789	        var options = this.options;
24790
24791	        var validPointers = input.pointers.length === options.pointers;
24792	        var validMovement = input.distance < options.threshold;
24793	        var validTouchTime = input.deltaTime < options.time;
24794
24795	        this.reset();
24796
24797	        if ((input.eventType & INPUT_START) && (this.count === 0)) {
24798	            return this.failTimeout();
24799	        }
24800
24801	        // we only allow little movement
24802	        // and we've reached an end event, so a tap is possible
24803	        if (validMovement && validTouchTime && validPointers) {
24804	            if (input.eventType != INPUT_END) {
24805	                return this.failTimeout();
24806	            }
24807
24808	            var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
24809	            var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
24810
24811	            this.pTime = input.timeStamp;
24812	            this.pCenter = input.center;
24813
24814	            if (!validMultiTap || !validInterval) {
24815	                this.count = 1;
24816	            } else {
24817	                this.count += 1;
24818	            }
24819
24820	            this._input = input;
24821
24822	            // if tap count matches we have recognized it,
24823	            // else it has began recognizing...
24824	            var tapCount = this.count % options.taps;
24825	            if (tapCount === 0) {
24826	                // no failing requirements, immediately trigger the tap event
24827	                // or wait as long as the multitap interval to trigger
24828	                if (!this.hasRequireFailures()) {
24829	                    return STATE_RECOGNIZED;
24830	                } else {
24831	                    this._timer = setTimeoutContext(function() {
24832	                        this.state = STATE_RECOGNIZED;
24833	                        this.tryEmit();
24834	                    }, options.interval, this);
24835	                    return STATE_BEGAN;
24836	                }
24837	            }
24838	        }
24839	        return STATE_FAILED;
24840	    },
24841
24842	    failTimeout: function() {
24843	        this._timer = setTimeoutContext(function() {
24844	            this.state = STATE_FAILED;
24845	        }, this.options.interval, this);
24846	        return STATE_FAILED;
24847	    },
24848
24849	    reset: function() {
24850	        clearTimeout(this._timer);
24851	    },
24852
24853	    emit: function() {
24854	        if (this.state == STATE_RECOGNIZED) {
24855	            this._input.tapCount = this.count;
24856	            this.manager.emit(this.options.event, this._input);
24857	        }
24858	    }
24859	});
24860
24861	/**
24862	 * Simple way to create a manager with a default set of recognizers.
24863	 * @param {HTMLElement} element
24864	 * @param {Object} [options]
24865	 * @constructor
24866	 */
24867	function Hammer(element, options) {
24868	    options = options || {};
24869	    options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
24870	    return new Manager(element, options);
24871	}
24872
24873	/**
24874	 * @const {string}
24875	 */
24876	Hammer.VERSION = '2.0.7';
24877
24878	/**
24879	 * default settings
24880	 * @namespace
24881	 */
24882	Hammer.defaults = {
24883	    /**
24884	     * set if DOM events are being triggered.
24885	     * But this is slower and unused by simple implementations, so disabled by default.
24886	     * @type {Boolean}
24887	     * @default false
24888	     */
24889	    domEvents: false,
24890
24891	    /**
24892	     * The value for the touchAction property/fallback.
24893	     * When set to `compute` it will magically set the correct value based on the added recognizers.
24894	     * @type {String}
24895	     * @default compute
24896	     */
24897	    touchAction: TOUCH_ACTION_COMPUTE,
24898
24899	    /**
24900	     * @type {Boolean}
24901	     * @default true
24902	     */
24903	    enable: true,
24904
24905	    /**
24906	     * EXPERIMENTAL FEATURE -- can be removed/changed
24907	     * Change the parent input target element.
24908	     * If Null, then it is being set the to main element.
24909	     * @type {Null|EventTarget}
24910	     * @default null
24911	     */
24912	    inputTarget: null,
24913
24914	    /**
24915	     * force an input class
24916	     * @type {Null|Function}
24917	     * @default null
24918	     */
24919	    inputClass: null,
24920
24921	    /**
24922	     * Default recognizer setup when calling `Hammer()`
24923	     * When creating a new Manager these will be skipped.
24924	     * @type {Array}
24925	     */
24926	    preset: [
24927	        // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
24928	        [RotateRecognizer, {enable: false}],
24929	        [PinchRecognizer, {enable: false}, ['rotate']],
24930	        [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
24931	        [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
24932	        [TapRecognizer],
24933	        [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
24934	        [PressRecognizer]
24935	    ],
24936
24937	    /**
24938	     * Some CSS properties can be used to improve the working of Hammer.
24939	     * Add them to this method and they will be set when creating a new Manager.
24940	     * @namespace
24941	     */
24942	    cssProps: {
24943	        /**
24944	         * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
24945	         * @type {String}
24946	         * @default 'none'
24947	         */
24948	        userSelect: 'none',
24949
24950	        /**
24951	         * Disable the Windows Phone grippers when pressing an element.
24952	         * @type {String}
24953	         * @default 'none'
24954	         */
24955	        touchSelect: 'none',
24956
24957	        /**
24958	         * Disables the default callout shown when you touch and hold a touch target.
24959	         * On iOS, when you touch and hold a touch target such as a link, Safari displays
24960	         * a callout containing information about the link. This property allows you to disable that callout.
24961	         * @type {String}
24962	         * @default 'none'
24963	         */
24964	        touchCallout: 'none',
24965
24966	        /**
24967	         * Specifies whether zooming is enabled. Used by IE10>
24968	         * @type {String}
24969	         * @default 'none'
24970	         */
24971	        contentZooming: 'none',
24972
24973	        /**
24974	         * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
24975	         * @type {String}
24976	         * @default 'none'
24977	         */
24978	        userDrag: 'none',
24979
24980	        /**
24981	         * Overrides the highlight color shown when the user taps a link or a JavaScript
24982	         * clickable element in iOS. This property obeys the alpha value, if specified.
24983	         * @type {String}
24984	         * @default 'rgba(0,0,0,0)'
24985	         */
24986	        tapHighlightColor: 'rgba(0,0,0,0)'
24987	    }
24988	};
24989
24990	var STOP = 1;
24991	var FORCED_STOP = 2;
24992
24993	/**
24994	 * Manager
24995	 * @param {HTMLElement} element
24996	 * @param {Object} [options]
24997	 * @constructor
24998	 */
24999	function Manager(element, options) {
25000	    this.options = assign({}, Hammer.defaults, options || {});
25001
25002	    this.options.inputTarget = this.options.inputTarget || element;
25003
25004	    this.handlers = {};
25005	    this.session = {};
25006	    this.recognizers = [];
25007	    this.oldCssProps = {};
25008
25009	    this.element = element;
25010	    this.input = createInputInstance(this);
25011	    this.touchAction = new TouchAction(this, this.options.touchAction);
25012
25013	    toggleCssProps(this, true);
25014
25015	    each(this.options.recognizers, function(item) {
25016	        var recognizer = this.add(new (item[0])(item[1]));
25017	        item[2] && recognizer.recognizeWith(item[2]);
25018	        item[3] && recognizer.requireFailure(item[3]);
25019	    }, this);
25020	}
25021
25022	Manager.prototype = {
25023	    /**
25024	     * set options
25025	     * @param {Object} options
25026	     * @returns {Manager}
25027	     */
25028	    set: function(options) {
25029	        assign(this.options, options);
25030
25031	        // Options that need a little more setup
25032	        if (options.touchAction) {
25033	            this.touchAction.update();
25034	        }
25035	        if (options.inputTarget) {
25036	            // Clean up existing event listeners and reinitialize
25037	            this.input.destroy();
25038	            this.input.target = options.inputTarget;
25039	            this.input.init();
25040	        }
25041	        return this;
25042	    },
25043
25044	    /**
25045	     * stop recognizing for this session.
25046	     * This session will be discarded, when a new [input]start event is fired.
25047	     * When forced, the recognizer cycle is stopped immediately.
25048	     * @param {Boolean} [force]
25049	     */
25050	    stop: function(force) {
25051	        this.session.stopped = force ? FORCED_STOP : STOP;
25052	    },
25053
25054	    /**
25055	     * run the recognizers!
25056	     * called by the inputHandler function on every movement of the pointers (touches)
25057	     * it walks through all the recognizers and tries to detect the gesture that is being made
25058	     * @param {Object} inputData
25059	     */
25060	    recognize: function(inputData) {
25061	        var session = this.session;
25062	        if (session.stopped) {
25063	            return;
25064	        }
25065
25066	        // run the touch-action polyfill
25067	        this.touchAction.preventDefaults(inputData);
25068
25069	        var recognizer;
25070	        var recognizers = this.recognizers;
25071
25072	        // this holds the recognizer that is being recognized.
25073	        // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
25074	        // if no recognizer is detecting a thing, it is set to `null`
25075	        var curRecognizer = session.curRecognizer;
25076
25077	        // reset when the last recognizer is recognized
25078	        // or when we're in a new session
25079	        if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
25080	            curRecognizer = session.curRecognizer = null;
25081	        }
25082
25083	        var i = 0;
25084	        while (i < recognizers.length) {
25085	            recognizer = recognizers[i];
25086
25087	            // find out if we are allowed try to recognize the input for this one.
25088	            // 1.   allow if the session is NOT forced stopped (see the .stop() method)
25089	            // 2.   allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
25090	            //      that is being recognized.
25091	            // 3.   allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
25092	            //      this can be setup with the `recognizeWith()` method on the recognizer.
25093	            if (session.stopped !== FORCED_STOP && ( // 1
25094	                    !curRecognizer || recognizer == curRecognizer || // 2
25095	                    recognizer.canRecognizeWith(curRecognizer))) { // 3
25096	                recognizer.recognize(inputData);
25097	            } else {
25098	                recognizer.reset();
25099	            }
25100
25101	            // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
25102	            // current active recognizer. but only if we don't already have an active recognizer
25103	            if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
25104	                curRecognizer = session.curRecognizer = recognizer;
25105	            }
25106	            i++;
25107	        }
25108	    },
25109
25110	    /**
25111	     * get a recognizer by its event name.
25112	     * @param {Recognizer|String} recognizer
25113	     * @returns {Recognizer|Null}
25114	     */
25115	    get: function(recognizer) {
25116	        if (recognizer instanceof Recognizer) {
25117	            return recognizer;
25118	        }
25119
25120	        var recognizers = this.recognizers;
25121	        for (var i = 0; i < recognizers.length; i++) {
25122	            if (recognizers[i].options.event == recognizer) {
25123	                return recognizers[i];
25124	            }
25125	        }
25126	        return null;
25127	    },
25128
25129	    /**
25130	     * add a recognizer to the manager
25131	     * existing recognizers with the same event name will be removed
25132	     * @param {Recognizer} recognizer
25133	     * @returns {Recognizer|Manager}
25134	     */
25135	    add: function(recognizer) {
25136	        if (invokeArrayArg(recognizer, 'add', this)) {
25137	            return this;
25138	        }
25139
25140	        // remove existing
25141	        var existing = this.get(recognizer.options.event);
25142	        if (existing) {
25143	            this.remove(existing);
25144	        }
25145
25146	        this.recognizers.push(recognizer);
25147	        recognizer.manager = this;
25148
25149	        this.touchAction.update();
25150	        return recognizer;
25151	    },
25152
25153	    /**
25154	     * remove a recognizer by name or instance
25155	     * @param {Recognizer|String} recognizer
25156	     * @returns {Manager}
25157	     */
25158	    remove: function(recognizer) {
25159	        if (invokeArrayArg(recognizer, 'remove', this)) {
25160	            return this;
25161	        }
25162
25163	        recognizer = this.get(recognizer);
25164
25165	        // let's make sure this recognizer exists
25166	        if (recognizer) {
25167	            var recognizers = this.recognizers;
25168	            var index = inArray(recognizers, recognizer);
25169
25170	            if (index !== -1) {
25171	                recognizers.splice(index, 1);
25172	                this.touchAction.update();
25173	            }
25174	        }
25175
25176	        return this;
25177	    },
25178
25179	    /**
25180	     * bind event
25181	     * @param {String} events
25182	     * @param {Function} handler
25183	     * @returns {EventEmitter} this
25184	     */
25185	    on: function(events, handler) {
25186	        if (events === undefined$1) {
25187	            return;
25188	        }
25189	        if (handler === undefined$1) {
25190	            return;
25191	        }
25192
25193	        var handlers = this.handlers;
25194	        each(splitStr(events), function(event) {
25195	            handlers[event] = handlers[event] || [];
25196	            handlers[event].push(handler);
25197	        });
25198	        return this;
25199	    },
25200
25201	    /**
25202	     * unbind event, leave emit blank to remove all handlers
25203	     * @param {String} events
25204	     * @param {Function} [handler]
25205	     * @returns {EventEmitter} this
25206	     */
25207	    off: function(events, handler) {
25208	        if (events === undefined$1) {
25209	            return;
25210	        }
25211
25212	        var handlers = this.handlers;
25213	        each(splitStr(events), function(event) {
25214	            if (!handler) {
25215	                delete handlers[event];
25216	            } else {
25217	                handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
25218	            }
25219	        });
25220	        return this;
25221	    },
25222
25223	    /**
25224	     * emit event to the listeners
25225	     * @param {String} event
25226	     * @param {Object} data
25227	     */
25228	    emit: function(event, data) {
25229	        // we also want to trigger dom events
25230	        if (this.options.domEvents) {
25231	            triggerDomEvent(event, data);
25232	        }
25233
25234	        // no handlers, so skip it all
25235	        var handlers = this.handlers[event] && this.handlers[event].slice();
25236	        if (!handlers || !handlers.length) {
25237	            return;
25238	        }
25239
25240	        data.type = event;
25241	        data.preventDefault = function() {
25242	            data.srcEvent.preventDefault();
25243	        };
25244
25245	        var i = 0;
25246	        while (i < handlers.length) {
25247	            handlers[i](data);
25248	            i++;
25249	        }
25250	    },
25251
25252	    /**
25253	     * destroy the manager and unbinds all events
25254	     * it doesn't unbind dom events, that is the user own responsibility
25255	     */
25256	    destroy: function() {
25257	        this.element && toggleCssProps(this, false);
25258
25259	        this.handlers = {};
25260	        this.session = {};
25261	        this.input.destroy();
25262	        this.element = null;
25263	    }
25264	};
25265
25266	/**
25267	 * add/remove the css properties as defined in manager.options.cssProps
25268	 * @param {Manager} manager
25269	 * @param {Boolean} add
25270	 */
25271	function toggleCssProps(manager, add) {
25272	    var element = manager.element;
25273	    if (!element.style) {
25274	        return;
25275	    }
25276	    var prop;
25277	    each(manager.options.cssProps, function(value, name) {
25278	        prop = prefixed(element.style, name);
25279	        if (add) {
25280	            manager.oldCssProps[prop] = element.style[prop];
25281	            element.style[prop] = value;
25282	        } else {
25283	            element.style[prop] = manager.oldCssProps[prop] || '';
25284	        }
25285	    });
25286	    if (!add) {
25287	        manager.oldCssProps = {};
25288	    }
25289	}
25290
25291	/**
25292	 * trigger dom event
25293	 * @param {String} event
25294	 * @param {Object} data
25295	 */
25296	function triggerDomEvent(event, data) {
25297	    var gestureEvent = document.createEvent('Event');
25298	    gestureEvent.initEvent(event, true, true);
25299	    gestureEvent.gesture = data;
25300	    data.target.dispatchEvent(gestureEvent);
25301	}
25302
25303	assign(Hammer, {
25304	    INPUT_START: INPUT_START,
25305	    INPUT_MOVE: INPUT_MOVE,
25306	    INPUT_END: INPUT_END,
25307	    INPUT_CANCEL: INPUT_CANCEL,
25308
25309	    STATE_POSSIBLE: STATE_POSSIBLE,
25310	    STATE_BEGAN: STATE_BEGAN,
25311	    STATE_CHANGED: STATE_CHANGED,
25312	    STATE_ENDED: STATE_ENDED,
25313	    STATE_RECOGNIZED: STATE_RECOGNIZED,
25314	    STATE_CANCELLED: STATE_CANCELLED,
25315	    STATE_FAILED: STATE_FAILED,
25316
25317	    DIRECTION_NONE: DIRECTION_NONE,
25318	    DIRECTION_LEFT: DIRECTION_LEFT,
25319	    DIRECTION_RIGHT: DIRECTION_RIGHT,
25320	    DIRECTION_UP: DIRECTION_UP,
25321	    DIRECTION_DOWN: DIRECTION_DOWN,
25322	    DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
25323	    DIRECTION_VERTICAL: DIRECTION_VERTICAL,
25324	    DIRECTION_ALL: DIRECTION_ALL,
25325
25326	    Manager: Manager,
25327	    Input: Input,
25328	    TouchAction: TouchAction,
25329
25330	    TouchInput: TouchInput,
25331	    MouseInput: MouseInput,
25332	    PointerEventInput: PointerEventInput,
25333	    TouchMouseInput: TouchMouseInput,
25334	    SingleTouchInput: SingleTouchInput,
25335
25336	    Recognizer: Recognizer,
25337	    AttrRecognizer: AttrRecognizer,
25338	    Tap: TapRecognizer,
25339	    Pan: PanRecognizer,
25340	    Swipe: SwipeRecognizer,
25341	    Pinch: PinchRecognizer,
25342	    Rotate: RotateRecognizer,
25343	    Press: PressRecognizer,
25344
25345	    on: addEventListeners,
25346	    off: removeEventListeners,
25347	    each: each,
25348	    merge: merge,
25349	    extend: extend,
25350	    assign: assign,
25351	    inherit: inherit,
25352	    bindFn: bindFn,
25353	    prefixed: prefixed
25354	});
25355
25356	// this prevents errors when Hammer is loaded in the presence of an AMD
25357	//  style loader but by script tag, not by the loader.
25358	var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
25359	freeGlobal.Hammer = Hammer;
25360
25361	if (typeof undefined$1 === 'function' && undefined$1.amd) {
25362	    undefined$1(function() {
25363	        return Hammer;
25364	    });
25365	} else if (module.exports) {
25366	    module.exports = Hammer;
25367	} else {
25368	    window[exportName] = Hammer;
25369	}
25370
25371	})(window, document, 'Hammer');
25372	}(hammer));
25373
25374	var Hammer = hammer.exports;
25375
25376	var MIN_ZOOM = 0.2,
25377	    MAX_ZOOM = 4;
25378
25379	var mouseEvents = [
25380	  'mousedown',
25381	  'mouseup',
25382	  'mouseover',
25383	  'mouseout',
25384	  'click',
25385	  'dblclick'
25386	];
25387
25388	function get(service, injector) {
25389	  return injector.get(service, false);
25390	}
25391
25392	function stopEvent(event) {
25393
25394	  event.preventDefault();
25395
25396	  if (typeof event.stopPropagation === 'function') {
25397	    event.stopPropagation();
25398	  } else if (event.srcEvent && typeof event.srcEvent.stopPropagation === 'function') {
25399
25400	    // iPhone & iPad
25401	    event.srcEvent.stopPropagation();
25402	  }
25403
25404	  if (typeof event.stopImmediatePropagation === 'function') {
25405	    event.stopImmediatePropagation();
25406	  }
25407	}
25408
25409
25410	function createTouchRecognizer(node) {
25411
25412	  function stopMouse(event) {
25413
25414	    forEach(mouseEvents, function(e) {
25415	      componentEvent.bind(node, e, stopEvent, true);
25416	    });
25417	  }
25418
25419	  function allowMouse(event) {
25420	    setTimeout(function() {
25421	      forEach(mouseEvents, function(e) {
25422	        componentEvent.unbind(node, e, stopEvent, true);
25423	      });
25424	    }, 500);
25425	  }
25426
25427	  componentEvent.bind(node, 'touchstart', stopMouse, true);
25428	  componentEvent.bind(node, 'touchend', allowMouse, true);
25429	  componentEvent.bind(node, 'touchcancel', allowMouse, true);
25430
25431	  // A touch event recognizer that handles
25432	  // touch events only (we know, we can already handle
25433	  // mouse events out of the box)
25434
25435	  var recognizer = new Hammer.Manager(node, {
25436	    inputClass: Hammer.TouchInput,
25437	    recognizers: [],
25438	    domEvents: true
25439	  });
25440
25441
25442	  var tap = new Hammer.Tap();
25443	  var pan = new Hammer.Pan({ threshold: 10 });
25444	  var press = new Hammer.Press();
25445	  var pinch = new Hammer.Pinch();
25446
25447	  var doubleTap = new Hammer.Tap({ event: 'doubletap', taps: 2 });
25448
25449	  pinch.requireFailure(pan);
25450	  pinch.requireFailure(press);
25451
25452	  recognizer.add([ pan, press, pinch, doubleTap, tap ]);
25453
25454	  recognizer.reset = function(force) {
25455	    var recognizers = this.recognizers,
25456	        session = this.session;
25457
25458	    if (session.stopped) {
25459	      return;
25460	    }
25461
25462	    recognizer.stop(force);
25463
25464	    setTimeout(function() {
25465	      var i, r;
25466	      for (i = 0; (r = recognizers[i]); i++) {
25467	        r.reset();
25468	        r.state = 8; // FAILED STATE
25469	      }
25470
25471	      session.curRecognizer = null;
25472	    }, 0);
25473	  };
25474
25475	  recognizer.on('hammer.input', function(event) {
25476	    if (event.srcEvent.defaultPrevented) {
25477	      recognizer.reset(true);
25478	    }
25479	  });
25480
25481	  return recognizer;
25482	}
25483
25484	/**
25485	 * A plugin that provides touch events for elements.
25486	 *
25487	 * @param {EventBus} eventBus
25488	 * @param {InteractionEvents} interactionEvents
25489	 */
25490	function TouchInteractionEvents(
25491	    injector, canvas, eventBus,
25492	    elementRegistry, interactionEvents) {
25493
25494	  // optional integrations
25495	  var dragging = get('dragging', injector),
25496	      move = get('move', injector),
25497	      contextPad = get('contextPad', injector),
25498	      palette = get('palette', injector);
25499
25500	  // the touch recognizer
25501	  var recognizer;
25502
25503	  function handler(type) {
25504
25505	    return function(event) {
25506
25507	      interactionEvents.fire(type, event);
25508	    };
25509	  }
25510
25511	  function getGfx(target) {
25512	    var node = closest(target, 'svg, .djs-element', true);
25513	    return node;
25514	  }
25515
25516	  function initEvents(svg) {
25517
25518	    // touch recognizer
25519	    recognizer = createTouchRecognizer(svg);
25520
25521	    recognizer.on('doubletap', handler('element.dblclick'));
25522
25523	    recognizer.on('tap', handler('element.click'));
25524
25525	    function startGrabCanvas(event) {
25526
25527	      var lx = 0, ly = 0;
25528
25529	      function update(e) {
25530
25531	        var dx = e.deltaX - lx,
25532	            dy = e.deltaY - ly;
25533
25534	        canvas.scroll({ dx: dx, dy: dy });
25535
25536	        lx = e.deltaX;
25537	        ly = e.deltaY;
25538	      }
25539
25540	      function end(e) {
25541	        recognizer.off('panmove', update);
25542	        recognizer.off('panend', end);
25543	        recognizer.off('pancancel', end);
25544	      }
25545
25546	      recognizer.on('panmove', update);
25547	      recognizer.on('panend', end);
25548	      recognizer.on('pancancel', end);
25549	    }
25550
25551	    function startGrab(event) {
25552
25553	      var gfx = getGfx(event.target),
25554	          element = gfx && elementRegistry.get(gfx);
25555
25556	      // recognizer
25557	      if (move && canvas.getRootElement() !== element) {
25558	        return move.start(event, element, true);
25559	      } else {
25560	        startGrabCanvas();
25561	      }
25562	    }
25563
25564	    function startZoom(e) {
25565
25566	      var zoom = canvas.zoom(),
25567	          mid = e.center;
25568
25569	      function update(e) {
25570
25571	        var ratio = 1 - (1 - e.scale) / 1.50,
25572	            newZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, ratio * zoom));
25573
25574	        canvas.zoom(newZoom, mid);
25575
25576	        stopEvent(e);
25577	      }
25578
25579	      function end(e) {
25580	        recognizer.off('pinchmove', update);
25581	        recognizer.off('pinchend', end);
25582	        recognizer.off('pinchcancel', end);
25583
25584	        recognizer.reset(true);
25585	      }
25586
25587	      recognizer.on('pinchmove', update);
25588	      recognizer.on('pinchend', end);
25589	      recognizer.on('pinchcancel', end);
25590	    }
25591
25592	    recognizer.on('panstart', startGrab);
25593	    recognizer.on('press', startGrab);
25594
25595	    recognizer.on('pinchstart', startZoom);
25596	  }
25597
25598	  if (dragging) {
25599
25600	    // simulate hover during dragging
25601	    eventBus.on('drag.move', function(event) {
25602
25603	      var originalEvent = event.originalEvent;
25604
25605	      if (!originalEvent || originalEvent instanceof MouseEvent) {
25606	        return;
25607	      }
25608
25609	      var position = toPoint(originalEvent);
25610
25611	      // this gets really expensive ...
25612	      var node = document.elementFromPoint(position.x, position.y),
25613	          gfx = getGfx(node),
25614	          element = gfx && elementRegistry.get(gfx);
25615
25616	      if (element !== event.hover) {
25617	        if (event.hover) {
25618	          dragging.out(event);
25619	        }
25620
25621	        if (element) {
25622	          dragging.hover({ element: element, gfx: gfx });
25623
25624	          event.hover = element;
25625	          event.hoverGfx = gfx;
25626	        }
25627	      }
25628	    });
25629	  }
25630
25631	  if (contextPad) {
25632
25633	    eventBus.on('contextPad.create', function(event) {
25634	      var node = event.pad.html;
25635
25636	      // touch recognizer
25637	      var padRecognizer = createTouchRecognizer(node);
25638
25639	      padRecognizer.on('panstart', function(event) {
25640	        contextPad.trigger('dragstart', event, true);
25641	      });
25642
25643	      padRecognizer.on('press', function(event) {
25644	        contextPad.trigger('dragstart', event, true);
25645	      });
25646
25647	      padRecognizer.on('tap', function(event) {
25648	        contextPad.trigger('click', event);
25649	      });
25650	    });
25651	  }
25652
25653	  if (palette) {
25654	    eventBus.on('palette.create', function(event) {
25655	      var node = event.container;
25656
25657	      // touch recognizer
25658	      var padRecognizer = createTouchRecognizer(node);
25659
25660	      padRecognizer.on('panstart', function(event) {
25661	        palette.trigger('dragstart', event, true);
25662	      });
25663
25664	      padRecognizer.on('press', function(event) {
25665	        palette.trigger('dragstart', event, true);
25666	      });
25667
25668	      padRecognizer.on('tap', function(event) {
25669	        palette.trigger('click', event);
25670	      });
25671	    });
25672	  }
25673
25674	  eventBus.on('canvas.init', function(event) {
25675	    initEvents(event.svg);
25676	  });
25677	}
25678
25679
25680	TouchInteractionEvents.$inject = [
25681	  'injector',
25682	  'canvas',
25683	  'eventBus',
25684	  'elementRegistry',
25685	  'interactionEvents',
25686	  'touchFix'
25687	];
25688
25689	function TouchFix(canvas, eventBus) {
25690
25691	  var self = this;
25692
25693	  eventBus.on('canvas.init', function(e) {
25694	    self.addBBoxMarker(e.svg);
25695	  });
25696	}
25697
25698	TouchFix.$inject = [ 'canvas', 'eventBus' ];
25699
25700
25701	/**
25702	 * Safari mobile (iOS 7) does not fire touchstart event in <SVG> element
25703	 * if there is no shape between 0,0 and viewport elements origin.
25704	 *
25705	 * So touchstart event is only fired when the <g class="viewport"> element was hit.
25706	 * Putting an element over and below the 'viewport' fixes that behavior.
25707	 */
25708	TouchFix.prototype.addBBoxMarker = function(svg) {
25709
25710	  var markerStyle = {
25711	    fill: 'none',
25712	    class: 'outer-bound-marker'
25713	  };
25714
25715	  var rect1 = create$1('rect');
25716	  attr(rect1, {
25717	    x: -10000,
25718	    y: 10000,
25719	    width: 10,
25720	    height: 10
25721	  });
25722	  attr(rect1, markerStyle);
25723
25724	  append(svg, rect1);
25725
25726	  var rect2 = create$1('rect');
25727	  attr(rect2, {
25728	    x: 10000,
25729	    y: 10000,
25730	    width: 10,
25731	    height: 10
25732	  });
25733	  attr(rect2, markerStyle);
25734
25735	  append(svg, rect2);
25736	};
25737
25738	var TouchModule$1 = {
25739	  __depends__: [ InteractionEventsModule$1 ],
25740	  __init__: [ 'touchInteractionEvents' ],
25741	  touchInteractionEvents: [ 'type', TouchInteractionEvents ],
25742	  touchFix: [ 'type', TouchFix ]
25743	};
25744
25745	var TouchModule = {
25746	  __depends__: [
25747	    TouchModule$1
25748	  ]
25749	};
25750
25751	function last(arr) {
25752	  return arr && arr[arr.length - 1];
25753	}
25754
25755	function sortTopOrMiddle(element) {
25756	  return element.y;
25757	}
25758
25759	function sortLeftOrCenter(element) {
25760	  return element.x;
25761	}
25762
25763	/**
25764	 * Sorting functions for different types of alignment
25765	 *
25766	 * @type {Object}
25767	 *
25768	 * @return {Function}
25769	 */
25770	var ALIGNMENT_SORTING = {
25771	  left: sortLeftOrCenter,
25772	  center: sortLeftOrCenter,
25773	  right: function(element) {
25774	    return element.x + element.width;
25775	  },
25776	  top: sortTopOrMiddle,
25777	  middle: sortTopOrMiddle,
25778	  bottom: function(element) {
25779	    return element.y + element.height;
25780	  }
25781	};
25782
25783
25784	function AlignElements$1(modeling) {
25785	  this._modeling = modeling;
25786	}
25787
25788	AlignElements$1.$inject = [ 'modeling' ];
25789
25790
25791	/**
25792	 * Get the relevant "axis" and "dimension" related to the current type of alignment
25793	 *
25794	 * @param  {string} type left|right|center|top|bottom|middle
25795	 *
25796	 * @return {Object} { axis, dimension }
25797	 */
25798	AlignElements$1.prototype._getOrientationDetails = function(type) {
25799	  var vertical = [ 'top', 'bottom', 'middle' ],
25800	      axis = 'x',
25801	      dimension = 'width';
25802
25803	  if (vertical.indexOf(type) !== -1) {
25804	    axis = 'y';
25805	    dimension = 'height';
25806	  }
25807
25808	  return {
25809	    axis: axis,
25810	    dimension: dimension
25811	  };
25812	};
25813
25814	AlignElements$1.prototype._isType = function(type, types) {
25815	  return types.indexOf(type) !== -1;
25816	};
25817
25818	/**
25819	 * Get a point on the relevant axis where elements should align to
25820	 *
25821	 * @param  {string} type left|right|center|top|bottom|middle
25822	 * @param  {Array} sortedElements
25823	 *
25824	 * @return {Object}
25825	 */
25826	AlignElements$1.prototype._alignmentPosition = function(type, sortedElements) {
25827	  var orientation = this._getOrientationDetails(type),
25828	      axis = orientation.axis,
25829	      dimension = orientation.dimension,
25830	      alignment = {},
25831	      centers = {},
25832	      hasSharedCenters = false,
25833	      centeredElements,
25834	      firstElement,
25835	      lastElement;
25836
25837	  function getMiddleOrTop(first, last) {
25838	    return Math.round((first[axis] + last[axis] + last[dimension]) / 2);
25839	  }
25840
25841	  if (this._isType(type, [ 'left', 'top' ])) {
25842	    alignment[type] = sortedElements[0][axis];
25843
25844	  } else if (this._isType(type, [ 'right', 'bottom' ])) {
25845	    lastElement = last(sortedElements);
25846
25847	    alignment[type] = lastElement[axis] + lastElement[dimension];
25848
25849	  } else if (this._isType(type, [ 'center', 'middle' ])) {
25850
25851	    // check if there is a center shared by more than one shape
25852	    // if not, just take the middle of the range
25853	    forEach(sortedElements, function(element) {
25854	      var center = element[axis] + Math.round(element[dimension] / 2);
25855
25856	      if (centers[center]) {
25857	        centers[center].elements.push(element);
25858	      } else {
25859	        centers[center] = {
25860	          elements: [ element ],
25861	          center: center
25862	        };
25863	      }
25864	    });
25865
25866	    centeredElements = sortBy(centers, function(center) {
25867	      if (center.elements.length > 1) {
25868	        hasSharedCenters = true;
25869	      }
25870
25871	      return center.elements.length;
25872	    });
25873
25874	    if (hasSharedCenters) {
25875	      alignment[type] = last(centeredElements).center;
25876
25877	      return alignment;
25878	    }
25879
25880	    firstElement = sortedElements[0];
25881
25882	    sortedElements = sortBy(sortedElements, function(element) {
25883	      return element[axis] + element[dimension];
25884	    });
25885
25886	    lastElement = last(sortedElements);
25887
25888	    alignment[type] = getMiddleOrTop(firstElement, lastElement);
25889	  }
25890
25891	  return alignment;
25892	};
25893
25894	/**
25895	 * Executes the alignment of a selection of elements
25896	 *
25897	 * @param  {Array} elements
25898	 * @param  {string} type left|right|center|top|bottom|middle
25899	 */
25900	AlignElements$1.prototype.trigger = function(elements, type) {
25901	  var modeling = this._modeling;
25902
25903	  var filteredElements = filter(elements, function(element) {
25904	    return !(element.waypoints || element.host || element.labelTarget);
25905	  });
25906
25907	  if (filteredElements.length < 2) {
25908	    return;
25909	  }
25910
25911	  var sortFn = ALIGNMENT_SORTING[type];
25912
25913	  var sortedElements = sortBy(filteredElements, sortFn);
25914
25915	  var alignment = this._alignmentPosition(type, sortedElements);
25916
25917	  modeling.alignElements(sortedElements, alignment);
25918	};
25919
25920	var AlignElementsModule = {
25921	  __init__: [ 'alignElements' ],
25922	  alignElements: [ 'type', AlignElements$1 ]
25923	};
25924
25925	// padding to detect element placement
25926	var PLACEMENT_DETECTION_PAD = 10;
25927
25928	var DEFAULT_DISTANCE = 50;
25929
25930	var DEFAULT_MAX_DISTANCE = 250;
25931
25932
25933	/**
25934	 * Get free position starting from given position.
25935	 *
25936	 * @param {djs.model.Shape} source
25937	 * @param {djs.model.Shape} element
25938	 * @param {Point} position
25939	 * @param {Function} getNextPosition
25940	 *
25941	 * @return {Point}
25942	 */
25943	function findFreePosition(source, element, position, getNextPosition) {
25944	  var connectedAtPosition;
25945
25946	  while ((connectedAtPosition = getConnectedAtPosition(source, position, element))) {
25947	    position = getNextPosition(element, position, connectedAtPosition);
25948	  }
25949
25950	  return position;
25951	}
25952
25953	/**
25954	 * Returns function that returns next position.
25955	 *
25956	 * @param {Object} nextPositionDirection
25957	 * @param {Object} [nextPositionDirection.x]
25958	 * @param {Object} [nextPositionDirection.y]
25959	 *
25960	 * @returns {Function}
25961	 */
25962	function generateGetNextPosition(nextPositionDirection) {
25963	  return function(element, previousPosition, connectedAtPosition) {
25964	    var nextPosition = {
25965	      x: previousPosition.x,
25966	      y: previousPosition.y
25967	    };
25968
25969	    [ 'x', 'y' ].forEach(function(axis) {
25970
25971	      var nextPositionDirectionForAxis = nextPositionDirection[ axis ];
25972
25973	      if (!nextPositionDirectionForAxis) {
25974	        return;
25975	      }
25976
25977	      var dimension = axis === 'x' ? 'width' : 'height';
25978
25979	      var margin = nextPositionDirectionForAxis.margin,
25980	          minDistance = nextPositionDirectionForAxis.minDistance;
25981
25982	      if (margin < 0) {
25983	        nextPosition[ axis ] = Math.min(
25984	          connectedAtPosition[ axis ] + margin - element[ dimension ] / 2,
25985	          previousPosition[ axis ] - minDistance + margin
25986	        );
25987	      } else {
25988	        nextPosition[ axis ] = Math.max(
25989	          connectedAtPosition[ axis ] + connectedAtPosition[ dimension ] + margin + element[ dimension ] / 2,
25990	          previousPosition[ axis ] + minDistance + margin
25991	        );
25992	      }
25993	    });
25994
25995	    return nextPosition;
25996	  };
25997	}
25998
25999	/**
26000	 * Return target at given position, if defined.
26001	 *
26002	 * This takes connected elements from host and attachers
26003	 * into account, too.
26004	 */
26005	function getConnectedAtPosition(source, position, element) {
26006
26007	  var bounds = {
26008	    x: position.x - (element.width / 2),
26009	    y: position.y - (element.height / 2),
26010	    width: element.width,
26011	    height: element.height
26012	  };
26013
26014	  var closure = getAutoPlaceClosure(source);
26015
26016	  return find(closure, function(target) {
26017
26018	    if (target === element) {
26019	      return false;
26020	    }
26021
26022	    var orientation = getOrientation(target, bounds, PLACEMENT_DETECTION_PAD);
26023
26024	    return orientation === 'intersect';
26025	  });
26026	}
26027
26028	/**
26029	* Compute optimal distance between source and target based on existing connections to and from source.
26030	* Assumes left-to-right and top-to-down modeling.
26031	*
26032	* @param {djs.model.Shape} source
26033	* @param {Object} [hints]
26034	* @param {number} [hints.defaultDistance]
26035	* @param {string} [hints.direction]
26036	* @param {Function} [hints.filter]
26037	* @param {Function} [hints.getWeight]
26038	* @param {number} [hints.maxDistance]
26039	* @param {string} [hints.reference]
26040	*
26041	* @return {number}
26042	*/
26043	function getConnectedDistance(source, hints) {
26044	  if (!hints) {
26045	    hints = {};
26046	  }
26047
26048	  // targets > sources by default
26049	  function getDefaultWeight(connection) {
26050	    return connection.source === source ? 1 : -1;
26051	  }
26052
26053	  var defaultDistance = hints.defaultDistance || DEFAULT_DISTANCE,
26054	      direction = hints.direction || 'e',
26055	      filter = hints.filter,
26056	      getWeight = hints.getWeight || getDefaultWeight,
26057	      maxDistance = hints.maxDistance || DEFAULT_MAX_DISTANCE,
26058	      reference = hints.reference || 'start';
26059
26060	  if (!filter) {
26061	    filter = noneFilter;
26062	  }
26063
26064	  function getDistance(a, b) {
26065	    if (direction === 'n') {
26066	      if (reference === 'start') {
26067	        return asTRBL(a).top - asTRBL(b).bottom;
26068	      } else if (reference === 'center') {
26069	        return asTRBL(a).top - getMid(b).y;
26070	      } else {
26071	        return asTRBL(a).top - asTRBL(b).top;
26072	      }
26073	    } else if (direction === 'w') {
26074	      if (reference === 'start') {
26075	        return asTRBL(a).left - asTRBL(b).right;
26076	      } else if (reference === 'center') {
26077	        return asTRBL(a).left - getMid(b).x;
26078	      } else {
26079	        return asTRBL(a).left - asTRBL(b).left;
26080	      }
26081	    } else if (direction === 's') {
26082	      if (reference === 'start') {
26083	        return asTRBL(b).top - asTRBL(a).bottom;
26084	      } else if (reference === 'center') {
26085	        return getMid(b).y - asTRBL(a).bottom;
26086	      } else {
26087	        return asTRBL(b).bottom - asTRBL(a).bottom;
26088	      }
26089	    } else {
26090	      if (reference === 'start') {
26091	        return asTRBL(b).left - asTRBL(a).right;
26092	      } else if (reference === 'center') {
26093	        return getMid(b).x - asTRBL(a).right;
26094	      } else {
26095	        return asTRBL(b).right - asTRBL(a).right;
26096	      }
26097	    }
26098	  }
26099
26100	  var sourcesDistances = source.incoming
26101	    .filter(filter)
26102	    .map(function(connection) {
26103	      var weight = getWeight(connection);
26104
26105	      var distance = weight < 0
26106	        ? getDistance(connection.source, source)
26107	        : getDistance(source, connection.source);
26108
26109	      return {
26110	        id: connection.source.id,
26111	        distance: distance,
26112	        weight: weight
26113	      };
26114	    });
26115
26116	  var targetsDistances = source.outgoing
26117	    .filter(filter)
26118	    .map(function(connection) {
26119	      var weight = getWeight(connection);
26120
26121	      var distance = weight > 0
26122	        ? getDistance(source, connection.target)
26123	        : getDistance(connection.target, source);
26124
26125	      return {
26126	        id: connection.target.id,
26127	        distance: distance,
26128	        weight: weight
26129	      };
26130	    });
26131
26132	  var distances = sourcesDistances.concat(targetsDistances).reduce(function(accumulator, currentValue) {
26133	    accumulator[ currentValue.id + '__weight_' + currentValue.weight ] = currentValue;
26134
26135	    return accumulator;
26136	  }, {});
26137
26138	  var distancesGrouped = reduce(distances, function(accumulator, currentValue) {
26139	    var distance = currentValue.distance,
26140	        weight = currentValue.weight;
26141
26142	    if (distance < 0 || distance > maxDistance) {
26143	      return accumulator;
26144	    }
26145
26146	    if (!accumulator[ String(distance) ]) {
26147	      accumulator[ String(distance) ] = 0;
26148	    }
26149
26150	    accumulator[ String(distance) ] += 1 * weight;
26151
26152	    if (!accumulator.distance || accumulator[ accumulator.distance ] < accumulator[ String(distance) ]) {
26153	      accumulator.distance = distance;
26154	    }
26155
26156	    return accumulator;
26157	  }, {});
26158
26159	  return distancesGrouped.distance || defaultDistance;
26160	}
26161
26162	/**
26163	 * Returns all connected elements around the given source.
26164	 *
26165	 * This includes:
26166	 *
26167	 *   - connected elements
26168	 *   - host connected elements
26169	 *   - attachers connected elements
26170	 *
26171	 * @param  {djs.model.Shape} source
26172	 *
26173	 * @return {Array<djs.model.Shape>}
26174	 */
26175	function getAutoPlaceClosure(source) {
26176
26177	  var allConnected = getConnected(source);
26178
26179	  if (source.host) {
26180	    allConnected = allConnected.concat(getConnected(source.host));
26181	  }
26182
26183	  if (source.attachers) {
26184	    allConnected = allConnected.concat(source.attachers.reduce(function(shapes, attacher) {
26185	      return shapes.concat(getConnected(attacher));
26186	    }, []));
26187	  }
26188
26189	  return allConnected;
26190	}
26191
26192	function getConnected(element) {
26193	  return getTargets(element).concat(getSources(element));
26194	}
26195
26196	function getSources(shape) {
26197	  return shape.incoming.map(function(connection) {
26198	    return connection.source;
26199	  });
26200	}
26201
26202	function getTargets(shape) {
26203	  return shape.outgoing.map(function(connection) {
26204	    return connection.target;
26205	  });
26206	}
26207
26208	function noneFilter() {
26209	  return true;
26210	}
26211
26212	var LOW_PRIORITY$i = 100;
26213
26214
26215	/**
26216	 * A service that places elements connected to existing ones
26217	 * to an appropriate position in an _automated_ fashion.
26218	 *
26219	 * @param {EventBus} eventBus
26220	 * @param {Modeling} modeling
26221	 */
26222	function AutoPlace$1(eventBus, modeling, canvas) {
26223
26224	  eventBus.on('autoPlace', LOW_PRIORITY$i, function(context) {
26225	    var shape = context.shape,
26226	        source = context.source;
26227
26228	    return getNewShapePosition$1(source, shape);
26229	  });
26230
26231	  eventBus.on('autoPlace.end', function(event) {
26232	    canvas.scrollToElement(event.shape);
26233	  });
26234
26235	  /**
26236	   * Append shape to source at appropriate position.
26237	   *
26238	   * @param {djs.model.Shape} source
26239	   * @param {djs.model.Shape} shape
26240	   *
26241	   * @return {djs.model.Shape} appended shape
26242	   */
26243	  this.append = function(source, shape, hints) {
26244
26245	    eventBus.fire('autoPlace.start', {
26246	      source: source,
26247	      shape: shape
26248	    });
26249
26250	    // allow others to provide the position
26251	    var position = eventBus.fire('autoPlace', {
26252	      source: source,
26253	      shape: shape
26254	    });
26255
26256	    var newShape = modeling.appendShape(source, shape, position, source.parent, hints);
26257
26258	    eventBus.fire('autoPlace.end', {
26259	      source: source,
26260	      shape: newShape
26261	    });
26262
26263	    return newShape;
26264	  };
26265
26266	}
26267
26268	AutoPlace$1.$inject = [
26269	  'eventBus',
26270	  'modeling',
26271	  'canvas'
26272	];
26273
26274	// helpers //////////
26275
26276	/**
26277	 * Find the new position for the target element to
26278	 * connect to source.
26279	 *
26280	 * @param  {djs.model.Shape} source
26281	 * @param  {djs.model.Shape} element
26282	 * @param  {Object} [hints]
26283	 * @param  {Object} [hints.defaultDistance]
26284	 *
26285	 * @returns {Point}
26286	 */
26287	function getNewShapePosition$1(source, element, hints) {
26288	  if (!hints) {
26289	    hints = {};
26290	  }
26291
26292	  var distance = hints.defaultDistance || DEFAULT_DISTANCE;
26293
26294	  var sourceMid = getMid(source),
26295	      sourceTrbl = asTRBL(source);
26296
26297	  // simply put element right next to source
26298	  return {
26299	    x: sourceTrbl.right + distance + element.width / 2,
26300	    y: sourceMid.y
26301	  };
26302	}
26303
26304	/**
26305	 * Select element after auto placement.
26306	 *
26307	 * @param {EventBus} eventBus
26308	 * @param {Selection} selection
26309	 */
26310	function AutoPlaceSelectionBehavior(eventBus, selection) {
26311
26312	  eventBus.on('autoPlace.end', 500, function(e) {
26313	    selection.select(e.shape);
26314	  });
26315
26316	}
26317
26318	AutoPlaceSelectionBehavior.$inject = [
26319	  'eventBus',
26320	  'selection'
26321	];
26322
26323	var AutoPlaceModule$1 = {
26324	  __init__: [ 'autoPlaceSelectionBehavior' ],
26325	  autoPlace: [ 'type', AutoPlace$1 ],
26326	  autoPlaceSelectionBehavior: [ 'type', AutoPlaceSelectionBehavior ]
26327	};
26328
26329	/**
26330	 * Return true if element has any of the given types.
26331	 *
26332	 * @param {djs.model.Base} element
26333	 * @param {Array<string>} types
26334	 *
26335	 * @return {boolean}
26336	 */
26337	function isAny(element, types) {
26338	  return some(types, function(t) {
26339	    return is$1(element, t);
26340	  });
26341	}
26342
26343
26344	/**
26345	 * Return the parent of the element with any of the given types.
26346	 *
26347	 * @param {djs.model.Base} element
26348	 * @param {string|Array<string>} anyType
26349	 *
26350	 * @return {djs.model.Base}
26351	 */
26352	function getParent(element, anyType) {
26353
26354	  if (typeof anyType === 'string') {
26355	    anyType = [ anyType ];
26356	  }
26357
26358	  while ((element = element.parent)) {
26359	    if (isAny(element, anyType)) {
26360	      return element;
26361	    }
26362	  }
26363
26364	  return null;
26365	}
26366
26367	/**
26368	 * Find the new position for the target element to
26369	 * connect to source.
26370	 *
26371	 * @param  {djs.model.Shape} source
26372	 * @param  {djs.model.Shape} element
26373	 *
26374	 * @return {Point}
26375	 */
26376	function getNewShapePosition(source, element) {
26377
26378	  if (is$1(element, 'bpmn:TextAnnotation')) {
26379	    return getTextAnnotationPosition(source, element);
26380	  }
26381
26382	  if (isAny(element, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
26383	    return getDataElementPosition(source, element);
26384	  }
26385
26386	  if (is$1(element, 'bpmn:FlowNode')) {
26387	    return getFlowNodePosition(source, element);
26388	  }
26389	}
26390
26391	/**
26392	 * Always try to place element right of source;
26393	 * compute actual distance from previous nodes in flow.
26394	 */
26395	function getFlowNodePosition(source, element) {
26396
26397	  var sourceTrbl = asTRBL(source);
26398	  var sourceMid = getMid(source);
26399
26400	  var horizontalDistance = getConnectedDistance(source, {
26401	    filter: function(connection) {
26402	      return is$1(connection, 'bpmn:SequenceFlow');
26403	    }
26404	  });
26405
26406	  var margin = 30,
26407	      minDistance = 80,
26408	      orientation = 'left';
26409
26410	  if (is$1(source, 'bpmn:BoundaryEvent')) {
26411	    orientation = getOrientation(source, source.host, -25);
26412
26413	    if (orientation.indexOf('top') !== -1) {
26414	      margin *= -1;
26415	    }
26416	  }
26417
26418	  var position = {
26419	    x: sourceTrbl.right + horizontalDistance + element.width / 2,
26420	    y: sourceMid.y + getVerticalDistance(orientation, minDistance)
26421	  };
26422
26423	  var nextPositionDirection = {
26424	    y: {
26425	      margin: margin,
26426	      minDistance: minDistance
26427	    }
26428	  };
26429
26430	  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
26431	}
26432
26433
26434	function getVerticalDistance(orientation, minDistance) {
26435	  if (orientation.indexOf('top') != -1) {
26436	    return -1 * minDistance;
26437	  } else if (orientation.indexOf('bottom') != -1) {
26438	    return minDistance;
26439	  } else {
26440	    return 0;
26441	  }
26442	}
26443
26444
26445	/**
26446	 * Always try to place text annotations top right of source.
26447	 */
26448	function getTextAnnotationPosition(source, element) {
26449
26450	  var sourceTrbl = asTRBL(source);
26451
26452	  var position = {
26453	    x: sourceTrbl.right + element.width / 2,
26454	    y: sourceTrbl.top - 50 - element.height / 2
26455	  };
26456
26457	  var nextPositionDirection = {
26458	    y: {
26459	      margin: -30,
26460	      minDistance: 20
26461	    }
26462	  };
26463
26464	  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
26465	}
26466
26467
26468	/**
26469	 * Always put element bottom right of source.
26470	 */
26471	function getDataElementPosition(source, element) {
26472
26473	  var sourceTrbl = asTRBL(source);
26474
26475	  var position = {
26476	    x: sourceTrbl.right - 10 + element.width / 2,
26477	    y: sourceTrbl.bottom + 40 + element.width / 2
26478	  };
26479
26480	  var nextPositionDirection = {
26481	    x: {
26482	      margin: 30,
26483	      minDistance: 30
26484	    }
26485	  };
26486
26487	  return findFreePosition(source, element, position, generateGetNextPosition(nextPositionDirection));
26488	}
26489
26490	/**
26491	 * BPMN auto-place behavior.
26492	 *
26493	 * @param {EventBus} eventBus
26494	 */
26495	function AutoPlace(eventBus) {
26496	  eventBus.on('autoPlace', function(context) {
26497	    var shape = context.shape,
26498	        source = context.source;
26499
26500	    return getNewShapePosition(source, shape);
26501	  });
26502	}
26503
26504	AutoPlace.$inject = [ 'eventBus' ];
26505
26506	var AutoPlaceModule = {
26507	  __depends__: [ AutoPlaceModule$1 ],
26508	  __init__: [ 'bpmnAutoPlace' ],
26509	  bpmnAutoPlace: [ 'type', AutoPlace ]
26510	};
26511
26512	var DEFAULT_PRIORITY$3 = 1000;
26513
26514	/**
26515	 * A utility that can be used to plug-in into the command execution for
26516	 * extension and/or validation.
26517	 *
26518	 * @param {EventBus} eventBus
26519	 *
26520	 * @example
26521	 *
26522	 * import inherits from 'inherits';
26523	 *
26524	 * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
26525	 *
26526	 * function CommandLogger(eventBus) {
26527	 *   CommandInterceptor.call(this, eventBus);
26528	 *
26529	 *   this.preExecute(function(event) {
26530	 *     console.log('command pre-execute', event);
26531	 *   });
26532	 * }
26533	 *
26534	 * inherits(CommandLogger, CommandInterceptor);
26535	 *
26536	 */
26537	function CommandInterceptor(eventBus) {
26538	  this._eventBus = eventBus;
26539	}
26540
26541	CommandInterceptor.$inject = [ 'eventBus' ];
26542
26543	function unwrapEvent(fn, that) {
26544	  return function(event) {
26545	    return fn.call(that || null, event.context, event.command, event);
26546	  };
26547	}
26548
26549	/**
26550	 * Register an interceptor for a command execution
26551	 *
26552	 * @param {string|Array<string>} [events] list of commands to register on
26553	 * @param {string} [hook] command hook, i.e. preExecute, executed to listen on
26554	 * @param {number} [priority] the priority on which to hook into the execution
26555	 * @param {Function} handlerFn interceptor to be invoked with (event)
26556	 * @param {boolean} unwrap if true, unwrap the event and pass (context, command, event) to the
26557	 *                          listener instead
26558	 * @param {Object} [that] Pass context (`this`) to the handler function
26559	 */
26560	CommandInterceptor.prototype.on = function(events, hook, priority, handlerFn, unwrap, that) {
26561
26562	  if (isFunction(hook) || isNumber(hook)) {
26563	    that = unwrap;
26564	    unwrap = handlerFn;
26565	    handlerFn = priority;
26566	    priority = hook;
26567	    hook = null;
26568	  }
26569
26570	  if (isFunction(priority)) {
26571	    that = unwrap;
26572	    unwrap = handlerFn;
26573	    handlerFn = priority;
26574	    priority = DEFAULT_PRIORITY$3;
26575	  }
26576
26577	  if (isObject(unwrap)) {
26578	    that = unwrap;
26579	    unwrap = false;
26580	  }
26581
26582	  if (!isFunction(handlerFn)) {
26583	    throw new Error('handlerFn must be a function');
26584	  }
26585
26586	  if (!isArray$2(events)) {
26587	    events = [ events ];
26588	  }
26589
26590	  var eventBus = this._eventBus;
26591
26592	  forEach(events, function(event) {
26593
26594	    // concat commandStack(.event)?(.hook)?
26595	    var fullEvent = [ 'commandStack', event, hook ].filter(function(e) { return e; }).join('.');
26596
26597	    eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that);
26598	  });
26599	};
26600
26601
26602	var hooks = [
26603	  'canExecute',
26604	  'preExecute',
26605	  'preExecuted',
26606	  'execute',
26607	  'executed',
26608	  'postExecute',
26609	  'postExecuted',
26610	  'revert',
26611	  'reverted'
26612	];
26613
26614	/*
26615	 * Install hook shortcuts
26616	 *
26617	 * This will generate the CommandInterceptor#(preExecute|...|reverted) methods
26618	 * which will in term forward to CommandInterceptor#on.
26619	 */
26620	forEach(hooks, function(hook) {
26621
26622	  /**
26623	   * {canExecute|preExecute|preExecuted|execute|executed|postExecute|postExecuted|revert|reverted}
26624	   *
26625	   * A named hook for plugging into the command execution
26626	   *
26627	   * @param {string|Array<string>} [events] list of commands to register on
26628	   * @param {number} [priority] the priority on which to hook into the execution
26629	   * @param {Function} handlerFn interceptor to be invoked with (event)
26630	   * @param {boolean} [unwrap=false] if true, unwrap the event and pass (context, command, event) to the
26631	   *                          listener instead
26632	   * @param {Object} [that] Pass context (`this`) to the handler function
26633	   */
26634	  CommandInterceptor.prototype[hook] = function(events, priority, handlerFn, unwrap, that) {
26635
26636	    if (isFunction(events) || isNumber(events)) {
26637	      that = unwrap;
26638	      unwrap = handlerFn;
26639	      handlerFn = priority;
26640	      priority = events;
26641	      events = null;
26642	    }
26643
26644	    this.on(events, hook, priority, handlerFn, unwrap, that);
26645	  };
26646	});
26647
26648	/**
26649	 * An auto resize component that takes care of expanding a parent element
26650	 * if child elements are created or moved close the parents edge.
26651	 *
26652	 * @param {EventBus} eventBus
26653	 * @param {ElementRegistry} elementRegistry
26654	 * @param {Modeling} modeling
26655	 * @param {Rules} rules
26656	 */
26657	function AutoResize(eventBus, elementRegistry, modeling, rules) {
26658
26659	  CommandInterceptor.call(this, eventBus);
26660
26661	  this._elementRegistry = elementRegistry;
26662	  this._modeling = modeling;
26663	  this._rules = rules;
26664
26665	  var self = this;
26666
26667	  this.postExecuted([ 'shape.create' ], function(event) {
26668	    var context = event.context,
26669	        hints = context.hints || {},
26670	        shape = context.shape,
26671	        parent = context.parent || context.newParent;
26672
26673	    if (hints.autoResize === false) {
26674	      return;
26675	    }
26676
26677	    self._expand([ shape ], parent);
26678	  });
26679
26680	  this.postExecuted([ 'elements.move' ], function(event) {
26681	    var context = event.context,
26682	        elements = flatten(values(context.closure.topLevel)),
26683	        hints = context.hints;
26684
26685	    var autoResize = hints ? hints.autoResize : true;
26686
26687	    if (autoResize === false) {
26688	      return;
26689	    }
26690
26691	    var expandings = groupBy(elements, function(element) {
26692	      return element.parent.id;
26693	    });
26694
26695	    forEach(expandings, function(elements, parentId) {
26696
26697	      // optionally filter elements to be considered when resizing
26698	      if (isArray$2(autoResize)) {
26699	        elements = elements.filter(function(element) {
26700	          return find(autoResize, matchPattern({ id: element.id }));
26701	        });
26702	      }
26703
26704	      self._expand(elements, parentId);
26705	    });
26706	  });
26707
26708	  this.postExecuted([ 'shape.toggleCollapse' ], function(event) {
26709	    var context = event.context,
26710	        hints = context.hints,
26711	        shape = context.shape;
26712
26713	    if (hints && hints.autoResize === false) {
26714	      return;
26715	    }
26716
26717	    if (shape.collapsed) {
26718	      return;
26719	    }
26720
26721	    self._expand(shape.children || [], shape);
26722	  });
26723
26724	  this.postExecuted([ 'shape.resize' ], function(event) {
26725	    var context = event.context,
26726	        hints = context.hints,
26727	        shape = context.shape,
26728	        parent = shape.parent;
26729
26730	    if (hints && hints.autoResize === false) {
26731	      return;
26732	    }
26733
26734	    if (parent) {
26735	      self._expand([ shape ], parent);
26736	    }
26737	  });
26738
26739	}
26740
26741	AutoResize.$inject = [
26742	  'eventBus',
26743	  'elementRegistry',
26744	  'modeling',
26745	  'rules'
26746	];
26747
26748	inherits$1(AutoResize, CommandInterceptor);
26749
26750
26751	/**
26752	 * Calculate the new bounds of the target shape, given
26753	 * a number of elements have been moved or added into the parent.
26754	 *
26755	 * This method considers the current size, the added elements as well as
26756	 * the provided padding for the new bounds.
26757	 *
26758	 * @param {Array<djs.model.Shape>} elements
26759	 * @param {djs.model.Shape} target
26760	 */
26761	AutoResize.prototype._getOptimalBounds = function(elements, target) {
26762
26763	  var offset = this.getOffset(target),
26764	      padding = this.getPadding(target);
26765
26766	  var elementsTrbl = asTRBL(getBBox(elements)),
26767	      targetTrbl = asTRBL(target);
26768
26769	  var newTrbl = {};
26770
26771	  if (elementsTrbl.top - targetTrbl.top < padding.top) {
26772	    newTrbl.top = elementsTrbl.top - offset.top;
26773	  }
26774
26775	  if (elementsTrbl.left - targetTrbl.left < padding.left) {
26776	    newTrbl.left = elementsTrbl.left - offset.left;
26777	  }
26778
26779	  if (targetTrbl.right - elementsTrbl.right < padding.right) {
26780	    newTrbl.right = elementsTrbl.right + offset.right;
26781	  }
26782
26783	  if (targetTrbl.bottom - elementsTrbl.bottom < padding.bottom) {
26784	    newTrbl.bottom = elementsTrbl.bottom + offset.bottom;
26785	  }
26786
26787	  return asBounds(assign({}, targetTrbl, newTrbl));
26788	};
26789
26790
26791	/**
26792	 * Expand the target shape respecting rules, offset and padding
26793	 *
26794	 * @param {Array<djs.model.Shape>} elements
26795	 * @param {djs.model.Shape|string} target|targetId
26796	 */
26797	AutoResize.prototype._expand = function(elements, target) {
26798
26799	  if (typeof target === 'string') {
26800	    target = this._elementRegistry.get(target);
26801	  }
26802
26803	  var allowed = this._rules.allowed('element.autoResize', {
26804	    elements: elements,
26805	    target: target
26806	  });
26807
26808	  if (!allowed) {
26809	    return;
26810	  }
26811
26812	  // calculate the new bounds
26813	  var newBounds = this._getOptimalBounds(elements, target);
26814
26815	  if (!boundsChanged$1(newBounds, target)) {
26816	    return;
26817	  }
26818
26819	  var resizeDirections = getResizeDirections(pick(target, [ 'x', 'y', 'width', 'height' ]), newBounds);
26820
26821	  // resize the parent shape
26822	  this.resize(target, newBounds, {
26823	    autoResize: resizeDirections
26824	  });
26825
26826	  var parent = target.parent;
26827
26828	  // recursively expand parent elements
26829	  if (parent) {
26830	    this._expand([ target ], parent);
26831	  }
26832	};
26833
26834
26835	/**
26836	 * Get the amount to expand the given shape in each direction.
26837	 *
26838	 * @param {djs.model.Shape} shape
26839	 *
26840	 * @return {TRBL}
26841	 */
26842	AutoResize.prototype.getOffset = function(shape) {
26843	  return { top: 60, bottom: 60, left: 100, right: 100 };
26844	};
26845
26846
26847	/**
26848	 * Get the activation threshold for each side for which
26849	 * resize triggers.
26850	 *
26851	 * @param {djs.model.Shape} shape
26852	 *
26853	 * @return {TRBL}
26854	 */
26855	AutoResize.prototype.getPadding = function(shape) {
26856	  return { top: 2, bottom: 2, left: 15, right: 15 };
26857	};
26858
26859
26860	/**
26861	 * Perform the actual resize operation.
26862	 *
26863	 * @param {djs.model.Shape} shape
26864	 * @param {Bounds} newBounds
26865	 * @param {Object} [hints]
26866	 * @param {string} [hints.autoResize]
26867	 */
26868	AutoResize.prototype.resize = function(shape, newBounds, hints) {
26869	  this._modeling.resizeShape(shape, newBounds, null, hints);
26870	};
26871
26872
26873	function boundsChanged$1(newBounds, oldBounds) {
26874	  return (
26875	    newBounds.x !== oldBounds.x ||
26876	    newBounds.y !== oldBounds.y ||
26877	    newBounds.width !== oldBounds.width ||
26878	    newBounds.height !== oldBounds.height
26879	  );
26880	}
26881
26882	/**
26883	 * Get directions of resize as {n|w|s|e} e.g. "nw".
26884	 *
26885	 * @param {Bounds} oldBounds
26886	 * @param {Bounds} newBounds
26887	 *
26888	 * @returns {string} Resize directions as {n|w|s|e}.
26889	 */
26890	function getResizeDirections(oldBounds, newBounds) {
26891	  var directions = '';
26892
26893	  oldBounds = asTRBL(oldBounds);
26894	  newBounds = asTRBL(newBounds);
26895
26896	  if (oldBounds.top > newBounds.top) {
26897	    directions = directions.concat('n');
26898	  }
26899
26900	  if (oldBounds.right < newBounds.right) {
26901	    directions = directions.concat('w');
26902	  }
26903
26904	  if (oldBounds.bottom < newBounds.bottom) {
26905	    directions = directions.concat('s');
26906	  }
26907
26908	  if (oldBounds.left > newBounds.left) {
26909	    directions = directions.concat('e');
26910	  }
26911
26912	  return directions;
26913	}
26914
26915	/**
26916	 * Sub class of the AutoResize module which implements a BPMN
26917	 * specific resize function.
26918	 */
26919	function BpmnAutoResize(injector) {
26920
26921	  injector.invoke(AutoResize, this);
26922	}
26923
26924	BpmnAutoResize.$inject = [
26925	  'injector'
26926	];
26927
26928	inherits$1(BpmnAutoResize, AutoResize);
26929
26930
26931	/**
26932	 * Resize shapes and lanes.
26933	 *
26934	 * @param {djs.model.Shape} target
26935	 * @param {Bounds} newBounds
26936	 * @param {Object} hints
26937	 */
26938	BpmnAutoResize.prototype.resize = function(target, newBounds, hints) {
26939
26940	  if (is$1(target, 'bpmn:Participant')) {
26941	    this._modeling.resizeLane(target, newBounds, null, hints);
26942	  } else {
26943	    this._modeling.resizeShape(target, newBounds, null, hints);
26944	  }
26945	};
26946
26947	/**
26948	 * A basic provider that may be extended to implement modeling rules.
26949	 *
26950	 * Extensions should implement the init method to actually add their custom
26951	 * modeling checks. Checks may be added via the #addRule(action, fn) method.
26952	 *
26953	 * @param {EventBus} eventBus
26954	 */
26955	function RuleProvider(eventBus) {
26956	  CommandInterceptor.call(this, eventBus);
26957
26958	  this.init();
26959	}
26960
26961	RuleProvider.$inject = [ 'eventBus' ];
26962
26963	inherits$1(RuleProvider, CommandInterceptor);
26964
26965
26966	/**
26967	 * Adds a modeling rule for the given action, implemented through
26968	 * a callback function.
26969	 *
26970	 * The function will receive the modeling specific action context
26971	 * to perform its check. It must return `false` to disallow the
26972	 * action from happening or `true` to allow the action.
26973	 *
26974	 * A rule provider may pass over the evaluation to lower priority
26975	 * rules by returning return nothing (or <code>undefined</code>).
26976	 *
26977	 * @example
26978	 *
26979	 * ResizableRules.prototype.init = function() {
26980	 *
26981	 *   \/**
26982	 *    * Return `true`, `false` or nothing to denote
26983	 *    * _allowed_, _not allowed_ and _continue evaluating_.
26984	 *    *\/
26985	 *   this.addRule('shape.resize', function(context) {
26986	 *
26987	 *     var shape = context.shape;
26988	 *
26989	 *     if (!context.newBounds) {
26990	 *       // check general resizability
26991	 *       if (!shape.resizable) {
26992	 *         return false;
26993	 *       }
26994	 *
26995	 *       // not returning anything (read: undefined)
26996	 *       // will continue the evaluation of other rules
26997	 *       // (with lower priority)
26998	 *       return;
26999	 *     } else {
27000	 *       // element must have minimum size of 10*10 points
27001	 *       return context.newBounds.width > 10 && context.newBounds.height > 10;
27002	 *     }
27003	 *   });
27004	 * };
27005	 *
27006	 * @param {string|Array<string>} actions the identifier for the modeling action to check
27007	 * @param {number} [priority] the priority at which this rule is being applied
27008	 * @param {Function} fn the callback function that performs the actual check
27009	 */
27010	RuleProvider.prototype.addRule = function(actions, priority, fn) {
27011
27012	  var self = this;
27013
27014	  if (typeof actions === 'string') {
27015	    actions = [ actions ];
27016	  }
27017
27018	  actions.forEach(function(action) {
27019
27020	    self.canExecute(action, priority, function(context, action, event) {
27021	      return fn(context);
27022	    }, true);
27023	  });
27024	};
27025
27026	/**
27027	 * Implement this method to add new rules during provider initialization.
27028	 */
27029	RuleProvider.prototype.init = function() {};
27030
27031	/**
27032	 * This is a base rule provider for the element.autoResize rule.
27033	 */
27034	function AutoResizeProvider(eventBus) {
27035
27036	  RuleProvider.call(this, eventBus);
27037
27038	  var self = this;
27039
27040	  this.addRule('element.autoResize', function(context) {
27041	    return self.canResize(context.elements, context.target);
27042	  });
27043	}
27044
27045	AutoResizeProvider.$inject = [ 'eventBus' ];
27046
27047	inherits$1(AutoResizeProvider, RuleProvider);
27048
27049	/**
27050	 * Needs to be implemented by sub classes to allow actual auto resize
27051	 *
27052	 * @param  {Array<djs.model.Shape>} elements
27053	 * @param  {djs.model.Shape} target
27054	 *
27055	 * @return {boolean}
27056	 */
27057	AutoResizeProvider.prototype.canResize = function(elements, target) {
27058	  return false;
27059	};
27060
27061	/**
27062	 * This module is a provider for automatically resizing parent BPMN elements
27063	 */
27064	function BpmnAutoResizeProvider(eventBus, modeling) {
27065	  AutoResizeProvider.call(this, eventBus);
27066
27067	  this._modeling = modeling;
27068	}
27069
27070	inherits$1(BpmnAutoResizeProvider, AutoResizeProvider);
27071
27072	BpmnAutoResizeProvider.$inject = [
27073	  'eventBus',
27074	  'modeling'
27075	];
27076
27077
27078	/**
27079	 * Check if the given target can be expanded
27080	 *
27081	 * @param  {djs.model.Shape} target
27082	 *
27083	 * @return {boolean}
27084	 */
27085	BpmnAutoResizeProvider.prototype.canResize = function(elements, target) {
27086
27087	  if (!is$1(target, 'bpmn:Participant') && !is$1(target, 'bpmn:Lane') && !(is$1(target, 'bpmn:SubProcess'))) {
27088	    return false;
27089	  }
27090
27091	  var canResize = true;
27092
27093	  forEach(elements, function(element) {
27094
27095	    if (is$1(element, 'bpmn:Lane') || element.labelTarget) {
27096	      canResize = false;
27097	      return;
27098	    }
27099	  });
27100
27101	  return canResize;
27102	};
27103
27104	var AutoResizeModule = {
27105	  __init__: [
27106	    'bpmnAutoResize',
27107	    'bpmnAutoResizeProvider'
27108	  ],
27109	  bpmnAutoResize: [ 'type', BpmnAutoResize ],
27110	  bpmnAutoResizeProvider: [ 'type', BpmnAutoResizeProvider ]
27111	};
27112
27113	var HIGH_PRIORITY$j = 1500;
27114
27115
27116	/**
27117	 * Browsers may swallow certain events (hover, out ...) if users are to
27118	 * fast with the mouse.
27119	 *
27120	 * @see http://stackoverflow.com/questions/7448468/why-cant-i-reliably-capture-a-mouseout-event
27121	 *
27122	 * The fix implemented in this component ensure that we
27123	 *
27124	 * 1) have a hover state after a successful drag.move event
27125	 * 2) have an out event when dragging leaves an element
27126	 *
27127	 * @param {ElementRegistry} elementRegistry
27128	 * @param {EventBus} eventBus
27129	 * @param {Injector} injector
27130	 */
27131	function HoverFix(elementRegistry, eventBus, injector) {
27132
27133	  var self = this;
27134
27135	  var dragging = injector.get('dragging', false);
27136
27137	  /**
27138	   * Make sure we are god damn hovering!
27139	   *
27140	   * @param {Event} dragging event
27141	   */
27142	  function ensureHover(event) {
27143
27144	    if (event.hover) {
27145	      return;
27146	    }
27147
27148	    var originalEvent = event.originalEvent;
27149
27150	    var gfx = self._findTargetGfx(originalEvent);
27151
27152	    var element = gfx && elementRegistry.get(gfx);
27153
27154	    if (gfx && element) {
27155
27156	      // 1) cancel current mousemove
27157	      event.stopPropagation();
27158
27159	      // 2) emit fake hover for new target
27160	      dragging.hover({ element: element, gfx: gfx });
27161
27162	      // 3) re-trigger move event
27163	      dragging.move(originalEvent);
27164	    }
27165	  }
27166
27167
27168	  if (dragging) {
27169
27170	    /**
27171	     * We wait for a specific sequence of events before
27172	     * emitting a fake drag.hover event.
27173	     *
27174	     * Event Sequence:
27175	     *
27176	     * drag.start
27177	     * drag.move >> ensure we are hovering
27178	     */
27179	    eventBus.on('drag.start', function(event) {
27180
27181	      eventBus.once('drag.move', HIGH_PRIORITY$j, function(event) {
27182
27183	        ensureHover(event);
27184
27185	      });
27186
27187	    });
27188	  }
27189
27190
27191	  /**
27192	   * We make sure that element.out is always fired, even if the
27193	   * browser swallows an element.out event.
27194	   *
27195	   * Event sequence:
27196	   *
27197	   * element.hover
27198	   * (element.out >> sometimes swallowed)
27199	   * element.hover >> ensure we fired element.out
27200	   */
27201	  (function() {
27202	    var hoverGfx;
27203	    var hover;
27204
27205	    eventBus.on('element.hover', function(event) {
27206
27207	      // (1) remember current hover element
27208	      hoverGfx = event.gfx;
27209	      hover = event.element;
27210	    });
27211
27212	    eventBus.on('element.hover', HIGH_PRIORITY$j, function(event) {
27213
27214	      // (3) am I on an element still?
27215	      if (hover) {
27216
27217	        // (4) that is a problem, gotta "simulate the out"
27218	        eventBus.fire('element.out', {
27219	          element: hover,
27220	          gfx: hoverGfx
27221	        });
27222	      }
27223
27224	    });
27225
27226	    eventBus.on('element.out', function() {
27227
27228	      // (2) unset hover state if we correctly outed us *GG*
27229	      hoverGfx = null;
27230	      hover = null;
27231	    });
27232
27233	  })();
27234
27235	  this._findTargetGfx = function(event) {
27236	    var position,
27237	        target;
27238
27239	    if (!(event instanceof MouseEvent)) {
27240	      return;
27241	    }
27242
27243	    position = toPoint(event);
27244
27245	    // damn expensive operation, ouch!
27246	    target = document.elementFromPoint(position.x, position.y);
27247
27248	    return getGfx(target);
27249	  };
27250
27251	}
27252
27253	HoverFix.$inject = [
27254	  'elementRegistry',
27255	  'eventBus',
27256	  'injector'
27257	];
27258
27259
27260	// helpers /////////////////////
27261
27262	function getGfx(target) {
27263	  return closest(target, 'svg, .djs-element', true);
27264	}
27265
27266	var HoverFixModule = {
27267	  __init__: [
27268	    'hoverFix'
27269	  ],
27270	  hoverFix: [ 'type', HoverFix ],
27271	};
27272
27273	var round$a = Math.round;
27274
27275	var DRAG_ACTIVE_CLS = 'djs-drag-active';
27276
27277
27278	function preventDefault$1(event) {
27279	  event.preventDefault();
27280	}
27281
27282	function isTouchEvent(event) {
27283
27284	  // check for TouchEvent being available first
27285	  // (i.e. not available on desktop Firefox)
27286	  return typeof TouchEvent !== 'undefined' && event instanceof TouchEvent;
27287	}
27288
27289	function getLength(point) {
27290	  return Math.sqrt(Math.pow(point.x, 2) + Math.pow(point.y, 2));
27291	}
27292
27293	/**
27294	 * A helper that fires canvas localized drag events and realizes
27295	 * the general "drag-and-drop" look and feel.
27296	 *
27297	 * Calling {@link Dragging#activate} activates dragging on a canvas.
27298	 *
27299	 * It provides the following:
27300	 *
27301	 *   * emits life cycle events, namespaced with a prefix assigned
27302	 *     during dragging activation
27303	 *   * sets and restores the cursor
27304	 *   * sets and restores the selection if elements still exist
27305	 *   * ensures there can be only one drag operation active at a time
27306	 *
27307	 * Dragging may be canceled manually by calling {@link Dragging#cancel}
27308	 * or by pressing ESC.
27309	 *
27310	 *
27311	 * ## Life-cycle events
27312	 *
27313	 * Dragging can be in three different states, off, initialized
27314	 * and active.
27315	 *
27316	 * (1) off: no dragging operation is in progress
27317	 * (2) initialized: a new drag operation got initialized but not yet
27318	 *                  started (i.e. because of no initial move)
27319	 * (3) started: dragging is in progress
27320	 *
27321	 * Eventually dragging will be off again after a drag operation has
27322	 * been ended or canceled via user click or ESC key press.
27323	 *
27324	 * To indicate transitions between these states dragging emits generic
27325	 * life-cycle events with the `drag.` prefix _and_ events namespaced
27326	 * to a prefix choosen by a user during drag initialization.
27327	 *
27328	 * The following events are emitted (appropriately prefixed) via
27329	 * the {@link EventBus}.
27330	 *
27331	 * * `init`
27332	 * * `start`
27333	 * * `move`
27334	 * * `end`
27335	 * * `ended` (dragging already in off state)
27336	 * * `cancel` (only if previously started)
27337	 * * `canceled` (dragging already in off state, only if previously started)
27338	 * * `cleanup`
27339	 *
27340	 *
27341	 * @example
27342	 *
27343	 * function MyDragComponent(eventBus, dragging) {
27344	 *
27345	 *   eventBus.on('mydrag.start', function(event) {
27346	 *     console.log('yes, we start dragging');
27347	 *   });
27348	 *
27349	 *   eventBus.on('mydrag.move', function(event) {
27350	 *     console.log('canvas local coordinates', event.x, event.y, event.dx, event.dy);
27351	 *
27352	 *     // local drag data is passed with the event
27353	 *     event.context.foo; // "BAR"
27354	 *
27355	 *     // the original mouse event, too
27356	 *     event.originalEvent; // MouseEvent(...)
27357	 *   });
27358	 *
27359	 *   eventBus.on('element.click', function(event) {
27360	 *     dragging.init(event, 'mydrag', {
27361	 *       cursor: 'grabbing',
27362	 *       data: {
27363	 *         context: {
27364	 *           foo: "BAR"
27365	 *         }
27366	 *       }
27367	 *     });
27368	 *   });
27369	 * }
27370	 */
27371	function Dragging(eventBus, canvas, selection, elementRegistry) {
27372
27373	  var defaultOptions = {
27374	    threshold: 5,
27375	    trapClick: true
27376	  };
27377
27378	  // the currently active drag operation
27379	  // dragging is active as soon as this context exists.
27380	  //
27381	  // it is visually _active_ only when a context.active flag is set to true.
27382	  var context;
27383
27384	  /* convert a global event into local coordinates */
27385	  function toLocalPoint(globalPosition) {
27386
27387	    var viewbox = canvas.viewbox();
27388
27389	    var clientRect = canvas._container.getBoundingClientRect();
27390
27391	    return {
27392	      x: viewbox.x + (globalPosition.x - clientRect.left) / viewbox.scale,
27393	      y: viewbox.y + (globalPosition.y - clientRect.top) / viewbox.scale
27394	    };
27395	  }
27396
27397	  // helpers
27398
27399	  function fire(type, dragContext) {
27400	    dragContext = dragContext || context;
27401
27402	    var event = eventBus.createEvent(
27403	      assign(
27404	        {},
27405	        dragContext.payload,
27406	        dragContext.data,
27407	        { isTouch: dragContext.isTouch }
27408	      )
27409	    );
27410
27411	    // default integration
27412	    if (eventBus.fire('drag.' + type, event) === false) {
27413	      return false;
27414	    }
27415
27416	    return eventBus.fire(dragContext.prefix + '.' + type, event);
27417	  }
27418
27419	  function restoreSelection(previousSelection) {
27420	    var existingSelection = previousSelection.filter(function(element) {
27421	      return elementRegistry.get(element.id);
27422	    });
27423
27424	    existingSelection.length && selection.select(existingSelection);
27425	  }
27426
27427	  // event listeners
27428
27429	  function move(event, activate) {
27430	    var payload = context.payload,
27431	        displacement = context.displacement;
27432
27433	    var globalStart = context.globalStart,
27434	        globalCurrent = toPoint(event),
27435	        globalDelta = delta(globalCurrent, globalStart);
27436
27437	    var localStart = context.localStart,
27438	        localCurrent = toLocalPoint(globalCurrent),
27439	        localDelta = delta(localCurrent, localStart);
27440
27441
27442	    // activate context explicitly or once threshold is reached
27443	    if (!context.active && (activate || getLength(globalDelta) > context.threshold)) {
27444
27445	      // fire start event with original
27446	      // starting coordinates
27447
27448	      assign(payload, {
27449	        x: round$a(localStart.x + displacement.x),
27450	        y: round$a(localStart.y + displacement.y),
27451	        dx: 0,
27452	        dy: 0
27453	      }, { originalEvent: event });
27454
27455	      if (false === fire('start')) {
27456	        return cancel();
27457	      }
27458
27459	      context.active = true;
27460
27461	      // unset selection and remember old selection
27462	      // the previous (old) selection will always passed
27463	      // with the event via the event.previousSelection property
27464	      if (!context.keepSelection) {
27465	        payload.previousSelection = selection.get();
27466	        selection.select(null);
27467	      }
27468
27469	      // allow custom cursor
27470	      if (context.cursor) {
27471	        set(context.cursor);
27472	      }
27473
27474	      // indicate dragging via marker on root element
27475	      canvas.addMarker(canvas.getRootElement(), DRAG_ACTIVE_CLS);
27476	    }
27477
27478	    stopPropagation$1(event);
27479
27480	    if (context.active) {
27481
27482	      // update payload with actual coordinates
27483	      assign(payload, {
27484	        x: round$a(localCurrent.x + displacement.x),
27485	        y: round$a(localCurrent.y + displacement.y),
27486	        dx: round$a(localDelta.x),
27487	        dy: round$a(localDelta.y)
27488	      }, { originalEvent: event });
27489
27490	      // emit move event
27491	      fire('move');
27492	    }
27493	  }
27494
27495	  function end(event) {
27496	    var previousContext,
27497	        returnValue = true;
27498
27499	    if (context.active) {
27500
27501	      if (event) {
27502	        context.payload.originalEvent = event;
27503
27504	        // suppress original event (click, ...)
27505	        // because we just ended a drag operation
27506	        stopPropagation$1(event);
27507	      }
27508
27509	      // implementations may stop restoring the
27510	      // original state (selections, ...) by preventing the
27511	      // end events default action
27512	      returnValue = fire('end');
27513	    }
27514
27515	    if (returnValue === false) {
27516	      fire('rejected');
27517	    }
27518
27519	    previousContext = cleanup(returnValue !== true);
27520
27521	    // last event to be fired when all drag operations are done
27522	    // at this point in time no drag operation is in progress anymore
27523	    fire('ended', previousContext);
27524	  }
27525
27526
27527	  // cancel active drag operation if the user presses
27528	  // the ESC key on the keyboard
27529
27530	  function checkCancel(event) {
27531
27532	    if (event.which === 27) {
27533	      preventDefault$1(event);
27534
27535	      cancel();
27536	    }
27537	  }
27538
27539
27540	  // prevent ghost click that might occur after a finished
27541	  // drag and drop session
27542
27543	  function trapClickAndEnd(event) {
27544
27545	    var untrap;
27546
27547	    // trap the click in case we are part of an active
27548	    // drag operation. This will effectively prevent
27549	    // the ghost click that cannot be canceled otherwise.
27550	    if (context.active) {
27551
27552	      untrap = install(eventBus);
27553
27554	      // remove trap after minimal delay
27555	      setTimeout(untrap, 400);
27556
27557	      // prevent default action (click)
27558	      preventDefault$1(event);
27559	    }
27560
27561	    end(event);
27562	  }
27563
27564	  function trapTouch(event) {
27565	    move(event);
27566	  }
27567
27568	  // update the drag events hover (djs.model.Base) and hoverGfx (Snap<SVGElement>)
27569	  // properties during hover and out and fire {prefix}.hover and {prefix}.out properties
27570	  // respectively
27571
27572	  function hover(event) {
27573	    var payload = context.payload;
27574
27575	    payload.hoverGfx = event.gfx;
27576	    payload.hover = event.element;
27577
27578	    fire('hover');
27579	  }
27580
27581	  function out(event) {
27582	    fire('out');
27583
27584	    var payload = context.payload;
27585
27586	    payload.hoverGfx = null;
27587	    payload.hover = null;
27588	  }
27589
27590
27591	  // life-cycle methods
27592
27593	  function cancel(restore) {
27594	    var previousContext;
27595
27596	    if (!context) {
27597	      return;
27598	    }
27599
27600	    var wasActive = context.active;
27601
27602	    if (wasActive) {
27603	      fire('cancel');
27604	    }
27605
27606	    previousContext = cleanup(restore);
27607
27608	    if (wasActive) {
27609
27610	      // last event to be fired when all drag operations are done
27611	      // at this point in time no drag operation is in progress anymore
27612	      fire('canceled', previousContext);
27613	    }
27614	  }
27615
27616	  function cleanup(restore) {
27617	    var previousContext,
27618	        endDrag;
27619
27620	    fire('cleanup');
27621
27622	    // reset cursor
27623	    unset();
27624
27625	    if (context.trapClick) {
27626	      endDrag = trapClickAndEnd;
27627	    } else {
27628	      endDrag = end;
27629	    }
27630
27631	    // reset dom listeners
27632	    componentEvent.unbind(document, 'mousemove', move);
27633
27634	    componentEvent.unbind(document, 'dragstart', preventDefault$1);
27635	    componentEvent.unbind(document, 'selectstart', preventDefault$1);
27636
27637	    componentEvent.unbind(document, 'mousedown', endDrag, true);
27638	    componentEvent.unbind(document, 'mouseup', endDrag, true);
27639
27640	    componentEvent.unbind(document, 'keyup', checkCancel);
27641
27642	    componentEvent.unbind(document, 'touchstart', trapTouch, true);
27643	    componentEvent.unbind(document, 'touchcancel', cancel, true);
27644	    componentEvent.unbind(document, 'touchmove', move, true);
27645	    componentEvent.unbind(document, 'touchend', end, true);
27646
27647	    eventBus.off('element.hover', hover);
27648	    eventBus.off('element.out', out);
27649
27650	    // remove drag marker on root element
27651	    canvas.removeMarker(canvas.getRootElement(), DRAG_ACTIVE_CLS);
27652
27653	    // restore selection, unless it has changed
27654	    var previousSelection = context.payload.previousSelection;
27655
27656	    if (restore !== false && previousSelection && !selection.get().length) {
27657	      restoreSelection(previousSelection);
27658	    }
27659
27660	    previousContext = context;
27661
27662	    context = null;
27663
27664	    return previousContext;
27665	  }
27666
27667	  /**
27668	   * Initialize a drag operation.
27669	   *
27670	   * If `localPosition` is given, drag events will be emitted
27671	   * relative to it.
27672	   *
27673	   * @param {MouseEvent|TouchEvent} [event]
27674	   * @param {Point} [localPosition] actual diagram local position this drag operation should start at
27675	   * @param {string} prefix
27676	   * @param {Object} [options]
27677	   */
27678	  function init(event, relativeTo, prefix, options) {
27679
27680	    // only one drag operation may be active, at a time
27681	    if (context) {
27682	      cancel(false);
27683	    }
27684
27685	    if (typeof relativeTo === 'string') {
27686	      options = prefix;
27687	      prefix = relativeTo;
27688	      relativeTo = null;
27689	    }
27690
27691	    options = assign({}, defaultOptions, options || {});
27692
27693	    var data = options.data || {},
27694	        originalEvent,
27695	        globalStart,
27696	        localStart,
27697	        endDrag,
27698	        isTouch;
27699
27700	    if (options.trapClick) {
27701	      endDrag = trapClickAndEnd;
27702	    } else {
27703	      endDrag = end;
27704	    }
27705
27706	    if (event) {
27707	      originalEvent = getOriginal$1(event) || event;
27708	      globalStart = toPoint(event);
27709
27710	      stopPropagation$1(event);
27711
27712	      // prevent default browser dragging behavior
27713	      if (originalEvent.type === 'dragstart') {
27714	        preventDefault$1(originalEvent);
27715	      }
27716	    } else {
27717	      originalEvent = null;
27718	      globalStart = { x: 0, y: 0 };
27719	    }
27720
27721	    localStart = toLocalPoint(globalStart);
27722
27723	    if (!relativeTo) {
27724	      relativeTo = localStart;
27725	    }
27726
27727	    isTouch = isTouchEvent(originalEvent);
27728
27729	    context = assign({
27730	      prefix: prefix,
27731	      data: data,
27732	      payload: {},
27733	      globalStart: globalStart,
27734	      displacement: delta(relativeTo, localStart),
27735	      localStart: localStart,
27736	      isTouch: isTouch
27737	    }, options);
27738
27739	    // skip dom registration if trigger
27740	    // is set to manual (during testing)
27741	    if (!options.manual) {
27742
27743	      // add dom listeners
27744
27745	      if (isTouch) {
27746	        componentEvent.bind(document, 'touchstart', trapTouch, true);
27747	        componentEvent.bind(document, 'touchcancel', cancel, true);
27748	        componentEvent.bind(document, 'touchmove', move, true);
27749	        componentEvent.bind(document, 'touchend', end, true);
27750	      } else {
27751
27752	        // assume we use the mouse to interact per default
27753	        componentEvent.bind(document, 'mousemove', move);
27754
27755	        // prevent default browser drag and text selection behavior
27756	        componentEvent.bind(document, 'dragstart', preventDefault$1);
27757	        componentEvent.bind(document, 'selectstart', preventDefault$1);
27758
27759	        componentEvent.bind(document, 'mousedown', endDrag, true);
27760	        componentEvent.bind(document, 'mouseup', endDrag, true);
27761	      }
27762
27763	      componentEvent.bind(document, 'keyup', checkCancel);
27764
27765	      eventBus.on('element.hover', hover);
27766	      eventBus.on('element.out', out);
27767	    }
27768
27769	    fire('init');
27770
27771	    if (options.autoActivate) {
27772	      move(event, true);
27773	    }
27774	  }
27775
27776	  // cancel on diagram destruction
27777	  eventBus.on('diagram.destroy', cancel);
27778
27779
27780	  // API
27781
27782	  this.init = init;
27783	  this.move = move;
27784	  this.hover = hover;
27785	  this.out = out;
27786	  this.end = end;
27787
27788	  this.cancel = cancel;
27789
27790	  // for introspection
27791
27792	  this.context = function() {
27793	    return context;
27794	  };
27795
27796	  this.setOptions = function(options) {
27797	    assign(defaultOptions, options);
27798	  };
27799	}
27800
27801	Dragging.$inject = [
27802	  'eventBus',
27803	  'canvas',
27804	  'selection',
27805	  'elementRegistry'
27806	];
27807
27808	var DraggingModule = {
27809	  __depends__: [
27810	    HoverFixModule,
27811	    SelectionModule,
27812	  ],
27813	  dragging: [ 'type', Dragging ],
27814	};
27815
27816	/**
27817	 * Initiates canvas scrolling if current cursor point is close to a border.
27818	 * Cancelled when current point moves back inside the scrolling borders
27819	 * or cancelled manually.
27820	 *
27821	 * Default options :
27822	 *   scrollThresholdIn: [ 20, 20, 20, 20 ],
27823	 *   scrollThresholdOut: [ 0, 0, 0, 0 ],
27824	 *   scrollRepeatTimeout: 15,
27825	 *   scrollStep: 10
27826	 *
27827	 * Threshold order:
27828	 *   [ left, top, right, bottom ]
27829	 */
27830	function AutoScroll(config, eventBus, canvas) {
27831
27832	  this._canvas = canvas;
27833
27834	  this._opts = assign({
27835	    scrollThresholdIn: [ 20, 20, 20, 20 ],
27836	    scrollThresholdOut: [ 0, 0, 0, 0 ],
27837	    scrollRepeatTimeout: 15,
27838	    scrollStep: 10
27839	  }, config);
27840
27841	  var self = this;
27842
27843	  eventBus.on('drag.move', function(e) {
27844	    var point = self._toBorderPoint(e);
27845
27846	    self.startScroll(point);
27847	  });
27848
27849	  eventBus.on([ 'drag.cleanup' ], function() {
27850	    self.stopScroll();
27851	  });
27852	}
27853
27854	AutoScroll.$inject = [
27855	  'config.autoScroll',
27856	  'eventBus',
27857	  'canvas'
27858	];
27859
27860
27861	/**
27862	 * Starts scrolling loop.
27863	 * Point is given in global scale in canvas container box plane.
27864	 *
27865	 * @param  {Object} point { x: X, y: Y }
27866	 */
27867	AutoScroll.prototype.startScroll = function(point) {
27868
27869	  var canvas = this._canvas;
27870	  var opts = this._opts;
27871	  var self = this;
27872
27873	  var clientRect = canvas.getContainer().getBoundingClientRect();
27874
27875	  var diff = [
27876	    point.x,
27877	    point.y,
27878	    clientRect.width - point.x,
27879	    clientRect.height - point.y
27880	  ];
27881
27882	  this.stopScroll();
27883
27884	  var dx = 0,
27885	      dy = 0;
27886
27887	  for (var i = 0; i < 4; i++) {
27888	    if (between(diff[i], opts.scrollThresholdOut[i], opts.scrollThresholdIn[i])) {
27889	      if (i === 0) {
27890	        dx = opts.scrollStep;
27891	      } else if (i == 1) {
27892	        dy = opts.scrollStep;
27893	      } else if (i == 2) {
27894	        dx = -opts.scrollStep;
27895	      } else if (i == 3) {
27896	        dy = -opts.scrollStep;
27897	      }
27898	    }
27899	  }
27900
27901	  if (dx !== 0 || dy !== 0) {
27902	    canvas.scroll({ dx: dx, dy: dy });
27903
27904	    this._scrolling = setTimeout(function() {
27905	      self.startScroll(point);
27906	    }, opts.scrollRepeatTimeout);
27907	  }
27908	};
27909
27910	function between(val, start, end) {
27911	  if (start < val && val < end) {
27912	    return true;
27913	  }
27914
27915	  return false;
27916	}
27917
27918
27919	/**
27920	 * Stops scrolling loop.
27921	 */
27922	AutoScroll.prototype.stopScroll = function() {
27923	  clearTimeout(this._scrolling);
27924	};
27925
27926
27927	/**
27928	 * Overrides defaults options.
27929	 *
27930	 * @param  {Object} options
27931	 */
27932	AutoScroll.prototype.setOptions = function(options) {
27933	  this._opts = assign({}, this._opts, options);
27934	};
27935
27936
27937	/**
27938	 * Converts event to a point in canvas container plane in global scale.
27939	 *
27940	 * @param  {Event} event
27941	 * @return {Point}
27942	 */
27943	AutoScroll.prototype._toBorderPoint = function(event) {
27944	  var clientRect = this._canvas._container.getBoundingClientRect();
27945
27946	  var globalPosition = toPoint(event.originalEvent);
27947
27948	  return {
27949	    x: globalPosition.x - clientRect.left,
27950	    y: globalPosition.y - clientRect.top
27951	  };
27952	};
27953
27954	var AutoScrollModule = {
27955	  __depends__: [
27956	    DraggingModule,
27957	  ],
27958	  __init__: [ 'autoScroll' ],
27959	  autoScroll: [ 'type', AutoScroll ]
27960	};
27961
27962	/**
27963	 * A service that provides rules for certain diagram actions.
27964	 *
27965	 * The default implementation will hook into the {@link CommandStack}
27966	 * to perform the actual rule evaluation. Make sure to provide the
27967	 * `commandStack` service with this module if you plan to use it.
27968	 *
27969	 * Together with this implementation you may use the {@link RuleProvider}
27970	 * to implement your own rule checkers.
27971	 *
27972	 * This module is ment to be easily replaced, thus the tiny foot print.
27973	 *
27974	 * @param {Injector} injector
27975	 */
27976	function Rules(injector) {
27977	  this._commandStack = injector.get('commandStack', false);
27978	}
27979
27980	Rules.$inject = [ 'injector' ];
27981
27982
27983	/**
27984	 * Returns whether or not a given modeling action can be executed
27985	 * in the specified context.
27986	 *
27987	 * This implementation will respond with allow unless anyone
27988	 * objects.
27989	 *
27990	 * @param {string} action the action to be checked
27991	 * @param {Object} [context] the context to check the action in
27992	 *
27993	 * @return {boolean} returns true, false or null depending on whether the
27994	 *                   operation is allowed, not allowed or should be ignored.
27995	 */
27996	Rules.prototype.allowed = function(action, context) {
27997	  var allowed = true;
27998
27999	  var commandStack = this._commandStack;
28000
28001	  if (commandStack) {
28002	    allowed = commandStack.canExecute(action, context);
28003	  }
28004
28005	  // map undefined to true, i.e. no rules
28006	  return allowed === undefined ? true : allowed;
28007	};
28008
28009	var RulesModule$1 = {
28010	  __init__: [ 'rules' ],
28011	  rules: [ 'type', Rules ]
28012	};
28013
28014	var round$9 = Math.round,
28015	    max$6 = Math.max;
28016
28017
28018	function circlePath(center, r) {
28019	  var x = center.x,
28020	      y = center.y;
28021
28022	  return [
28023	    ['M', x, y],
28024	    ['m', 0, -r],
28025	    ['a', r, r, 0, 1, 1, 0, 2 * r],
28026	    ['a', r, r, 0, 1, 1, 0, -2 * r],
28027	    ['z']
28028	  ];
28029	}
28030
28031	function linePath(points) {
28032	  var segments = [];
28033
28034	  points.forEach(function(p, idx) {
28035	    segments.push([ idx === 0 ? 'M' : 'L', p.x, p.y ]);
28036	  });
28037
28038	  return segments;
28039	}
28040
28041
28042	var INTERSECTION_THRESHOLD$1 = 10;
28043
28044	function getBendpointIntersection(waypoints, reference) {
28045
28046	  var i, w;
28047
28048	  for (i = 0; (w = waypoints[i]); i++) {
28049
28050	    if (pointDistance(w, reference) <= INTERSECTION_THRESHOLD$1) {
28051	      return {
28052	        point: waypoints[i],
28053	        bendpoint: true,
28054	        index: i
28055	      };
28056	    }
28057	  }
28058
28059	  return null;
28060	}
28061
28062	function getPathIntersection(waypoints, reference) {
28063
28064	  var intersections = intersect(circlePath(reference, INTERSECTION_THRESHOLD$1), linePath(waypoints));
28065
28066	  var a = intersections[0],
28067	      b = intersections[intersections.length - 1],
28068	      idx;
28069
28070	  if (!a) {
28071
28072	    // no intersection
28073	    return null;
28074	  }
28075
28076	  if (a !== b) {
28077
28078	    if (a.segment2 !== b.segment2) {
28079
28080	      // we use the bendpoint in between both segments
28081	      // as the intersection point
28082
28083	      idx = max$6(a.segment2, b.segment2) - 1;
28084
28085	      return {
28086	        point: waypoints[idx],
28087	        bendpoint: true,
28088	        index: idx
28089	      };
28090	    }
28091
28092	    return {
28093	      point: {
28094	        x: (round$9(a.x + b.x) / 2),
28095	        y: (round$9(a.y + b.y) / 2)
28096	      },
28097	      index: a.segment2
28098	    };
28099	  }
28100
28101	  return {
28102	    point: {
28103	      x: round$9(a.x),
28104	      y: round$9(a.y)
28105	    },
28106	    index: a.segment2
28107	  };
28108	}
28109
28110	/**
28111	 * Returns the closest point on the connection towards a given reference point.
28112	 *
28113	 * @param  {Array<Point>} waypoints
28114	 * @param  {Point} reference
28115	 *
28116	 * @return {Object} intersection data (segment, point)
28117	 */
28118	function getApproxIntersection(waypoints, reference) {
28119	  return getBendpointIntersection(waypoints, reference) || getPathIntersection(waypoints, reference);
28120	}
28121
28122	var BENDPOINT_CLS = 'djs-bendpoint';
28123	var SEGMENT_DRAGGER_CLS = 'djs-segment-dragger';
28124
28125	function toCanvasCoordinates(canvas, event) {
28126
28127	  var position = toPoint(event),
28128	      clientRect = canvas._container.getBoundingClientRect(),
28129	      offset;
28130
28131	  // canvas relative position
28132
28133	  offset = {
28134	    x: clientRect.left,
28135	    y: clientRect.top
28136	  };
28137
28138	  // update actual event payload with canvas relative measures
28139
28140	  var viewbox = canvas.viewbox();
28141
28142	  return {
28143	    x: viewbox.x + (position.x - offset.x) / viewbox.scale,
28144	    y: viewbox.y + (position.y - offset.y) / viewbox.scale
28145	  };
28146	}
28147
28148	function getConnectionIntersection(canvas, waypoints, event) {
28149	  var localPosition = toCanvasCoordinates(canvas, event),
28150	      intersection = getApproxIntersection(waypoints, localPosition);
28151
28152	  return intersection;
28153	}
28154
28155	function addBendpoint(parentGfx, cls) {
28156	  var groupGfx = create$1('g');
28157	  classes(groupGfx).add(BENDPOINT_CLS);
28158
28159	  append(parentGfx, groupGfx);
28160
28161	  var visual = create$1('circle');
28162	  attr(visual, {
28163	    cx: 0,
28164	    cy: 0,
28165	    r: 4
28166	  });
28167	  classes(visual).add('djs-visual');
28168
28169	  append(groupGfx, visual);
28170
28171	  var hit = create$1('circle');
28172	  attr(hit, {
28173	    cx: 0,
28174	    cy: 0,
28175	    r: 10
28176	  });
28177	  classes(hit).add('djs-hit');
28178
28179	  append(groupGfx, hit);
28180
28181	  if (cls) {
28182	    classes(groupGfx).add(cls);
28183	  }
28184
28185	  return groupGfx;
28186	}
28187
28188	function createParallelDragger(parentGfx, segmentStart, segmentEnd, alignment) {
28189	  var draggerGfx = create$1('g');
28190
28191	  append(parentGfx, draggerGfx);
28192
28193	  var width = 14,
28194	      height = 3,
28195	      padding = 11,
28196	      hitWidth = calculateHitWidth(segmentStart, segmentEnd, alignment),
28197	      hitHeight = height + padding;
28198
28199	  var visual = create$1('rect');
28200	  attr(visual, {
28201	    x: -width / 2,
28202	    y: -height / 2,
28203	    width: width,
28204	    height: height
28205	  });
28206	  classes(visual).add('djs-visual');
28207
28208	  append(draggerGfx, visual);
28209
28210	  var hit = create$1('rect');
28211	  attr(hit, {
28212	    x: -hitWidth / 2,
28213	    y: -hitHeight / 2,
28214	    width: hitWidth,
28215	    height: hitHeight
28216	  });
28217	  classes(hit).add('djs-hit');
28218
28219	  append(draggerGfx, hit);
28220
28221	  rotate(draggerGfx, alignment === 'v' ? 90 : 0);
28222
28223	  return draggerGfx;
28224	}
28225
28226
28227	function addSegmentDragger(parentGfx, segmentStart, segmentEnd) {
28228
28229	  var groupGfx = create$1('g'),
28230	      mid = getMidPoint(segmentStart, segmentEnd),
28231	      alignment = pointsAligned(segmentStart, segmentEnd);
28232
28233	  append(parentGfx, groupGfx);
28234
28235	  createParallelDragger(groupGfx, segmentStart, segmentEnd, alignment);
28236
28237	  classes(groupGfx).add(SEGMENT_DRAGGER_CLS);
28238	  classes(groupGfx).add(alignment === 'h' ? 'horizontal' : 'vertical');
28239
28240	  translate$2(groupGfx, mid.x, mid.y);
28241
28242	  return groupGfx;
28243	}
28244
28245	/**
28246	 * Calculates region for segment move which is 2/3 of the full segment length
28247	 * @param {number} segmentLength
28248	 *
28249	 * @return {number}
28250	 */
28251	function calculateSegmentMoveRegion(segmentLength) {
28252	  return Math.abs(Math.round(segmentLength * 2 / 3));
28253	}
28254
28255	// helper //////////
28256
28257	function calculateHitWidth(segmentStart, segmentEnd, alignment) {
28258	  var segmentLengthXAxis = segmentEnd.x - segmentStart.x,
28259	      segmentLengthYAxis = segmentEnd.y - segmentStart.y;
28260
28261	  return alignment === 'h' ?
28262	    calculateSegmentMoveRegion(segmentLengthXAxis) :
28263	    calculateSegmentMoveRegion(segmentLengthYAxis);
28264	}
28265
28266	var css_escape = {exports: {}};
28267
28268	/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
28269
28270	(function (module, exports) {
28271	(function(root, factory) {
28272		// https://github.com/umdjs/umd/blob/master/returnExports.js
28273		{
28274			// For Node.js.
28275			module.exports = factory(root);
28276		}
28277	}(typeof commonjsGlobal != 'undefined' ? commonjsGlobal : commonjsGlobal, function(root) {
28278
28279		if (root.CSS && root.CSS.escape) {
28280			return root.CSS.escape;
28281		}
28282
28283		// https://drafts.csswg.org/cssom/#serialize-an-identifier
28284		var cssEscape = function(value) {
28285			if (arguments.length == 0) {
28286				throw new TypeError('`CSS.escape` requires an argument.');
28287			}
28288			var string = String(value);
28289			var length = string.length;
28290			var index = -1;
28291			var codeUnit;
28292			var result = '';
28293			var firstCodeUnit = string.charCodeAt(0);
28294			while (++index < length) {
28295				codeUnit = string.charCodeAt(index);
28296				// Note: there’s no need to special-case astral symbols, surrogate
28297				// pairs, or lone surrogates.
28298
28299				// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
28300				// (U+FFFD).
28301				if (codeUnit == 0x0000) {
28302					result += '\uFFFD';
28303					continue;
28304				}
28305
28306				if (
28307					// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
28308					// U+007F, […]
28309					(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
28310					// If the character is the first character and is in the range [0-9]
28311					// (U+0030 to U+0039), […]
28312					(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
28313					// If the character is the second character and is in the range [0-9]
28314					// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
28315					(
28316						index == 1 &&
28317						codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
28318						firstCodeUnit == 0x002D
28319					)
28320				) {
28321					// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
28322					result += '\\' + codeUnit.toString(16) + ' ';
28323					continue;
28324				}
28325
28326				if (
28327					// If the character is the first character and is a `-` (U+002D), and
28328					// there is no second character, […]
28329					index == 0 &&
28330					length == 1 &&
28331					codeUnit == 0x002D
28332				) {
28333					result += '\\' + string.charAt(index);
28334					continue;
28335				}
28336
28337				// If the character is not handled by one of the above rules and is
28338				// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
28339				// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
28340				// U+005A), or [a-z] (U+0061 to U+007A), […]
28341				if (
28342					codeUnit >= 0x0080 ||
28343					codeUnit == 0x002D ||
28344					codeUnit == 0x005F ||
28345					codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
28346					codeUnit >= 0x0041 && codeUnit <= 0x005A ||
28347					codeUnit >= 0x0061 && codeUnit <= 0x007A
28348				) {
28349					// the character itself
28350					result += string.charAt(index);
28351					continue;
28352				}
28353
28354				// Otherwise, the escaped character.
28355				// https://drafts.csswg.org/cssom/#escape-a-character
28356				result += '\\' + string.charAt(index);
28357
28358			}
28359			return result;
28360		};
28361
28362		if (!root.CSS) {
28363			root.CSS = {};
28364		}
28365
28366		root.CSS.escape = cssEscape;
28367		return cssEscape;
28368
28369	}));
28370	}(css_escape));
28371
28372	var cssEscape = css_escape.exports;
28373
28374	var HTML_ESCAPE_MAP = {
28375	  '&': '&amp;',
28376	  '<': '&lt;',
28377	  '>': '&gt;',
28378	  '"': '&quot;',
28379	  '\'': '&#39;'
28380	};
28381
28382	function escapeHTML(str) {
28383	  str = '' + str;
28384
28385	  return str && str.replace(/[&<>"']/g, function(match) {
28386	    return HTML_ESCAPE_MAP[match];
28387	  });
28388	}
28389
28390	/**
28391	 * A service that adds editable bendpoints to connections.
28392	 */
28393	function Bendpoints(
28394	    eventBus, canvas, interactionEvents,
28395	    bendpointMove, connectionSegmentMove) {
28396
28397	  /**
28398	   * Returns true if intersection point is inside middle region of segment, adjusted by
28399	   * optional threshold
28400	   */
28401	  function isIntersectionMiddle(intersection, waypoints, treshold) {
28402	    var idx = intersection.index,
28403	        p = intersection.point,
28404	        p0, p1, mid, aligned, xDelta, yDelta;
28405
28406	    if (idx <= 0 || intersection.bendpoint) {
28407	      return false;
28408	    }
28409
28410	    p0 = waypoints[idx - 1];
28411	    p1 = waypoints[idx];
28412	    mid = getMidPoint(p0, p1),
28413	    aligned = pointsAligned(p0, p1);
28414	    xDelta = Math.abs(p.x - mid.x);
28415	    yDelta = Math.abs(p.y - mid.y);
28416
28417	    return aligned && xDelta <= treshold && yDelta <= treshold;
28418	  }
28419
28420	  /**
28421	   * Calculates the threshold from a connection's middle which fits the two-third-region
28422	   */
28423	  function calculateIntersectionThreshold(connection, intersection) {
28424	    var waypoints = connection.waypoints,
28425	        relevantSegment, alignment, segmentLength, threshold;
28426
28427	    if (intersection.index <= 0 || intersection.bendpoint) {
28428	      return null;
28429	    }
28430
28431	    // segment relative to connection intersection
28432	    relevantSegment = {
28433	      start: waypoints[intersection.index - 1],
28434	      end: waypoints[intersection.index]
28435	    };
28436
28437	    alignment = pointsAligned(relevantSegment.start, relevantSegment.end);
28438
28439	    if (!alignment) {
28440	      return null;
28441	    }
28442
28443	    if (alignment === 'h') {
28444	      segmentLength = relevantSegment.end.x - relevantSegment.start.x;
28445	    } else {
28446	      segmentLength = relevantSegment.end.y - relevantSegment.start.y;
28447	    }
28448
28449	    // calculate threshold relative to 2/3 of segment length
28450	    threshold = calculateSegmentMoveRegion(segmentLength) / 2;
28451
28452	    return threshold;
28453	  }
28454
28455	  function activateBendpointMove(event, connection) {
28456	    var waypoints = connection.waypoints,
28457	        intersection = getConnectionIntersection(canvas, waypoints, event),
28458	        threshold;
28459
28460	    if (!intersection) {
28461	      return;
28462	    }
28463
28464	    threshold = calculateIntersectionThreshold(connection, intersection);
28465
28466	    if (isIntersectionMiddle(intersection, waypoints, threshold)) {
28467	      connectionSegmentMove.start(event, connection, intersection.index);
28468	    } else {
28469	      bendpointMove.start(event, connection, intersection.index, !intersection.bendpoint);
28470	    }
28471
28472	    // we've handled the event
28473	    return true;
28474	  }
28475
28476	  function bindInteractionEvents(node, eventName, element) {
28477
28478	    componentEvent.bind(node, eventName, function(event) {
28479	      interactionEvents.triggerMouseEvent(eventName, event, element);
28480	      event.stopPropagation();
28481	    });
28482	  }
28483
28484	  function getBendpointsContainer(element, create) {
28485
28486	    var layer = canvas.getLayer('overlays'),
28487	        gfx = query('.djs-bendpoints[data-element-id="' + cssEscape(element.id) + '"]', layer);
28488
28489	    if (!gfx && create) {
28490	      gfx = create$1('g');
28491	      attr(gfx, { 'data-element-id': element.id });
28492	      classes(gfx).add('djs-bendpoints');
28493
28494	      append(layer, gfx);
28495
28496	      bindInteractionEvents(gfx, 'mousedown', element);
28497	      bindInteractionEvents(gfx, 'click', element);
28498	      bindInteractionEvents(gfx, 'dblclick', element);
28499	    }
28500
28501	    return gfx;
28502	  }
28503
28504	  function getSegmentDragger(idx, parentGfx) {
28505	    return query(
28506	      '.djs-segment-dragger[data-segment-idx="' + idx + '"]',
28507	      parentGfx
28508	    );
28509	  }
28510
28511	  function createBendpoints(gfx, connection) {
28512	    connection.waypoints.forEach(function(p, idx) {
28513	      var bendpoint = addBendpoint(gfx);
28514
28515	      append(gfx, bendpoint);
28516
28517	      translate$2(bendpoint, p.x, p.y);
28518	    });
28519
28520	    // add floating bendpoint
28521	    addBendpoint(gfx, 'floating');
28522	  }
28523
28524	  function createSegmentDraggers(gfx, connection) {
28525
28526	    var waypoints = connection.waypoints;
28527
28528	    var segmentStart,
28529	        segmentEnd,
28530	        segmentDraggerGfx;
28531
28532	    for (var i = 1; i < waypoints.length; i++) {
28533
28534	      segmentStart = waypoints[i - 1];
28535	      segmentEnd = waypoints[i];
28536
28537	      if (pointsAligned(segmentStart, segmentEnd)) {
28538	        segmentDraggerGfx = addSegmentDragger(gfx, segmentStart, segmentEnd);
28539
28540	        attr(segmentDraggerGfx, { 'data-segment-idx': i });
28541
28542	        bindInteractionEvents(segmentDraggerGfx, 'mousemove', connection);
28543	      }
28544	    }
28545	  }
28546
28547	  function clearBendpoints(gfx) {
28548	    forEach(all('.' + BENDPOINT_CLS, gfx), function(node) {
28549	      remove$1(node);
28550	    });
28551	  }
28552
28553	  function clearSegmentDraggers(gfx) {
28554	    forEach(all('.' + SEGMENT_DRAGGER_CLS, gfx), function(node) {
28555	      remove$1(node);
28556	    });
28557	  }
28558
28559	  function addHandles(connection) {
28560
28561	    var gfx = getBendpointsContainer(connection);
28562
28563	    if (!gfx) {
28564	      gfx = getBendpointsContainer(connection, true);
28565
28566	      createBendpoints(gfx, connection);
28567	      createSegmentDraggers(gfx, connection);
28568	    }
28569
28570	    return gfx;
28571	  }
28572
28573	  function updateHandles(connection) {
28574
28575	    var gfx = getBendpointsContainer(connection);
28576
28577	    if (gfx) {
28578	      clearSegmentDraggers(gfx);
28579	      clearBendpoints(gfx);
28580	      createSegmentDraggers(gfx, connection);
28581	      createBendpoints(gfx, connection);
28582	    }
28583	  }
28584
28585	  function updateFloatingBendpointPosition(parentGfx, intersection) {
28586	    var floating = query('.floating', parentGfx),
28587	        point = intersection.point;
28588
28589	    if (!floating) {
28590	      return;
28591	    }
28592
28593	    translate$2(floating, point.x, point.y);
28594
28595	  }
28596
28597	  function updateSegmentDraggerPosition(parentGfx, intersection, waypoints) {
28598
28599	    var draggerGfx = getSegmentDragger(intersection.index, parentGfx),
28600	        segmentStart = waypoints[intersection.index - 1],
28601	        segmentEnd = waypoints[intersection.index],
28602	        point = intersection.point,
28603	        mid = getMidPoint(segmentStart, segmentEnd),
28604	        alignment = pointsAligned(segmentStart, segmentEnd),
28605	        draggerVisual, relativePosition;
28606
28607	    if (!draggerGfx) {
28608	      return;
28609	    }
28610
28611	    draggerVisual = getDraggerVisual(draggerGfx);
28612
28613	    relativePosition = {
28614	      x: point.x - mid.x,
28615	      y: point.y - mid.y
28616	    };
28617
28618	    if (alignment === 'v') {
28619
28620	      // rotate position
28621	      relativePosition = {
28622	        x: relativePosition.y,
28623	        y: relativePosition.x
28624	      };
28625	    }
28626
28627	    translate$2(draggerVisual, relativePosition.x, relativePosition.y);
28628	  }
28629
28630	  eventBus.on('connection.changed', function(event) {
28631	    updateHandles(event.element);
28632	  });
28633
28634	  eventBus.on('connection.remove', function(event) {
28635	    var gfx = getBendpointsContainer(event.element);
28636
28637	    if (gfx) {
28638	      remove$1(gfx);
28639	    }
28640	  });
28641
28642	  eventBus.on('element.marker.update', function(event) {
28643
28644	    var element = event.element,
28645	        bendpointsGfx;
28646
28647	    if (!element.waypoints) {
28648	      return;
28649	    }
28650
28651	    bendpointsGfx = addHandles(element);
28652
28653	    if (event.add) {
28654	      classes(bendpointsGfx).add(event.marker);
28655	    } else {
28656	      classes(bendpointsGfx).remove(event.marker);
28657	    }
28658	  });
28659
28660	  eventBus.on('element.mousemove', function(event) {
28661
28662	    var element = event.element,
28663	        waypoints = element.waypoints,
28664	        bendpointsGfx,
28665	        intersection;
28666
28667	    if (waypoints) {
28668	      bendpointsGfx = getBendpointsContainer(element, true);
28669
28670	      intersection = getConnectionIntersection(canvas, waypoints, event.originalEvent);
28671
28672	      if (!intersection) {
28673	        return;
28674	      }
28675
28676	      updateFloatingBendpointPosition(bendpointsGfx, intersection);
28677
28678	      if (!intersection.bendpoint) {
28679	        updateSegmentDraggerPosition(bendpointsGfx, intersection, waypoints);
28680	      }
28681
28682	    }
28683	  });
28684
28685	  eventBus.on('element.mousedown', function(event) {
28686
28687	    if (!isPrimaryButton(event)) {
28688	      return;
28689	    }
28690
28691	    var originalEvent = event.originalEvent,
28692	        element = event.element;
28693
28694	    if (!element.waypoints) {
28695	      return;
28696	    }
28697
28698	    return activateBendpointMove(originalEvent, element);
28699	  });
28700
28701	  eventBus.on('selection.changed', function(event) {
28702	    var newSelection = event.newSelection,
28703	        primary = newSelection[0];
28704
28705	    if (primary && primary.waypoints) {
28706	      addHandles(primary);
28707	    }
28708	  });
28709
28710	  eventBus.on('element.hover', function(event) {
28711	    var element = event.element;
28712
28713	    if (element.waypoints) {
28714	      addHandles(element);
28715	      interactionEvents.registerEvent(event.gfx, 'mousemove', 'element.mousemove');
28716	    }
28717	  });
28718
28719	  eventBus.on('element.out', function(event) {
28720	    interactionEvents.unregisterEvent(event.gfx, 'mousemove', 'element.mousemove');
28721	  });
28722
28723	  // update bendpoint container data attribute on element ID change
28724	  eventBus.on('element.updateId', function(context) {
28725	    var element = context.element,
28726	        newId = context.newId;
28727
28728	    if (element.waypoints) {
28729	      var bendpointContainer = getBendpointsContainer(element);
28730
28731	      if (bendpointContainer) {
28732	        attr(bendpointContainer, { 'data-element-id': newId });
28733	      }
28734	    }
28735	  });
28736
28737	  // API
28738
28739	  this.addHandles = addHandles;
28740	  this.updateHandles = updateHandles;
28741	  this.getBendpointsContainer = getBendpointsContainer;
28742	  this.getSegmentDragger = getSegmentDragger;
28743	}
28744
28745	Bendpoints.$inject = [
28746	  'eventBus',
28747	  'canvas',
28748	  'interactionEvents',
28749	  'bendpointMove',
28750	  'connectionSegmentMove'
28751	];
28752
28753
28754
28755	// helper /////////////
28756
28757	function getDraggerVisual(draggerGfx) {
28758	  return query('.djs-visual', draggerGfx);
28759	}
28760
28761	var round$8 = Math.round;
28762
28763	var RECONNECT_START$1 = 'reconnectStart',
28764	    RECONNECT_END$1 = 'reconnectEnd',
28765	    UPDATE_WAYPOINTS$1 = 'updateWaypoints';
28766
28767
28768	/**
28769	 * Move bendpoints through drag and drop to add/remove bendpoints or reconnect connection.
28770	 */
28771	function BendpointMove(injector, eventBus, canvas, dragging, rules, modeling) {
28772	  this._injector = injector;
28773
28774	  this.start = function(event, connection, bendpointIndex, insert) {
28775	    var gfx = canvas.getGraphics(connection),
28776	        source = connection.source,
28777	        target = connection.target,
28778	        waypoints = connection.waypoints,
28779	        type;
28780
28781	    if (!insert && bendpointIndex === 0) {
28782	      type = RECONNECT_START$1;
28783	    } else
28784	    if (!insert && bendpointIndex === waypoints.length - 1) {
28785	      type = RECONNECT_END$1;
28786	    } else {
28787	      type = UPDATE_WAYPOINTS$1;
28788	    }
28789
28790	    var command = type === UPDATE_WAYPOINTS$1 ? 'connection.updateWaypoints' : 'connection.reconnect';
28791
28792	    var allowed = rules.allowed(command, {
28793	      connection: connection,
28794	      source: source,
28795	      target: target
28796	    });
28797
28798	    if (allowed === false) {
28799	      allowed = rules.allowed(command, {
28800	        connection: connection,
28801	        source: target,
28802	        target: source
28803	      });
28804	    }
28805
28806	    if (allowed === false) {
28807	      return;
28808	    }
28809
28810	    dragging.init(event, 'bendpoint.move', {
28811	      data: {
28812	        connection: connection,
28813	        connectionGfx: gfx,
28814	        context: {
28815	          allowed: allowed,
28816	          bendpointIndex: bendpointIndex,
28817	          connection: connection,
28818	          source: source,
28819	          target: target,
28820	          insert: insert,
28821	          type: type
28822	        }
28823	      }
28824	    });
28825	  };
28826
28827	  eventBus.on('bendpoint.move.hover', function(event) {
28828	    var context = event.context,
28829	        connection = context.connection,
28830	        source = connection.source,
28831	        target = connection.target,
28832	        hover = event.hover,
28833	        type = context.type;
28834
28835	    // cache hover state
28836	    context.hover = hover;
28837
28838	    var allowed;
28839
28840	    if (!hover) {
28841	      return;
28842	    }
28843
28844	    var command = type === UPDATE_WAYPOINTS$1 ? 'connection.updateWaypoints' : 'connection.reconnect';
28845
28846	    allowed = context.allowed = rules.allowed(command, {
28847	      connection: connection,
28848	      source: type === RECONNECT_START$1 ? hover : source,
28849	      target: type === RECONNECT_END$1 ? hover : target
28850	    });
28851
28852	    if (allowed) {
28853	      context.source = type === RECONNECT_START$1 ? hover : source;
28854	      context.target = type === RECONNECT_END$1 ? hover : target;
28855
28856	      return;
28857	    }
28858
28859	    if (allowed === false) {
28860	      allowed = context.allowed = rules.allowed(command, {
28861	        connection: connection,
28862	        source: type === RECONNECT_END$1 ? hover : target,
28863	        target: type === RECONNECT_START$1 ? hover : source
28864	      });
28865	    }
28866
28867	    if (allowed) {
28868	      context.source = type === RECONNECT_END$1 ? hover : target;
28869	      context.target = type === RECONNECT_START$1 ? hover : source;
28870	    }
28871	  });
28872
28873	  eventBus.on([ 'bendpoint.move.out', 'bendpoint.move.cleanup' ], function(event) {
28874	    var context = event.context,
28875	        type = context.type;
28876
28877	    context.hover = null;
28878	    context.source = null;
28879	    context.target = null;
28880
28881	    if (type !== UPDATE_WAYPOINTS$1) {
28882	      context.allowed = false;
28883	    }
28884	  });
28885
28886	  eventBus.on('bendpoint.move.end', function(event) {
28887	    var context = event.context,
28888	        allowed = context.allowed,
28889	        bendpointIndex = context.bendpointIndex,
28890	        connection = context.connection,
28891	        insert = context.insert,
28892	        newWaypoints = connection.waypoints.slice(),
28893	        source = context.source,
28894	        target = context.target,
28895	        type = context.type,
28896	        hints = context.hints || {};
28897
28898	    // ensure integer values (important if zoom level was > 1 during move)
28899	    var docking = {
28900	      x: round$8(event.x),
28901	      y: round$8(event.y)
28902	    };
28903
28904	    if (!allowed) {
28905	      return false;
28906	    }
28907
28908	    if (type === UPDATE_WAYPOINTS$1) {
28909	      if (insert) {
28910
28911	        // insert new bendpoint
28912	        newWaypoints.splice(bendpointIndex, 0, docking);
28913	      } else {
28914
28915	        // swap previous waypoint with moved one
28916	        newWaypoints[bendpointIndex] = docking;
28917	      }
28918
28919	      // pass hints about actual moved bendpoint
28920	      // useful for connection/label layout
28921	      hints.bendpointMove = {
28922	        insert: insert,
28923	        bendpointIndex: bendpointIndex
28924	      };
28925
28926	      newWaypoints = this.cropWaypoints(connection, newWaypoints);
28927
28928	      modeling.updateWaypoints(connection, filterRedundantWaypoints(newWaypoints), hints);
28929	    } else {
28930	      if (type === RECONNECT_START$1) {
28931	        hints.docking = 'source';
28932
28933	        if (isReverse$2(context)) {
28934	          hints.docking = 'target';
28935
28936	          hints.newWaypoints = newWaypoints.reverse();
28937	        }
28938	      } else if (type === RECONNECT_END$1) {
28939	        hints.docking = 'target';
28940
28941	        if (isReverse$2(context)) {
28942	          hints.docking = 'source';
28943
28944	          hints.newWaypoints = newWaypoints.reverse();
28945	        }
28946	      }
28947
28948	      modeling.reconnect(connection, source, target, docking, hints);
28949	    }
28950	  }, this);
28951	}
28952
28953	BendpointMove.$inject = [
28954	  'injector',
28955	  'eventBus',
28956	  'canvas',
28957	  'dragging',
28958	  'rules',
28959	  'modeling'
28960	];
28961
28962	BendpointMove.prototype.cropWaypoints = function(connection, newWaypoints) {
28963	  var connectionDocking = this._injector.get('connectionDocking', false);
28964
28965	  if (!connectionDocking) {
28966	    return newWaypoints;
28967	  }
28968
28969	  var waypoints = connection.waypoints;
28970
28971	  connection.waypoints = newWaypoints;
28972
28973	  connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
28974
28975	  newWaypoints = connection.waypoints;
28976
28977	  connection.waypoints = waypoints;
28978
28979	  return newWaypoints;
28980	};
28981
28982
28983	// helpers //////////
28984
28985	function isReverse$2(context) {
28986	  var hover = context.hover,
28987	      source = context.source,
28988	      target = context.target,
28989	      type = context.type;
28990
28991	  if (type === RECONNECT_START$1) {
28992	    return hover && target && hover === target && source !== target;
28993	  }
28994
28995	  if (type === RECONNECT_END$1) {
28996	    return hover && source && hover === source && source !== target;
28997	  }
28998	}
28999
29000	var RECONNECT_START = 'reconnectStart',
29001	    RECONNECT_END = 'reconnectEnd',
29002	    UPDATE_WAYPOINTS = 'updateWaypoints';
29003
29004	var MARKER_OK$4 = 'connect-ok',
29005	    MARKER_NOT_OK$4 = 'connect-not-ok',
29006	    MARKER_CONNECT_HOVER$1 = 'connect-hover',
29007	    MARKER_CONNECT_UPDATING$1 = 'djs-updating',
29008	    MARKER_ELEMENT_HIDDEN = 'djs-element-hidden';
29009
29010	var HIGH_PRIORITY$i = 1100;
29011
29012	/**
29013	 * Preview connection while moving bendpoints.
29014	 */
29015	function BendpointMovePreview(bendpointMove, injector, eventBus, canvas) {
29016	  this._injector = injector;
29017
29018	  var connectionPreview = injector.get('connectionPreview', false);
29019
29020	  eventBus.on('bendpoint.move.start', function(event) {
29021	    var context = event.context,
29022	        bendpointIndex = context.bendpointIndex,
29023	        connection = context.connection,
29024	        insert = context.insert,
29025	        waypoints = connection.waypoints,
29026	        newWaypoints = waypoints.slice();
29027
29028	    context.waypoints = waypoints;
29029
29030	    if (insert) {
29031
29032	      // insert placeholder for new bendpoint
29033	      newWaypoints.splice(bendpointIndex, 0, { x: event.x, y: event.y });
29034	    }
29035
29036	    connection.waypoints = newWaypoints;
29037
29038	    // add dragger gfx
29039	    var draggerGfx = context.draggerGfx = addBendpoint(canvas.getLayer('overlays'));
29040
29041	    classes(draggerGfx).add('djs-dragging');
29042
29043	    canvas.addMarker(connection, MARKER_ELEMENT_HIDDEN);
29044	    canvas.addMarker(connection, MARKER_CONNECT_UPDATING$1);
29045	  });
29046
29047	  eventBus.on('bendpoint.move.hover', function(event) {
29048	    var context = event.context,
29049	        allowed = context.allowed,
29050	        hover = context.hover,
29051	        type = context.type;
29052
29053	    if (hover) {
29054	      canvas.addMarker(hover, MARKER_CONNECT_HOVER$1);
29055
29056	      if (type === UPDATE_WAYPOINTS) {
29057	        return;
29058	      }
29059
29060	      if (allowed) {
29061	        canvas.removeMarker(hover, MARKER_NOT_OK$4);
29062	        canvas.addMarker(hover, MARKER_OK$4);
29063	      } else if (allowed === false) {
29064	        canvas.removeMarker(hover, MARKER_OK$4);
29065	        canvas.addMarker(hover, MARKER_NOT_OK$4);
29066	      }
29067	    }
29068	  });
29069
29070	  eventBus.on([
29071	    'bendpoint.move.out',
29072	    'bendpoint.move.cleanup'
29073	  ], HIGH_PRIORITY$i, function(event) {
29074	    var context = event.context,
29075	        hover = context.hover,
29076	        target = context.target;
29077
29078	    if (hover) {
29079	      canvas.removeMarker(hover, MARKER_CONNECT_HOVER$1);
29080	      canvas.removeMarker(hover, target ? MARKER_OK$4 : MARKER_NOT_OK$4);
29081	    }
29082	  });
29083
29084	  eventBus.on('bendpoint.move.move', function(event) {
29085	    var context = event.context,
29086	        allowed = context.allowed,
29087	        bendpointIndex = context.bendpointIndex,
29088	        draggerGfx = context.draggerGfx,
29089	        hover = context.hover,
29090	        type = context.type,
29091	        connection = context.connection,
29092	        source = connection.source,
29093	        target = connection.target,
29094	        newWaypoints = connection.waypoints.slice(),
29095	        bendpoint = { x: event.x, y: event.y },
29096	        hints = context.hints || {},
29097	        drawPreviewHints = {};
29098
29099	    if (connectionPreview) {
29100	      if (hints.connectionStart) {
29101	        drawPreviewHints.connectionStart = hints.connectionStart;
29102	      }
29103
29104	      if (hints.connectionEnd) {
29105	        drawPreviewHints.connectionEnd = hints.connectionEnd;
29106	      }
29107
29108
29109	      if (type === RECONNECT_START) {
29110	        if (isReverse$2(context)) {
29111	          drawPreviewHints.connectionEnd = drawPreviewHints.connectionEnd || bendpoint;
29112
29113	          drawPreviewHints.source = target;
29114	          drawPreviewHints.target = hover || source;
29115
29116	          newWaypoints = newWaypoints.reverse();
29117	        } else {
29118	          drawPreviewHints.connectionStart = drawPreviewHints.connectionStart || bendpoint;
29119
29120	          drawPreviewHints.source = hover || source;
29121	          drawPreviewHints.target = target;
29122	        }
29123	      } else if (type === RECONNECT_END) {
29124	        if (isReverse$2(context)) {
29125	          drawPreviewHints.connectionStart = drawPreviewHints.connectionStart || bendpoint;
29126
29127	          drawPreviewHints.source = hover || target;
29128	          drawPreviewHints.target = source;
29129
29130	          newWaypoints = newWaypoints.reverse();
29131	        } else {
29132	          drawPreviewHints.connectionEnd = drawPreviewHints.connectionEnd || bendpoint;
29133
29134	          drawPreviewHints.source = source;
29135	          drawPreviewHints.target = hover || target;
29136	        }
29137
29138	      } else {
29139	        drawPreviewHints.noCropping = true;
29140	        drawPreviewHints.noLayout = true;
29141	        newWaypoints[ bendpointIndex ] = bendpoint;
29142	      }
29143
29144	      if (type === UPDATE_WAYPOINTS) {
29145	        newWaypoints = bendpointMove.cropWaypoints(connection, newWaypoints);
29146	      }
29147
29148	      drawPreviewHints.waypoints = newWaypoints;
29149
29150	      connectionPreview.drawPreview(context, allowed, drawPreviewHints);
29151	    }
29152
29153	    translate$2(draggerGfx, event.x, event.y);
29154	  }, this);
29155
29156	  eventBus.on([
29157	    'bendpoint.move.end',
29158	    'bendpoint.move.cancel'
29159	  ], HIGH_PRIORITY$i, function(event) {
29160	    var context = event.context,
29161	        connection = context.connection,
29162	        draggerGfx = context.draggerGfx,
29163	        hover = context.hover,
29164	        target = context.target,
29165	        waypoints = context.waypoints;
29166
29167	    connection.waypoints = waypoints;
29168
29169	    // remove dragger gfx
29170	    remove$1(draggerGfx);
29171
29172	    canvas.removeMarker(connection, MARKER_CONNECT_UPDATING$1);
29173	    canvas.removeMarker(connection, MARKER_ELEMENT_HIDDEN);
29174
29175	    if (hover) {
29176	      canvas.removeMarker(hover, MARKER_OK$4);
29177	      canvas.removeMarker(hover, target ? MARKER_OK$4 : MARKER_NOT_OK$4);
29178	    }
29179
29180	    if (connectionPreview) {
29181	      connectionPreview.cleanUp(context);
29182	    }
29183	  });
29184	}
29185
29186	BendpointMovePreview.$inject = [
29187	  'bendpointMove',
29188	  'injector',
29189	  'eventBus',
29190	  'canvas'
29191	];
29192
29193	var MARKER_CONNECT_HOVER = 'connect-hover',
29194	    MARKER_CONNECT_UPDATING = 'djs-updating';
29195
29196
29197	function axisAdd(point, axis, delta) {
29198	  return axisSet(point, axis, point[axis] + delta);
29199	}
29200
29201	function axisSet(point, axis, value) {
29202	  return {
29203	    x: (axis === 'x' ? value : point.x),
29204	    y: (axis === 'y' ? value : point.y)
29205	  };
29206	}
29207
29208	function axisFenced(position, segmentStart, segmentEnd, axis) {
29209
29210	  var maxValue = Math.max(segmentStart[axis], segmentEnd[axis]),
29211	      minValue = Math.min(segmentStart[axis], segmentEnd[axis]);
29212
29213	  var padding = 20;
29214
29215	  var fencedValue = Math.min(Math.max(minValue + padding, position[axis]), maxValue - padding);
29216
29217	  return axisSet(segmentStart, axis, fencedValue);
29218	}
29219
29220	function flipAxis(axis) {
29221	  return axis === 'x' ? 'y' : 'x';
29222	}
29223
29224	/**
29225	 * Get the docking point on the given element.
29226	 *
29227	 * Compute a reasonable docking, if non exists.
29228	 *
29229	 * @param  {Point} point
29230	 * @param  {djs.model.Shape} referenceElement
29231	 * @param  {string} moveAxis (x|y)
29232	 *
29233	 * @return {Point}
29234	 */
29235	function getDocking$2(point, referenceElement, moveAxis) {
29236
29237	  var referenceMid,
29238	      inverseAxis;
29239
29240	  if (point.original) {
29241	    return point.original;
29242	  } else {
29243	    referenceMid = getMid(referenceElement);
29244	    inverseAxis = flipAxis(moveAxis);
29245
29246	    return axisSet(point, inverseAxis, referenceMid[inverseAxis]);
29247	  }
29248	}
29249
29250	/**
29251	 * A component that implements moving of bendpoints
29252	 */
29253	function ConnectionSegmentMove(
29254	    injector, eventBus, canvas,
29255	    dragging, graphicsFactory, modeling) {
29256
29257	  // optional connection docking integration
29258	  var connectionDocking = injector.get('connectionDocking', false);
29259
29260
29261	  // API
29262
29263	  this.start = function(event, connection, idx) {
29264
29265	    var context,
29266	        gfx = canvas.getGraphics(connection),
29267	        segmentStartIndex = idx - 1,
29268	        segmentEndIndex = idx,
29269	        waypoints = connection.waypoints,
29270	        segmentStart = waypoints[segmentStartIndex],
29271	        segmentEnd = waypoints[segmentEndIndex],
29272	        intersection = getConnectionIntersection(canvas, waypoints, event),
29273	        direction, axis, dragPosition;
29274
29275	    direction = pointsAligned(segmentStart, segmentEnd);
29276
29277	    // do not move diagonal connection
29278	    if (!direction) {
29279	      return;
29280	    }
29281
29282	    // the axis where we are going to move things
29283	    axis = direction === 'v' ? 'x' : 'y';
29284
29285	    if (segmentStartIndex === 0) {
29286	      segmentStart = getDocking$2(segmentStart, connection.source, axis);
29287	    }
29288
29289	    if (segmentEndIndex === waypoints.length - 1) {
29290	      segmentEnd = getDocking$2(segmentEnd, connection.target, axis);
29291	    }
29292
29293	    if (intersection) {
29294	      dragPosition = intersection.point;
29295	    } else {
29296
29297	      // set to segment center as default
29298	      dragPosition = {
29299	        x: (segmentStart.x + segmentEnd.x) / 2,
29300	        y: (segmentStart.y + segmentEnd.y) / 2
29301	      };
29302	    }
29303
29304	    context = {
29305	      connection: connection,
29306	      segmentStartIndex: segmentStartIndex,
29307	      segmentEndIndex: segmentEndIndex,
29308	      segmentStart: segmentStart,
29309	      segmentEnd: segmentEnd,
29310	      axis: axis,
29311	      dragPosition: dragPosition
29312	    };
29313
29314	    dragging.init(event, dragPosition, 'connectionSegment.move', {
29315	      cursor: axis === 'x' ? 'resize-ew' : 'resize-ns',
29316	      data: {
29317	        connection: connection,
29318	        connectionGfx: gfx,
29319	        context: context
29320	      }
29321	    });
29322	  };
29323
29324	  /**
29325	   * Crop connection if connection cropping is provided.
29326	   *
29327	   * @param {Connection} connection
29328	   * @param {Array<Point>} newWaypoints
29329	   *
29330	   * @return {Array<Point>} cropped connection waypoints
29331	   */
29332	  function cropConnection(connection, newWaypoints) {
29333
29334	    // crop connection, if docking service is provided only
29335	    if (!connectionDocking) {
29336	      return newWaypoints;
29337	    }
29338
29339	    var oldWaypoints = connection.waypoints,
29340	        croppedWaypoints;
29341
29342	    // temporary set new waypoints
29343	    connection.waypoints = newWaypoints;
29344
29345	    croppedWaypoints = connectionDocking.getCroppedWaypoints(connection);
29346
29347	    // restore old waypoints
29348	    connection.waypoints = oldWaypoints;
29349
29350	    return croppedWaypoints;
29351	  }
29352
29353	  // DRAGGING IMPLEMENTATION
29354
29355	  function redrawConnection(data) {
29356	    graphicsFactory.update('connection', data.connection, data.connectionGfx);
29357	  }
29358
29359	  function updateDragger(context, segmentOffset, event) {
29360
29361	    var newWaypoints = context.newWaypoints,
29362	        segmentStartIndex = context.segmentStartIndex + segmentOffset,
29363	        segmentStart = newWaypoints[segmentStartIndex],
29364	        segmentEndIndex = context.segmentEndIndex + segmentOffset,
29365	        segmentEnd = newWaypoints[segmentEndIndex],
29366	        axis = flipAxis(context.axis);
29367
29368	    // make sure the dragger does not move
29369	    // outside the connection
29370	    var draggerPosition = axisFenced(event, segmentStart, segmentEnd, axis);
29371
29372	    // update dragger
29373	    translate$2(context.draggerGfx, draggerPosition.x, draggerPosition.y);
29374	  }
29375
29376	  /**
29377	   * Filter waypoints for redundant ones (i.e. on the same axis).
29378	   * Returns the filtered waypoints and the offset related to the segment move.
29379	   *
29380	   * @param {Array<Point>} waypoints
29381	   * @param {Integer} segmentStartIndex of moved segment start
29382	   *
29383	   * @return {Object} { filteredWaypoints, segmentOffset }
29384	   */
29385	  function filterRedundantWaypoints(waypoints, segmentStartIndex) {
29386
29387	    var segmentOffset = 0;
29388
29389	    var filteredWaypoints = waypoints.filter(function(r, idx) {
29390	      if (pointsOnLine(waypoints[idx - 1], waypoints[idx + 1], r)) {
29391
29392	        // remove point and increment offset
29393	        segmentOffset = idx <= segmentStartIndex ? segmentOffset - 1 : segmentOffset;
29394	        return false;
29395	      }
29396
29397	      // dont remove point
29398	      return true;
29399	    });
29400
29401	    return {
29402	      waypoints: filteredWaypoints,
29403	      segmentOffset: segmentOffset
29404	    };
29405	  }
29406
29407	  eventBus.on('connectionSegment.move.start', function(event) {
29408
29409	    var context = event.context,
29410	        connection = event.connection,
29411	        layer = canvas.getLayer('overlays');
29412
29413	    context.originalWaypoints = connection.waypoints.slice();
29414
29415	    // add dragger gfx
29416	    context.draggerGfx = addSegmentDragger(layer, context.segmentStart, context.segmentEnd);
29417	    classes(context.draggerGfx).add('djs-dragging');
29418
29419	    canvas.addMarker(connection, MARKER_CONNECT_UPDATING);
29420	  });
29421
29422	  eventBus.on('connectionSegment.move.move', function(event) {
29423
29424	    var context = event.context,
29425	        connection = context.connection,
29426	        segmentStartIndex = context.segmentStartIndex,
29427	        segmentEndIndex = context.segmentEndIndex,
29428	        segmentStart = context.segmentStart,
29429	        segmentEnd = context.segmentEnd,
29430	        axis = context.axis;
29431
29432	    var newWaypoints = context.originalWaypoints.slice(),
29433	        newSegmentStart = axisAdd(segmentStart, axis, event['d' + axis]),
29434	        newSegmentEnd = axisAdd(segmentEnd, axis, event['d' + axis]);
29435
29436	    // original waypoint count and added / removed
29437	    // from start waypoint delta. We use the later
29438	    // to retrieve the updated segmentStartIndex / segmentEndIndex
29439	    var waypointCount = newWaypoints.length,
29440	        segmentOffset = 0;
29441
29442	    // move segment start / end by axis delta
29443	    newWaypoints[segmentStartIndex] = newSegmentStart;
29444	    newWaypoints[segmentEndIndex] = newSegmentEnd;
29445
29446	    var sourceToSegmentOrientation,
29447	        targetToSegmentOrientation;
29448
29449	    // handle first segment
29450	    if (segmentStartIndex < 2) {
29451	      sourceToSegmentOrientation = getOrientation(connection.source, newSegmentStart);
29452
29453	      // first bendpoint, remove first segment if intersecting
29454	      if (segmentStartIndex === 1) {
29455
29456	        if (sourceToSegmentOrientation === 'intersect') {
29457	          newWaypoints.shift();
29458	          newWaypoints[0] = newSegmentStart;
29459	          segmentOffset--;
29460	        }
29461	      }
29462
29463	      // docking point, add segment if not intersecting anymore
29464	      else {
29465	        if (sourceToSegmentOrientation !== 'intersect') {
29466	          newWaypoints.unshift(segmentStart);
29467	          segmentOffset++;
29468	        }
29469	      }
29470	    }
29471
29472	    // handle last segment
29473	    if (segmentEndIndex > waypointCount - 3) {
29474	      targetToSegmentOrientation = getOrientation(connection.target, newSegmentEnd);
29475
29476	      // last bendpoint, remove last segment if intersecting
29477	      if (segmentEndIndex === waypointCount - 2) {
29478
29479	        if (targetToSegmentOrientation === 'intersect') {
29480	          newWaypoints.pop();
29481	          newWaypoints[newWaypoints.length - 1] = newSegmentEnd;
29482	        }
29483	      }
29484
29485	      // last bendpoint, remove last segment if intersecting
29486	      else {
29487	        if (targetToSegmentOrientation !== 'intersect') {
29488	          newWaypoints.push(segmentEnd);
29489	        }
29490	      }
29491	    }
29492
29493	    // update connection waypoints
29494	    context.newWaypoints = connection.waypoints = cropConnection(connection, newWaypoints);
29495
29496	    // update dragger position
29497	    updateDragger(context, segmentOffset, event);
29498
29499	    // save segmentOffset in context
29500	    context.newSegmentStartIndex = segmentStartIndex + segmentOffset;
29501
29502	    // redraw connection
29503	    redrawConnection(event);
29504	  });
29505
29506	  eventBus.on('connectionSegment.move.hover', function(event) {
29507
29508	    event.context.hover = event.hover;
29509	    canvas.addMarker(event.hover, MARKER_CONNECT_HOVER);
29510	  });
29511
29512	  eventBus.on([
29513	    'connectionSegment.move.out',
29514	    'connectionSegment.move.cleanup'
29515	  ], function(event) {
29516
29517	    // remove connect marker
29518	    // if it was added
29519	    var hover = event.context.hover;
29520
29521	    if (hover) {
29522	      canvas.removeMarker(hover, MARKER_CONNECT_HOVER);
29523	    }
29524	  });
29525
29526	  eventBus.on('connectionSegment.move.cleanup', function(event) {
29527
29528	    var context = event.context,
29529	        connection = context.connection;
29530
29531	    // remove dragger gfx
29532	    if (context.draggerGfx) {
29533	      remove$1(context.draggerGfx);
29534	    }
29535
29536	    canvas.removeMarker(connection, MARKER_CONNECT_UPDATING);
29537	  });
29538
29539	  eventBus.on([
29540	    'connectionSegment.move.cancel',
29541	    'connectionSegment.move.end'
29542	  ], function(event) {
29543	    var context = event.context,
29544	        connection = context.connection;
29545
29546	    connection.waypoints = context.originalWaypoints;
29547
29548	    redrawConnection(event);
29549	  });
29550
29551	  eventBus.on('connectionSegment.move.end', function(event) {
29552
29553	    var context = event.context,
29554	        connection = context.connection,
29555	        newWaypoints = context.newWaypoints,
29556	        newSegmentStartIndex = context.newSegmentStartIndex;
29557
29558	    // ensure we have actual pixel values bendpoint
29559	    // coordinates (important when zoom level was > 1 during move)
29560	    newWaypoints = newWaypoints.map(function(p) {
29561	      return {
29562	        original: p.original,
29563	        x: Math.round(p.x),
29564	        y: Math.round(p.y)
29565	      };
29566	    });
29567
29568	    // apply filter redunant waypoints
29569	    var filtered = filterRedundantWaypoints(newWaypoints, newSegmentStartIndex);
29570
29571	    // get filtered waypoints
29572	    var filteredWaypoints = filtered.waypoints,
29573	        croppedWaypoints = cropConnection(connection, filteredWaypoints),
29574	        segmentOffset = filtered.segmentOffset;
29575
29576	    var hints = {
29577	      segmentMove: {
29578	        segmentStartIndex: context.segmentStartIndex,
29579	        newSegmentStartIndex: newSegmentStartIndex + segmentOffset
29580	      }
29581	    };
29582
29583	    modeling.updateWaypoints(connection, croppedWaypoints, hints);
29584	  });
29585	}
29586
29587	ConnectionSegmentMove.$inject = [
29588	  'injector',
29589	  'eventBus',
29590	  'canvas',
29591	  'dragging',
29592	  'graphicsFactory',
29593	  'modeling'
29594	];
29595
29596	var abs$6 = Math.abs,
29597	    round$7 = Math.round;
29598
29599
29600	/**
29601	 * Snap value to a collection of reference values.
29602	 *
29603	 * @param  {number} value
29604	 * @param  {Array<number>} values
29605	 * @param  {number} [tolerance=10]
29606	 *
29607	 * @return {number} the value we snapped to or null, if none snapped
29608	 */
29609	function snapTo(value, values, tolerance) {
29610	  tolerance = tolerance === undefined ? 10 : tolerance;
29611
29612	  var idx, snapValue;
29613
29614	  for (idx = 0; idx < values.length; idx++) {
29615	    snapValue = values[idx];
29616
29617	    if (abs$6(snapValue - value) <= tolerance) {
29618	      return snapValue;
29619	    }
29620	  }
29621	}
29622
29623
29624	function topLeft(bounds) {
29625	  return {
29626	    x: bounds.x,
29627	    y: bounds.y
29628	  };
29629	}
29630
29631	function bottomRight(bounds) {
29632	  return {
29633	    x: bounds.x + bounds.width,
29634	    y: bounds.y + bounds.height
29635	  };
29636	}
29637
29638	function mid$2(bounds, defaultValue) {
29639
29640	  if (!bounds || isNaN(bounds.x) || isNaN(bounds.y)) {
29641	    return defaultValue;
29642	  }
29643
29644	  return {
29645	    x: round$7(bounds.x + bounds.width / 2),
29646	    y: round$7(bounds.y + bounds.height / 2)
29647	  };
29648	}
29649
29650
29651	/**
29652	 * Retrieve the snap state of the given event.
29653	 *
29654	 * @param  {Event} event
29655	 * @param  {string} axis
29656	 *
29657	 * @return {boolean} the snapped state
29658	 *
29659	 */
29660	function isSnapped(event, axis) {
29661	  var snapped = event.snapped;
29662
29663	  if (!snapped) {
29664	    return false;
29665	  }
29666
29667	  if (typeof axis === 'string') {
29668	    return snapped[axis];
29669	  }
29670
29671	  return snapped.x && snapped.y;
29672	}
29673
29674
29675	/**
29676	 * Set the given event as snapped.
29677	 *
29678	 * This method may change the x and/or y position of the shape
29679	 * from the given event!
29680	 *
29681	 * @param {Event} event
29682	 * @param {string} axis
29683	 * @param {number|boolean} value
29684	 *
29685	 * @return {number} old value
29686	 */
29687	function setSnapped(event, axis, value) {
29688	  if (typeof axis !== 'string') {
29689	    throw new Error('axis must be in [x, y]');
29690	  }
29691
29692	  if (typeof value !== 'number' && value !== false) {
29693	    throw new Error('value must be Number or false');
29694	  }
29695
29696	  var delta,
29697	      previousValue = event[axis];
29698
29699	  var snapped = event.snapped = (event.snapped || {});
29700
29701
29702	  if (value === false) {
29703	    snapped[axis] = false;
29704	  } else {
29705	    snapped[axis] = true;
29706
29707	    delta = value - previousValue;
29708
29709	    event[axis] += delta;
29710	    event['d' + axis] += delta;
29711	  }
29712
29713	  return previousValue;
29714	}
29715
29716	/**
29717	 * Get children of a shape.
29718	 *
29719	 * @param {djs.model.Shape} parent
29720	 *
29721	 * @returns {Array<djs.model.Shape|djs.model.Connection>}
29722	 */
29723	function getChildren(parent) {
29724	  return parent.children || [];
29725	}
29726
29727	var abs$5= Math.abs,
29728	    round$6 = Math.round;
29729
29730	var TOLERANCE = 10;
29731
29732
29733	function BendpointSnapping(eventBus) {
29734
29735	  function snapTo(values, value) {
29736
29737	    if (isArray$2(values)) {
29738	      var i = values.length;
29739
29740	      while (i--) if (abs$5(values[i] - value) <= TOLERANCE) {
29741	        return values[i];
29742	      }
29743	    } else {
29744	      values = +values;
29745	      var rem = value % values;
29746
29747	      if (rem < TOLERANCE) {
29748	        return value - rem;
29749	      }
29750
29751	      if (rem > values - TOLERANCE) {
29752	        return value - rem + values;
29753	      }
29754	    }
29755
29756	    return value;
29757	  }
29758
29759	  function mid(element) {
29760	    if (element.width) {
29761	      return {
29762	        x: round$6(element.width / 2 + element.x),
29763	        y: round$6(element.height / 2 + element.y)
29764	      };
29765	    }
29766	  }
29767
29768	  // connection segment snapping //////////////////////
29769
29770	  function getConnectionSegmentSnaps(context) {
29771
29772	    var snapPoints = context.snapPoints,
29773	        connection = context.connection,
29774	        waypoints = connection.waypoints,
29775	        segmentStart = context.segmentStart,
29776	        segmentStartIndex = context.segmentStartIndex,
29777	        segmentEnd = context.segmentEnd,
29778	        segmentEndIndex = context.segmentEndIndex,
29779	        axis = context.axis;
29780
29781	    if (snapPoints) {
29782	      return snapPoints;
29783	    }
29784
29785	    var referenceWaypoints = [
29786	      waypoints[segmentStartIndex - 1],
29787	      segmentStart,
29788	      segmentEnd,
29789	      waypoints[segmentEndIndex + 1]
29790	    ];
29791
29792	    if (segmentStartIndex < 2) {
29793	      referenceWaypoints.unshift(mid(connection.source));
29794	    }
29795
29796	    if (segmentEndIndex > waypoints.length - 3) {
29797	      referenceWaypoints.unshift(mid(connection.target));
29798	    }
29799
29800	    context.snapPoints = snapPoints = { horizontal: [] , vertical: [] };
29801
29802	    forEach(referenceWaypoints, function(p) {
29803
29804	      // we snap on existing bendpoints only,
29805	      // not placeholders that are inserted during add
29806	      if (p) {
29807	        p = p.original || p;
29808
29809	        if (axis === 'y') {
29810	          snapPoints.horizontal.push(p.y);
29811	        }
29812
29813	        if (axis === 'x') {
29814	          snapPoints.vertical.push(p.x);
29815	        }
29816	      }
29817	    });
29818
29819	    return snapPoints;
29820	  }
29821
29822	  eventBus.on('connectionSegment.move.move', 1500, function(event) {
29823	    var context = event.context,
29824	        snapPoints = getConnectionSegmentSnaps(context),
29825	        x = event.x,
29826	        y = event.y,
29827	        sx, sy;
29828
29829	    if (!snapPoints) {
29830	      return;
29831	    }
29832
29833	    // snap
29834	    sx = snapTo(snapPoints.vertical, x);
29835	    sy = snapTo(snapPoints.horizontal, y);
29836
29837
29838	    // correction x/y
29839	    var cx = (x - sx),
29840	        cy = (y - sy);
29841
29842	    // update delta
29843	    assign(event, {
29844	      dx: event.dx - cx,
29845	      dy: event.dy - cy,
29846	      x: sx,
29847	      y: sy
29848	    });
29849
29850	    // only set snapped if actually snapped
29851	    if (cx || snapPoints.vertical.indexOf(x) !== -1) {
29852	      setSnapped(event, 'x', sx);
29853	    }
29854
29855	    if (cy || snapPoints.horizontal.indexOf(y) !== -1) {
29856	      setSnapped(event, 'y', sy);
29857	    }
29858	  });
29859
29860
29861	  // bendpoint snapping //////////////////////
29862
29863	  function getBendpointSnaps(context) {
29864
29865	    var snapPoints = context.snapPoints,
29866	        waypoints = context.connection.waypoints,
29867	        bendpointIndex = context.bendpointIndex;
29868
29869	    if (snapPoints) {
29870	      return snapPoints;
29871	    }
29872
29873	    var referenceWaypoints = [ waypoints[bendpointIndex - 1], waypoints[bendpointIndex + 1] ];
29874
29875	    context.snapPoints = snapPoints = { horizontal: [] , vertical: [] };
29876
29877	    forEach(referenceWaypoints, function(p) {
29878
29879	      // we snap on existing bendpoints only,
29880	      // not placeholders that are inserted during add
29881	      if (p) {
29882	        p = p.original || p;
29883
29884	        snapPoints.horizontal.push(p.y);
29885	        snapPoints.vertical.push(p.x);
29886	      }
29887	    });
29888
29889	    return snapPoints;
29890	  }
29891
29892
29893	  eventBus.on([ 'bendpoint.move.move', 'bendpoint.move.end' ], 1500, function(event) {
29894
29895	    var context = event.context,
29896	        snapPoints = getBendpointSnaps(context),
29897	        hover = context.hover,
29898	        hoverMid = hover && mid(hover),
29899	        x = event.x,
29900	        y = event.y,
29901	        sx, sy;
29902
29903	    if (!snapPoints) {
29904	      return;
29905	    }
29906
29907	    // snap to hover mid
29908	    sx = snapTo(hoverMid ? snapPoints.vertical.concat([ hoverMid.x ]) : snapPoints.vertical, x);
29909	    sy = snapTo(hoverMid ? snapPoints.horizontal.concat([ hoverMid.y ]) : snapPoints.horizontal, y);
29910
29911	    // correction x/y
29912	    var cx = (x - sx),
29913	        cy = (y - sy);
29914
29915	    // update delta
29916	    assign(event, {
29917	      dx: event.dx - cx,
29918	      dy: event.dy - cy,
29919	      x: event.x - cx,
29920	      y: event.y - cy
29921	    });
29922
29923	    // only set snapped if actually snapped
29924	    if (cx || snapPoints.vertical.indexOf(x) !== -1) {
29925	      setSnapped(event, 'x', sx);
29926	    }
29927
29928	    if (cy || snapPoints.horizontal.indexOf(y) !== -1) {
29929	      setSnapped(event, 'y', sy);
29930	    }
29931	  });
29932	}
29933
29934
29935	BendpointSnapping.$inject = [ 'eventBus' ];
29936
29937	var BendpointsModule = {
29938	  __depends__: [
29939	    DraggingModule,
29940	    RulesModule$1
29941	  ],
29942	  __init__: [ 'bendpoints', 'bendpointSnapping', 'bendpointMovePreview' ],
29943	  bendpoints: [ 'type', Bendpoints ],
29944	  bendpointMove: [ 'type', BendpointMove ],
29945	  bendpointMovePreview: [ 'type', BendpointMovePreview ],
29946	  connectionSegmentMove: [ 'type', ConnectionSegmentMove ],
29947	  bendpointSnapping: [ 'type', BendpointSnapping ]
29948	};
29949
29950	function Connect(eventBus, dragging, modeling, rules) {
29951
29952	  // rules
29953
29954	  function canConnect(source, target) {
29955	    return rules.allowed('connection.create', {
29956	      source: source,
29957	      target: target
29958	    });
29959	  }
29960
29961	  function canConnectReverse(source, target) {
29962	    return canConnect(target, source);
29963	  }
29964
29965
29966	  // event handlers
29967
29968	  eventBus.on('connect.hover', function(event) {
29969	    var context = event.context,
29970	        start = context.start,
29971	        hover = event.hover,
29972	        canExecute;
29973
29974	    // cache hover state
29975	    context.hover = hover;
29976
29977	    canExecute = context.canExecute = canConnect(start, hover);
29978
29979	    // ignore hover
29980	    if (isNil(canExecute)) {
29981	      return;
29982	    }
29983
29984	    if (canExecute !== false) {
29985	      context.source = start;
29986	      context.target = hover;
29987
29988	      return;
29989	    }
29990
29991	    canExecute = context.canExecute = canConnectReverse(start, hover);
29992
29993	    // ignore hover
29994	    if (isNil(canExecute)) {
29995	      return;
29996	    }
29997
29998	    if (canExecute !== false) {
29999	      context.source = hover;
30000	      context.target = start;
30001	    }
30002	  });
30003
30004	  eventBus.on([ 'connect.out', 'connect.cleanup' ], function(event) {
30005	    var context = event.context;
30006
30007	    context.hover = null;
30008	    context.source = null;
30009	    context.target = null;
30010
30011	    context.canExecute = false;
30012	  });
30013
30014	  eventBus.on('connect.end', function(event) {
30015	    var context = event.context,
30016	        canExecute = context.canExecute,
30017	        connectionStart = context.connectionStart,
30018	        connectionEnd = {
30019	          x: event.x,
30020	          y: event.y
30021	        },
30022	        source = context.source,
30023	        target = context.target;
30024
30025	    if (!canExecute) {
30026	      return false;
30027	    }
30028
30029	    var attrs = null,
30030	        hints = {
30031	          connectionStart: isReverse$1(context) ? connectionEnd : connectionStart,
30032	          connectionEnd: isReverse$1(context) ? connectionStart : connectionEnd
30033	        };
30034
30035	    if (isObject(canExecute)) {
30036	      attrs = canExecute;
30037	    }
30038
30039	    modeling.connect(source, target, attrs, hints);
30040	  });
30041
30042
30043	  // API
30044
30045	  /**
30046	   * Start connect operation.
30047	   *
30048	   * @param {DOMEvent} event
30049	   * @param {djs.model.Base} start
30050	   * @param {Point} [connectionStart]
30051	   * @param {boolean} [autoActivate=false]
30052	   */
30053	  this.start = function(event, start, connectionStart, autoActivate) {
30054	    if (!isObject(connectionStart)) {
30055	      autoActivate = connectionStart;
30056	      connectionStart = getMid(start);
30057	    }
30058
30059	    dragging.init(event, 'connect', {
30060	      autoActivate: autoActivate,
30061	      data: {
30062	        shape: start,
30063	        context: {
30064	          start: start,
30065	          connectionStart: connectionStart
30066	        }
30067	      }
30068	    });
30069	  };
30070	}
30071
30072	Connect.$inject = [
30073	  'eventBus',
30074	  'dragging',
30075	  'modeling',
30076	  'rules'
30077	];
30078
30079
30080	// helpers //////////
30081
30082	function isReverse$1(context) {
30083	  var hover = context.hover,
30084	      source = context.source,
30085	      target = context.target;
30086
30087	  return hover && source && hover === source && source !== target;
30088	}
30089
30090	var HIGH_PRIORITY$h = 1100,
30091	    LOW_PRIORITY$h = 900;
30092
30093	var MARKER_OK$3 = 'connect-ok',
30094	    MARKER_NOT_OK$3 = 'connect-not-ok';
30095
30096	/**
30097	 * Shows connection preview during connect.
30098	 *
30099	 * @param {didi.Injector} injector
30100	 * @param {EventBus} eventBus
30101	 * @param {Canvas} canvas
30102	 */
30103	function ConnectPreview(injector, eventBus, canvas) {
30104	  var connectionPreview = injector.get('connectionPreview', false);
30105
30106	  connectionPreview && eventBus.on('connect.move', function(event) {
30107	    var context = event.context,
30108	        canConnect = context.canExecute,
30109	        hover = context.hover,
30110	        source = context.source,
30111	        start = context.start,
30112	        startPosition = context.startPosition,
30113	        target = context.target,
30114	        connectionStart = context.connectionStart || startPosition,
30115	        connectionEnd = context.connectionEnd || {
30116	          x: event.x,
30117	          y: event.y
30118	        },
30119	        previewStart = connectionStart,
30120	        previewEnd = connectionEnd;
30121
30122	    if (isReverse$1(context)) {
30123	      previewStart = connectionEnd;
30124	      previewEnd = connectionStart;
30125	    }
30126
30127	    connectionPreview.drawPreview(context, canConnect, {
30128	      source: source || start,
30129	      target: target || hover,
30130	      connectionStart: previewStart,
30131	      connectionEnd: previewEnd
30132	    });
30133	  });
30134
30135	  eventBus.on('connect.hover', LOW_PRIORITY$h, function(event) {
30136	    var context = event.context,
30137	        hover = event.hover,
30138	        canExecute = context.canExecute;
30139
30140	    // ignore hover
30141	    if (canExecute === null) {
30142	      return;
30143	    }
30144
30145	    canvas.addMarker(hover, canExecute ? MARKER_OK$3 : MARKER_NOT_OK$3);
30146	  });
30147
30148	  eventBus.on([
30149	    'connect.out',
30150	    'connect.cleanup'
30151	  ], HIGH_PRIORITY$h, function(event) {
30152	    var hover = event.hover;
30153
30154	    if (hover) {
30155	      canvas.removeMarker(hover, MARKER_OK$3);
30156	      canvas.removeMarker(hover, MARKER_NOT_OK$3);
30157	    }
30158	  });
30159
30160	  connectionPreview && eventBus.on('connect.cleanup', function(event) {
30161	    connectionPreview.cleanUp(event.context);
30162	  });
30163	}
30164
30165	ConnectPreview.$inject = [
30166	  'injector',
30167	  'eventBus',
30168	  'canvas'
30169	];
30170
30171	var ConnectModule = {
30172	  __depends__: [
30173	    SelectionModule,
30174	    RulesModule$1,
30175	    DraggingModule
30176	  ],
30177	  __init__: [
30178	    'connectPreview'
30179	  ],
30180	  connect: [ 'type', Connect ],
30181	  connectPreview: [ 'type', ConnectPreview ]
30182	};
30183
30184	var MARKER_CONNECTION_PREVIEW = 'djs-connection-preview';
30185
30186	/**
30187	 * Draws connection preview. Optionally, this can use layouter and connection docking to draw
30188	 * better looking previews.
30189	 *
30190	 * @param {didi.Injector} injector
30191	 * @param {Canvas} canvas
30192	 * @param {GraphicsFactory} graphicsFactory
30193	 * @param {ElementFactory} elementFactory
30194	 */
30195	function ConnectionPreview(
30196	    injector,
30197	    canvas,
30198	    graphicsFactory,
30199	    elementFactory
30200	) {
30201	  this._canvas = canvas;
30202	  this._graphicsFactory = graphicsFactory;
30203	  this._elementFactory = elementFactory;
30204
30205	  // optional components
30206	  this._connectionDocking = injector.get('connectionDocking', false);
30207	  this._layouter = injector.get('layouter', false);
30208	}
30209
30210	ConnectionPreview.$inject = [
30211	  'injector',
30212	  'canvas',
30213	  'graphicsFactory',
30214	  'elementFactory'
30215	];
30216
30217	/**
30218	 * Draw connection preview.
30219	 *
30220	 * Provide at least one of <source, connectionStart> and <target, connectionEnd> to create a preview.
30221	 * In the clean up stage, call `connectionPreview#cleanUp` with the context to remove preview.
30222	 *
30223	 * @param {Object} context
30224	 * @param {Object|boolean} canConnect
30225	 * @param {Object} hints
30226	 * @param {djs.model.shape} [hints.source] source element
30227	 * @param {djs.model.shape} [hints.target] target element
30228	 * @param {Point} [hints.connectionStart] connection preview start
30229	 * @param {Point} [hints.connectionEnd] connection preview end
30230	 * @param {Array<Point>} [hints.waypoints] provided waypoints for preview
30231	 * @param {boolean} [hints.noLayout] true if preview should not be laid out
30232	 * @param {boolean} [hints.noCropping] true if preview should not be cropped
30233	 * @param {boolean} [hints.noNoop] true if simple connection should not be drawn
30234	 */
30235	ConnectionPreview.prototype.drawPreview = function(context, canConnect, hints) {
30236
30237	  hints = hints || {};
30238
30239	  var connectionPreviewGfx = context.connectionPreviewGfx,
30240	      getConnection = context.getConnection,
30241	      source = hints.source,
30242	      target = hints.target,
30243	      waypoints = hints.waypoints,
30244	      connectionStart = hints.connectionStart,
30245	      connectionEnd = hints.connectionEnd,
30246	      noLayout = hints.noLayout,
30247	      noCropping = hints.noCropping,
30248	      noNoop = hints.noNoop,
30249	      connection;
30250
30251	  var self = this;
30252
30253	  if (!connectionPreviewGfx) {
30254	    connectionPreviewGfx = context.connectionPreviewGfx = this.createConnectionPreviewGfx();
30255	  }
30256
30257	  clear(connectionPreviewGfx);
30258
30259	  if (!getConnection) {
30260	    getConnection = context.getConnection = cacheReturnValues(function(canConnect, source, target) {
30261	      return self.getConnection(canConnect, source, target);
30262	    });
30263	  }
30264
30265	  if (canConnect) {
30266	    connection = getConnection(canConnect, source, target);
30267	  }
30268
30269	  if (!connection) {
30270	    !noNoop && this.drawNoopPreview(connectionPreviewGfx, hints);
30271	    return;
30272	  }
30273
30274	  connection.waypoints = waypoints || [];
30275
30276	  // optional layout
30277	  if (this._layouter && !noLayout) {
30278	    connection.waypoints = this._layouter.layoutConnection(connection, {
30279	      source: source,
30280	      target: target,
30281	      connectionStart: connectionStart,
30282	      connectionEnd: connectionEnd,
30283	      waypoints: hints.waypoints || connection.waypoints
30284	    });
30285	  }
30286
30287	  // fallback if no waypoints were provided nor created with layouter
30288	  if (!connection.waypoints || !connection.waypoints.length) {
30289	    connection.waypoints = [
30290	      source ? getMid(source) : connectionStart,
30291	      target ? getMid(target) : connectionEnd
30292	    ];
30293	  }
30294
30295	  // optional cropping
30296	  if (this._connectionDocking && (source || target) && !noCropping) {
30297	    connection.waypoints = this._connectionDocking.getCroppedWaypoints(connection, source, target);
30298	  }
30299
30300	  this._graphicsFactory.drawConnection(connectionPreviewGfx, connection);
30301	};
30302
30303	/**
30304	 * Draw simple connection between source and target or provided points.
30305	 *
30306	 * @param {SVGElement} connectionPreviewGfx container for the connection
30307	 * @param {Object} hints
30308	 * @param {djs.model.shape} [hints.source] source element
30309	 * @param {djs.model.shape} [hints.target] target element
30310	 * @param {Point} [hints.connectionStart] required if source is not provided
30311	 * @param {Point} [hints.connectionEnd] required if target is not provided
30312	 */
30313	ConnectionPreview.prototype.drawNoopPreview = function(connectionPreviewGfx, hints) {
30314	  var source = hints.source,
30315	      target = hints.target,
30316	      start = hints.connectionStart || getMid(source),
30317	      end = hints.connectionEnd || getMid(target);
30318
30319	  var waypoints = this.cropWaypoints(start, end, source, target);
30320
30321	  var connection = this.createNoopConnection(waypoints[0], waypoints[1]);
30322
30323	  append(connectionPreviewGfx, connection);
30324	};
30325
30326	/**
30327	 * Return cropped waypoints.
30328	 *
30329	 * @param {Point} start
30330	 * @param {Point} end
30331	 * @param {djs.model.shape} source
30332	 * @param {djs.model.shape} target
30333	 *
30334	 * @returns {Array}
30335	 */
30336	ConnectionPreview.prototype.cropWaypoints = function(start, end, source, target) {
30337	  var graphicsFactory = this._graphicsFactory,
30338	      sourcePath = source && graphicsFactory.getShapePath(source),
30339	      targetPath = target && graphicsFactory.getShapePath(target),
30340	      connectionPath = graphicsFactory.getConnectionPath({ waypoints: [ start, end ] });
30341
30342	  start = (source && getElementLineIntersection(sourcePath, connectionPath, true)) || start;
30343	  end = (target && getElementLineIntersection(targetPath, connectionPath, false)) || end;
30344
30345	  return [ start, end ];
30346	};
30347
30348	/**
30349	 * Remove connection preview container if it exists.
30350	 *
30351	 * @param {Object} [context]
30352	 * @param {SVGElement} [context.connectionPreviewGfx] preview container
30353	 */
30354	ConnectionPreview.prototype.cleanUp = function(context) {
30355	  if (context && context.connectionPreviewGfx) {
30356	    remove$1(context.connectionPreviewGfx);
30357	  }
30358	};
30359
30360	/**
30361	 * Get connection that connects source and target.
30362	 *
30363	 * @param {Object|boolean} canConnect
30364	 *
30365	 * @returns {djs.model.connection}
30366	 */
30367	ConnectionPreview.prototype.getConnection = function(canConnect) {
30368	  var attrs = ensureConnectionAttrs(canConnect);
30369
30370	  return this._elementFactory.createConnection(attrs);
30371	};
30372
30373
30374	/**
30375	 * Add and return preview graphics.
30376	 *
30377	 * @returns {SVGElement}
30378	 */
30379	ConnectionPreview.prototype.createConnectionPreviewGfx = function() {
30380	  var gfx = create$1('g');
30381
30382	  attr(gfx, {
30383	    pointerEvents: 'none'
30384	  });
30385
30386	  classes(gfx).add(MARKER_CONNECTION_PREVIEW);
30387
30388	  append(this._canvas.getActiveLayer(), gfx);
30389
30390	  return gfx;
30391	};
30392
30393	/**
30394	 * Create and return simple connection.
30395	 *
30396	 * @param {Point} start
30397	 * @param {Point} end
30398	 *
30399	 * @returns {SVGElement}
30400	 */
30401	ConnectionPreview.prototype.createNoopConnection = function(start, end) {
30402	  var connection = create$1('polyline');
30403
30404	  attr(connection, {
30405	    'stroke': '#333',
30406	    'strokeDasharray': [ 1 ],
30407	    'strokeWidth': 2,
30408	    'pointer-events': 'none'
30409	  });
30410
30411	  attr(connection, { 'points': [ start.x, start.y, end.x, end.y ] });
30412
30413	  return connection;
30414	};
30415
30416	// helpers //////////
30417
30418	/**
30419	 * Returns function that returns cached return values referenced by stringified first argument.
30420	 *
30421	 * @param {Function} fn
30422	 *
30423	 * @return {Function}
30424	 */
30425	function cacheReturnValues(fn) {
30426	  var returnValues = {};
30427
30428	  /**
30429	   * Return cached return value referenced by stringified first argument.
30430	   *
30431	   * @returns {*}
30432	   */
30433	  return function(firstArgument) {
30434	    var key = JSON.stringify(firstArgument);
30435
30436	    var returnValue = returnValues[key];
30437
30438	    if (!returnValue) {
30439	      returnValue = returnValues[key] = fn.apply(null, arguments);
30440	    }
30441
30442	    return returnValue;
30443	  };
30444	}
30445
30446	/**
30447	 * Ensure connection attributes is object.
30448	 *
30449	 * @param {Object|boolean} canConnect
30450	 *
30451	 * @returns {Object}
30452	 */
30453	function ensureConnectionAttrs(canConnect) {
30454	  if (isObject(canConnect)) {
30455	    return canConnect;
30456	  } else {
30457	    return {};
30458	  }
30459	}
30460
30461	var ConnectionPreviewModule = {
30462	  __init__: [ 'connectionPreview' ],
30463	  connectionPreview: [ 'type', ConnectionPreview ]
30464	};
30465
30466	var min$3 = Math.min,
30467	    max$5 = Math.max;
30468
30469	function preventDefault(e) {
30470	  e.preventDefault();
30471	}
30472
30473	function stopPropagation(e) {
30474	  e.stopPropagation();
30475	}
30476
30477	function isTextNode(node) {
30478	  return node.nodeType === Node.TEXT_NODE;
30479	}
30480
30481	function toArray(nodeList) {
30482	  return [].slice.call(nodeList);
30483	}
30484
30485	/**
30486	 * Initializes a container for a content editable div.
30487	 *
30488	 * Structure:
30489	 *
30490	 * container
30491	 *   parent
30492	 *     content
30493	 *     resize-handle
30494	 *
30495	 * @param {object} options
30496	 * @param {DOMElement} options.container The DOM element to append the contentContainer to
30497	 * @param {Function} options.keyHandler Handler for key events
30498	 * @param {Function} options.resizeHandler Handler for resize events
30499	 */
30500	function TextBox(options) {
30501	  this.container = options.container;
30502
30503	  this.parent = domify(
30504	    '<div class="djs-direct-editing-parent">' +
30505	      '<div class="djs-direct-editing-content" contenteditable="true"></div>' +
30506	    '</div>'
30507	  );
30508
30509	  this.content = query('[contenteditable]', this.parent);
30510
30511	  this.keyHandler = options.keyHandler || function() {};
30512	  this.resizeHandler = options.resizeHandler || function() {};
30513
30514	  this.autoResize = bind$2(this.autoResize, this);
30515	  this.handlePaste = bind$2(this.handlePaste, this);
30516	}
30517
30518
30519	/**
30520	 * Create a text box with the given position, size, style and text content
30521	 *
30522	 * @param {Object} bounds
30523	 * @param {Number} bounds.x absolute x position
30524	 * @param {Number} bounds.y absolute y position
30525	 * @param {Number} [bounds.width] fixed width value
30526	 * @param {Number} [bounds.height] fixed height value
30527	 * @param {Number} [bounds.maxWidth] maximum width value
30528	 * @param {Number} [bounds.maxHeight] maximum height value
30529	 * @param {Number} [bounds.minWidth] minimum width value
30530	 * @param {Number} [bounds.minHeight] minimum height value
30531	 * @param {Object} [style]
30532	 * @param {String} value text content
30533	 *
30534	 * @return {DOMElement} The created content DOM element
30535	 */
30536	TextBox.prototype.create = function(bounds, style, value, options) {
30537	  var self = this;
30538
30539	  var parent = this.parent,
30540	      content = this.content,
30541	      container = this.container;
30542
30543	  options = this.options = options || {};
30544
30545	  style = this.style = style || {};
30546
30547	  var parentStyle = pick(style, [
30548	    'width',
30549	    'height',
30550	    'maxWidth',
30551	    'maxHeight',
30552	    'minWidth',
30553	    'minHeight',
30554	    'left',
30555	    'top',
30556	    'backgroundColor',
30557	    'position',
30558	    'overflow',
30559	    'border',
30560	    'wordWrap',
30561	    'textAlign',
30562	    'outline',
30563	    'transform'
30564	  ]);
30565
30566	  assign(parent.style, {
30567	    width: bounds.width + 'px',
30568	    height: bounds.height + 'px',
30569	    maxWidth: bounds.maxWidth + 'px',
30570	    maxHeight: bounds.maxHeight + 'px',
30571	    minWidth: bounds.minWidth + 'px',
30572	    minHeight: bounds.minHeight + 'px',
30573	    left: bounds.x + 'px',
30574	    top: bounds.y + 'px',
30575	    backgroundColor: '#ffffff',
30576	    position: 'absolute',
30577	    overflow: 'visible',
30578	    border: '1px solid #ccc',
30579	    boxSizing: 'border-box',
30580	    wordWrap: 'normal',
30581	    textAlign: 'center',
30582	    outline: 'none'
30583	  }, parentStyle);
30584
30585	  var contentStyle = pick(style, [
30586	    'fontFamily',
30587	    'fontSize',
30588	    'fontWeight',
30589	    'lineHeight',
30590	    'padding',
30591	    'paddingTop',
30592	    'paddingRight',
30593	    'paddingBottom',
30594	    'paddingLeft'
30595	  ]);
30596
30597	  assign(content.style, {
30598	    boxSizing: 'border-box',
30599	    width: '100%',
30600	    outline: 'none',
30601	    wordWrap: 'break-word'
30602	  }, contentStyle);
30603
30604	  if (options.centerVertically) {
30605	    assign(content.style, {
30606	      position: 'absolute',
30607	      top: '50%',
30608	      transform: 'translate(0, -50%)'
30609	    }, contentStyle);
30610	  }
30611
30612	  content.innerText = value;
30613
30614	  componentEvent.bind(content, 'keydown', this.keyHandler);
30615	  componentEvent.bind(content, 'mousedown', stopPropagation);
30616	  componentEvent.bind(content, 'paste', self.handlePaste);
30617
30618	  if (options.autoResize) {
30619	    componentEvent.bind(content, 'input', this.autoResize);
30620	  }
30621
30622	  if (options.resizable) {
30623	    this.resizable(style);
30624	  }
30625
30626	  container.appendChild(parent);
30627
30628	  // set selection to end of text
30629	  this.setSelection(content.lastChild, content.lastChild && content.lastChild.length);
30630
30631	  return parent;
30632	};
30633
30634	/**
30635	 * Intercept paste events to remove formatting from pasted text.
30636	 */
30637	TextBox.prototype.handlePaste = function(e) {
30638	  var options = this.options,
30639	      style = this.style;
30640
30641	  e.preventDefault();
30642
30643	  var text;
30644
30645	  if (e.clipboardData) {
30646
30647	    // Chrome, Firefox, Safari
30648	    text = e.clipboardData.getData('text/plain');
30649	  } else {
30650
30651	    // Internet Explorer
30652	    text = window.clipboardData.getData('Text');
30653	  }
30654
30655	  this.insertText(text);
30656
30657	  if (options.autoResize) {
30658	    var hasResized = this.autoResize(style);
30659
30660	    if (hasResized) {
30661	      this.resizeHandler(hasResized);
30662	    }
30663	  }
30664	};
30665
30666	TextBox.prototype.insertText = function(text) {
30667	  text = normalizeEndOfLineSequences(text);
30668
30669	  // insertText command not supported by Internet Explorer
30670	  var success = document.execCommand('insertText', false, text);
30671
30672	  if (success) {
30673	    return;
30674	  }
30675
30676	  this._insertTextIE(text);
30677	};
30678
30679	TextBox.prototype._insertTextIE = function(text) {
30680
30681	  // Internet Explorer
30682	  var range = this.getSelection(),
30683	      startContainer = range.startContainer,
30684	      endContainer = range.endContainer,
30685	      startOffset = range.startOffset,
30686	      endOffset = range.endOffset,
30687	      commonAncestorContainer = range.commonAncestorContainer;
30688
30689	  var childNodesArray = toArray(commonAncestorContainer.childNodes);
30690
30691	  var container,
30692	      offset;
30693
30694	  if (isTextNode(commonAncestorContainer)) {
30695	    var containerTextContent = startContainer.textContent;
30696
30697	    startContainer.textContent =
30698	      containerTextContent.substring(0, startOffset)
30699	      + text
30700	      + containerTextContent.substring(endOffset);
30701
30702	    container = startContainer;
30703	    offset = startOffset + text.length;
30704
30705	  } else if (startContainer === this.content && endContainer === this.content) {
30706	    var textNode = document.createTextNode(text);
30707
30708	    this.content.insertBefore(textNode, childNodesArray[startOffset]);
30709
30710	    container = textNode;
30711	    offset = textNode.textContent.length;
30712	  } else {
30713	    var startContainerChildIndex = childNodesArray.indexOf(startContainer),
30714	        endContainerChildIndex = childNodesArray.indexOf(endContainer);
30715
30716	    childNodesArray.forEach(function(childNode, index) {
30717
30718	      if (index === startContainerChildIndex) {
30719	        childNode.textContent =
30720	          startContainer.textContent.substring(0, startOffset) +
30721	          text +
30722	          endContainer.textContent.substring(endOffset);
30723	      } else if (index > startContainerChildIndex && index <= endContainerChildIndex) {
30724	        remove$2(childNode);
30725	      }
30726	    });
30727
30728	    container = startContainer;
30729	    offset = startOffset + text.length;
30730	  }
30731
30732	  if (container && offset !== undefined) {
30733
30734	    // is necessary in Internet Explorer
30735	    setTimeout(function() {
30736	      self.setSelection(container, offset);
30737	    });
30738	  }
30739	};
30740
30741	/**
30742	 * Automatically resize element vertically to fit its content.
30743	 */
30744	TextBox.prototype.autoResize = function() {
30745	  var parent = this.parent,
30746	      content = this.content;
30747
30748	  var fontSize = parseInt(this.style.fontSize) || 12;
30749
30750	  if (content.scrollHeight > parent.offsetHeight ||
30751	      content.scrollHeight < parent.offsetHeight - fontSize) {
30752	    var bounds = parent.getBoundingClientRect();
30753
30754	    var height = content.scrollHeight;
30755	    parent.style.height = height + 'px';
30756
30757	    this.resizeHandler({
30758	      width: bounds.width,
30759	      height: bounds.height,
30760	      dx: 0,
30761	      dy: height - bounds.height
30762	    });
30763	  }
30764	};
30765
30766	/**
30767	 * Make an element resizable by adding a resize handle.
30768	 */
30769	TextBox.prototype.resizable = function() {
30770	  var self = this;
30771
30772	  var parent = this.parent,
30773	      resizeHandle = this.resizeHandle;
30774
30775	  var minWidth = parseInt(this.style.minWidth) || 0,
30776	      minHeight = parseInt(this.style.minHeight) || 0,
30777	      maxWidth = parseInt(this.style.maxWidth) || Infinity,
30778	      maxHeight = parseInt(this.style.maxHeight) || Infinity;
30779
30780	  if (!resizeHandle) {
30781	    resizeHandle = this.resizeHandle = domify(
30782	      '<div class="djs-direct-editing-resize-handle"></div>'
30783	    );
30784
30785	    var startX, startY, startWidth, startHeight;
30786
30787	    var onMouseDown = function(e) {
30788	      preventDefault(e);
30789	      stopPropagation(e);
30790
30791	      startX = e.clientX;
30792	      startY = e.clientY;
30793
30794	      var bounds = parent.getBoundingClientRect();
30795
30796	      startWidth = bounds.width;
30797	      startHeight = bounds.height;
30798
30799	      componentEvent.bind(document, 'mousemove', onMouseMove);
30800	      componentEvent.bind(document, 'mouseup', onMouseUp);
30801	    };
30802
30803	    var onMouseMove = function(e) {
30804	      preventDefault(e);
30805	      stopPropagation(e);
30806
30807	      var newWidth = min$3(max$5(startWidth + e.clientX - startX, minWidth), maxWidth);
30808	      var newHeight = min$3(max$5(startHeight + e.clientY - startY, minHeight), maxHeight);
30809
30810	      parent.style.width = newWidth + 'px';
30811	      parent.style.height = newHeight + 'px';
30812
30813	      self.resizeHandler({
30814	        width: startWidth,
30815	        height: startHeight,
30816	        dx: e.clientX - startX,
30817	        dy: e.clientY - startY
30818	      });
30819	    };
30820
30821	    var onMouseUp = function(e) {
30822	      preventDefault(e);
30823	      stopPropagation(e);
30824
30825	      componentEvent.unbind(document,'mousemove', onMouseMove, false);
30826	      componentEvent.unbind(document, 'mouseup', onMouseUp, false);
30827	    };
30828
30829	    componentEvent.bind(resizeHandle, 'mousedown', onMouseDown);
30830	  }
30831
30832	  assign(resizeHandle.style, {
30833	    position: 'absolute',
30834	    bottom: '0px',
30835	    right: '0px',
30836	    cursor: 'nwse-resize',
30837	    width: '0',
30838	    height: '0',
30839	    borderTop: (parseInt(this.style.fontSize) / 4 || 3) + 'px solid transparent',
30840	    borderRight: (parseInt(this.style.fontSize) / 4 || 3) + 'px solid #ccc',
30841	    borderBottom: (parseInt(this.style.fontSize) / 4 || 3) + 'px solid #ccc',
30842	    borderLeft: (parseInt(this.style.fontSize) / 4 || 3) + 'px solid transparent'
30843	  });
30844
30845	  parent.appendChild(resizeHandle);
30846	};
30847
30848
30849	/**
30850	 * Clear content and style of the textbox, unbind listeners and
30851	 * reset CSS style.
30852	 */
30853	TextBox.prototype.destroy = function() {
30854	  var parent = this.parent,
30855	      content = this.content,
30856	      resizeHandle = this.resizeHandle;
30857
30858	  // clear content
30859	  content.innerText = '';
30860
30861	  // clear styles
30862	  parent.removeAttribute('style');
30863	  content.removeAttribute('style');
30864
30865	  componentEvent.unbind(content, 'keydown', this.keyHandler);
30866	  componentEvent.unbind(content, 'mousedown', stopPropagation);
30867	  componentEvent.unbind(content, 'input', this.autoResize);
30868	  componentEvent.unbind(content, 'paste', this.handlePaste);
30869
30870	  if (resizeHandle) {
30871	    resizeHandle.removeAttribute('style');
30872
30873	    remove$2(resizeHandle);
30874	  }
30875
30876	  remove$2(parent);
30877	};
30878
30879
30880	TextBox.prototype.getValue = function() {
30881	  return this.content.innerText.trim();
30882	};
30883
30884
30885	TextBox.prototype.getSelection = function() {
30886	  var selection = window.getSelection(),
30887	      range = selection.getRangeAt(0);
30888
30889	  return range;
30890	};
30891
30892
30893	TextBox.prototype.setSelection = function(container, offset) {
30894	  var range = document.createRange();
30895
30896	  if (container === null) {
30897	    range.selectNodeContents(this.content);
30898	  } else {
30899	    range.setStart(container, offset);
30900	    range.setEnd(container, offset);
30901	  }
30902
30903	  var selection = window.getSelection();
30904
30905	  selection.removeAllRanges();
30906	  selection.addRange(range);
30907	};
30908
30909	// helpers //////////
30910
30911	function normalizeEndOfLineSequences(string) {
30912	  return string.replace(/\r\n|\r|\n/g, '\n');
30913	}
30914
30915	/**
30916	 * A direct editing component that allows users
30917	 * to edit an elements text directly in the diagram
30918	 *
30919	 * @param {EventBus} eventBus the event bus
30920	 */
30921	function DirectEditing(eventBus, canvas) {
30922
30923	  this._eventBus = eventBus;
30924
30925	  this._providers = [];
30926	  this._textbox = new TextBox({
30927	    container: canvas.getContainer(),
30928	    keyHandler: bind$2(this._handleKey, this),
30929	    resizeHandler: bind$2(this._handleResize, this)
30930	  });
30931	}
30932
30933	DirectEditing.$inject = [ 'eventBus', 'canvas' ];
30934
30935
30936	/**
30937	 * Register a direct editing provider
30938
30939	 * @param {Object} provider the provider, must expose an #activate(element) method that returns
30940	 *                          an activation context ({ bounds: {x, y, width, height }, text }) if
30941	 *                          direct editing is available for the given element.
30942	 *                          Additionally the provider must expose a #update(element, value) method
30943	 *                          to receive direct editing updates.
30944	 */
30945	DirectEditing.prototype.registerProvider = function(provider) {
30946	  this._providers.push(provider);
30947	};
30948
30949
30950	/**
30951	 * Returns true if direct editing is currently active
30952	 *
30953	 * @return {Boolean}
30954	 */
30955	DirectEditing.prototype.isActive = function() {
30956	  return !!this._active;
30957	};
30958
30959
30960	/**
30961	 * Cancel direct editing, if it is currently active
30962	 */
30963	DirectEditing.prototype.cancel = function() {
30964	  if (!this._active) {
30965	    return;
30966	  }
30967
30968	  this._fire('cancel');
30969	  this.close();
30970	};
30971
30972
30973	DirectEditing.prototype._fire = function(event, context) {
30974	  this._eventBus.fire('directEditing.' + event, context || { active: this._active });
30975	};
30976
30977	DirectEditing.prototype.close = function() {
30978	  this._textbox.destroy();
30979
30980	  this._fire('deactivate');
30981
30982	  this._active = null;
30983
30984	  this.resizable = undefined;
30985	};
30986
30987
30988	DirectEditing.prototype.complete = function() {
30989
30990	  var active = this._active;
30991
30992	  if (!active) {
30993	    return;
30994	  }
30995
30996	  var containerBounds,
30997	      previousBounds = active.context.bounds,
30998	      newBounds = this.$textbox.getBoundingClientRect(),
30999	      newText = this.getValue(),
31000	      previousText = active.context.text;
31001
31002	  if (
31003	    newText !== previousText ||
31004	    newBounds.height !== previousBounds.height ||
31005	    newBounds.width !== previousBounds.width
31006	  ) {
31007	    containerBounds = this._textbox.container.getBoundingClientRect();
31008
31009	    active.provider.update(active.element, newText, active.context.text, {
31010	      x: newBounds.left - containerBounds.left,
31011	      y: newBounds.top - containerBounds.top,
31012	      width: newBounds.width,
31013	      height: newBounds.height
31014	    });
31015	  }
31016
31017	  this._fire('complete');
31018
31019	  this.close();
31020	};
31021
31022
31023	DirectEditing.prototype.getValue = function() {
31024	  return this._textbox.getValue();
31025	};
31026
31027
31028	DirectEditing.prototype._handleKey = function(e) {
31029
31030	  // stop bubble
31031	  e.stopPropagation();
31032
31033	  var key = e.keyCode || e.charCode;
31034
31035	  // ESC
31036	  if (key === 27) {
31037	    e.preventDefault();
31038	    return this.cancel();
31039	  }
31040
31041	  // Enter
31042	  if (key === 13 && !e.shiftKey) {
31043	    e.preventDefault();
31044	    return this.complete();
31045	  }
31046	};
31047
31048
31049	DirectEditing.prototype._handleResize = function(event) {
31050	  this._fire('resize', event);
31051	};
31052
31053
31054	/**
31055	 * Activate direct editing on the given element
31056	 *
31057	 * @param {Object} ElementDescriptor the descriptor for a shape or connection
31058	 * @return {Boolean} true if the activation was possible
31059	 */
31060	DirectEditing.prototype.activate = function(element) {
31061	  if (this.isActive()) {
31062	    this.cancel();
31063	  }
31064
31065	  // the direct editing context
31066	  var context;
31067
31068	  var provider = find(this._providers, function(p) {
31069	    return (context = p.activate(element)) ? p : null;
31070	  });
31071
31072	  // check if activation took place
31073	  if (context) {
31074	    this.$textbox = this._textbox.create(
31075	      context.bounds,
31076	      context.style,
31077	      context.text,
31078	      context.options
31079	    );
31080
31081	    this._active = {
31082	      element: element,
31083	      context: context,
31084	      provider: provider
31085	    };
31086
31087	    if (context.options && context.options.resizable) {
31088	      this.resizable = true;
31089	    }
31090
31091	    this._fire('activate');
31092	  }
31093
31094	  return !!context;
31095	};
31096
31097	var DirectEditingModule = {
31098	  __depends__: [
31099	    InteractionEventsModule$1
31100	  ],
31101	  __init__: [ 'directEditing' ],
31102	  directEditing: [ 'type', DirectEditing ]
31103	};
31104
31105	var entrySelector = '.entry';
31106
31107	var DEFAULT_PRIORITY$2 = 1000;
31108
31109
31110	/**
31111	 * A context pad that displays element specific, contextual actions next
31112	 * to a diagram element.
31113	 *
31114	 * @param {Object} config
31115	 * @param {boolean|Object} [config.scale={ min: 1.0, max: 1.5 }]
31116	 * @param {number} [config.scale.min]
31117	 * @param {number} [config.scale.max]
31118	 * @param {EventBus} eventBus
31119	 * @param {Overlays} overlays
31120	 */
31121	function ContextPad(config, eventBus, overlays) {
31122
31123	  this._eventBus = eventBus;
31124	  this._overlays = overlays;
31125
31126	  var scale = isDefined(config && config.scale) ? config.scale : {
31127	    min: 1,
31128	    max: 1.5
31129	  };
31130
31131	  this._overlaysConfig = {
31132	    position: {
31133	      right: -9,
31134	      top: -6
31135	    },
31136	    scale: scale
31137	  };
31138
31139	  this._current = null;
31140
31141	  this._init();
31142	}
31143
31144	ContextPad.$inject = [
31145	  'config.contextPad',
31146	  'eventBus',
31147	  'overlays'
31148	];
31149
31150
31151	/**
31152	 * Registers events needed for interaction with other components
31153	 */
31154	ContextPad.prototype._init = function() {
31155
31156	  var eventBus = this._eventBus;
31157
31158	  var self = this;
31159
31160	  eventBus.on('selection.changed', function(e) {
31161
31162	    var selection = e.newSelection;
31163
31164	    if (selection.length === 1) {
31165	      self.open(selection[0]);
31166	    } else {
31167	      self.close();
31168	    }
31169	  });
31170
31171	  eventBus.on('elements.delete', function(event) {
31172	    var elements = event.elements;
31173
31174	    forEach(elements, function(e) {
31175	      if (self.isOpen(e)) {
31176	        self.close();
31177	      }
31178	    });
31179	  });
31180
31181	  eventBus.on('element.changed', function(event) {
31182	    var element = event.element,
31183	        current = self._current;
31184
31185	    // force reopen if element for which we are currently opened changed
31186	    if (current && current.element === element) {
31187	      self.open(element, true);
31188	    }
31189	  });
31190	};
31191
31192
31193	/**
31194	 * Register a provider with the context pad
31195	 *
31196	 * @param  {number} [priority=1000]
31197	 * @param  {ContextPadProvider} provider
31198	 *
31199	 * @example
31200	 * const contextPadProvider = {
31201	  *   getContextPadEntries: function(element) {
31202	  *     return function(entries) {
31203	  *       return {
31204	  *         ...entries,
31205	  *         'entry-1': {
31206	  *           label: 'My Entry',
31207	  *           action: function() { alert("I have been clicked!"); }
31208	  *         }
31209	  *       };
31210	  *     }
31211	  *   }
31212	  * };
31213	  *
31214	 * contextPad.registerProvider(800, contextPadProvider);
31215	 */
31216	ContextPad.prototype.registerProvider = function(priority, provider) {
31217	  if (!provider) {
31218	    provider = priority;
31219	    priority = DEFAULT_PRIORITY$2;
31220	  }
31221
31222	  this._eventBus.on('contextPad.getProviders', priority, function(event) {
31223	    event.providers.push(provider);
31224	  });
31225	};
31226
31227
31228	/**
31229	 * Returns the context pad entries for a given element
31230	 *
31231	 * @param {djs.element.Base} element
31232	 *
31233	 * @return {Array<ContextPadEntryDescriptor>} list of entries
31234	 */
31235	ContextPad.prototype.getEntries = function(element) {
31236	  var providers = this._getProviders();
31237
31238	  var entries = {};
31239
31240	  // loop through all providers and their entries.
31241	  // group entries by id so that overriding an entry is possible
31242	  forEach(providers, function(provider) {
31243	    var entriesOrUpdater = provider.getContextPadEntries(element);
31244
31245	    if (isFunction(entriesOrUpdater)) {
31246	      entries = entriesOrUpdater(entries);
31247	    } else {
31248	      forEach(entriesOrUpdater, function(entry, id) {
31249	        entries[id] = entry;
31250	      });
31251	    }
31252	  });
31253
31254	  return entries;
31255	};
31256
31257
31258	/**
31259	 * Trigger an action available on the opened context pad
31260	 *
31261	 * @param  {string} action
31262	 * @param  {Event} event
31263	 * @param  {boolean} [autoActivate=false]
31264	 */
31265	ContextPad.prototype.trigger = function(action, event, autoActivate) {
31266
31267	  var element = this._current.element,
31268	      entries = this._current.entries,
31269	      entry,
31270	      handler,
31271	      originalEvent,
31272	      button = event.delegateTarget || event.target;
31273
31274	  if (!button) {
31275	    return event.preventDefault();
31276	  }
31277
31278	  entry = entries[attr$1(button, 'data-action')];
31279	  handler = entry.action;
31280
31281	  originalEvent = event.originalEvent || event;
31282
31283	  // simple action (via callback function)
31284	  if (isFunction(handler)) {
31285	    if (action === 'click') {
31286	      return handler(originalEvent, element, autoActivate);
31287	    }
31288	  } else {
31289	    if (handler[action]) {
31290	      return handler[action](originalEvent, element, autoActivate);
31291	    }
31292	  }
31293
31294	  // silence other actions
31295	  event.preventDefault();
31296	};
31297
31298
31299	/**
31300	 * Open the context pad for the given element
31301	 *
31302	 * @param {djs.model.Base} element
31303	 * @param {boolean} force if true, force reopening the context pad
31304	 */
31305	ContextPad.prototype.open = function(element, force) {
31306	  if (!force && this.isOpen(element)) {
31307	    return;
31308	  }
31309
31310	  this.close();
31311	  this._updateAndOpen(element);
31312	};
31313
31314	ContextPad.prototype._getProviders = function() {
31315
31316	  var event = this._eventBus.createEvent({
31317	    type: 'contextPad.getProviders',
31318	    providers: []
31319	  });
31320
31321	  this._eventBus.fire(event);
31322
31323	  return event.providers;
31324	};
31325
31326	ContextPad.prototype._updateAndOpen = function(element) {
31327
31328	  var entries = this.getEntries(element),
31329	      pad = this.getPad(element),
31330	      html = pad.html;
31331
31332	  forEach(entries, function(entry, id) {
31333	    var grouping = entry.group || 'default',
31334	        control = domify(entry.html || '<div class="entry" draggable="true"></div>'),
31335	        container;
31336
31337	    attr$1(control, 'data-action', id);
31338
31339	    container = query('[data-group=' + grouping + ']', html);
31340	    if (!container) {
31341	      container = domify('<div class="group" data-group="' + grouping + '"></div>');
31342	      html.appendChild(container);
31343	    }
31344
31345	    container.appendChild(control);
31346
31347	    if (entry.className) {
31348	      addClasses$1(control, entry.className);
31349	    }
31350
31351	    if (entry.title) {
31352	      attr$1(control, 'title', entry.title);
31353	    }
31354
31355	    if (entry.imageUrl) {
31356	      control.appendChild(domify('<img src="' + entry.imageUrl + '">'));
31357	    }
31358	  });
31359
31360	  classes$1(html).add('open');
31361
31362	  this._current = {
31363	    element: element,
31364	    pad: pad,
31365	    entries: entries
31366	  };
31367
31368	  this._eventBus.fire('contextPad.open', { current: this._current });
31369	};
31370
31371
31372	ContextPad.prototype.getPad = function(element) {
31373	  if (this.isOpen()) {
31374	    return this._current.pad;
31375	  }
31376
31377	  var self = this;
31378
31379	  var overlays = this._overlays;
31380
31381	  var html = domify('<div class="djs-context-pad"></div>');
31382
31383	  var overlaysConfig = assign({
31384	    html: html
31385	  }, this._overlaysConfig);
31386
31387	  delegate.bind(html, entrySelector, 'click', function(event) {
31388	    self.trigger('click', event);
31389	  });
31390
31391	  delegate.bind(html, entrySelector, 'dragstart', function(event) {
31392	    self.trigger('dragstart', event);
31393	  });
31394
31395	  // stop propagation of mouse events
31396	  componentEvent.bind(html, 'mousedown', function(event) {
31397	    event.stopPropagation();
31398	  });
31399
31400	  this._overlayId = overlays.add(element, 'context-pad', overlaysConfig);
31401
31402	  var pad = overlays.get(this._overlayId);
31403
31404	  this._eventBus.fire('contextPad.create', { element: element, pad: pad });
31405
31406	  return pad;
31407	};
31408
31409
31410	/**
31411	 * Close the context pad
31412	 */
31413	ContextPad.prototype.close = function() {
31414	  if (!this.isOpen()) {
31415	    return;
31416	  }
31417
31418	  this._overlays.remove(this._overlayId);
31419
31420	  this._overlayId = null;
31421
31422	  this._eventBus.fire('contextPad.close', { current: this._current });
31423
31424	  this._current = null;
31425	};
31426
31427	/**
31428	 * Check if pad is open. If element is given, will check
31429	 * if pad is opened with given element.
31430	 *
31431	 * @param {Element} element
31432	 * @return {boolean}
31433	 */
31434	ContextPad.prototype.isOpen = function(element) {
31435	  return !!this._current && (!element ? true : this._current.element === element);
31436	};
31437
31438
31439
31440
31441	// helpers //////////////////////
31442
31443	function addClasses$1(element, classNames) {
31444
31445	  var classes = classes$1(element);
31446
31447	  var actualClassNames = isArray$2(classNames) ? classNames : classNames.split(/\s+/g);
31448	  actualClassNames.forEach(function(cls) {
31449	    classes.add(cls);
31450	  });
31451	}
31452
31453	var ContextPadModule$1 = {
31454	  __depends__: [
31455	    InteractionEventsModule$1,
31456	    OverlaysModule
31457	  ],
31458	  contextPad: [ 'type', ContextPad ]
31459	};
31460
31461	var MARKER_TYPES = [
31462	  'marker-start',
31463	  'marker-mid',
31464	  'marker-end'
31465	];
31466
31467	var NODES_CAN_HAVE_MARKER = [
31468	  'circle',
31469	  'ellipse',
31470	  'line',
31471	  'path',
31472	  'polygon',
31473	  'polyline',
31474	  'rect'
31475	];
31476
31477
31478	/**
31479	 * Adds support for previews of moving/resizing elements.
31480	 */
31481	function PreviewSupport(elementRegistry, eventBus, canvas, styles) {
31482	  this._elementRegistry = elementRegistry;
31483	  this._canvas = canvas;
31484	  this._styles = styles;
31485
31486	  this._clonedMarkers = {};
31487
31488	  var self = this;
31489
31490	  eventBus.on('drag.cleanup', function() {
31491	    forEach(self._clonedMarkers, function(clonedMarker) {
31492	      remove$1(clonedMarker);
31493	    });
31494
31495	    self._clonedMarkers = {};
31496	  });
31497	}
31498
31499	PreviewSupport.$inject = [
31500	  'elementRegistry',
31501	  'eventBus',
31502	  'canvas',
31503	  'styles'
31504	];
31505
31506
31507	/**
31508	 * Returns graphics of an element.
31509	 *
31510	 * @param {djs.model.Base} element
31511	 *
31512	 * @return {SVGElement}
31513	 */
31514	PreviewSupport.prototype.getGfx = function(element) {
31515	  return this._elementRegistry.getGraphics(element);
31516	};
31517
31518	/**
31519	 * Adds a move preview of a given shape to a given svg group.
31520	 *
31521	 * @param {djs.model.Base} element
31522	 * @param {SVGElement} group
31523	 * @param {SVGElement} [gfx]
31524	 *
31525	 * @return {SVGElement} dragger
31526	 */
31527	PreviewSupport.prototype.addDragger = function(element, group, gfx) {
31528	  gfx = gfx || this.getGfx(element);
31529
31530	  var dragger = clone$1(gfx);
31531	  var bbox = gfx.getBoundingClientRect();
31532
31533	  this._cloneMarkers(getVisual(dragger));
31534
31535	  attr(dragger, this._styles.cls('djs-dragger', [], {
31536	    x: bbox.top,
31537	    y: bbox.left
31538	  }));
31539
31540	  append(group, dragger);
31541
31542	  return dragger;
31543	};
31544
31545	/**
31546	 * Adds a resize preview of a given shape to a given svg group.
31547	 *
31548	 * @param {djs.model.Base} element
31549	 * @param {SVGElement} group
31550	 *
31551	 * @return {SVGElement} frame
31552	 */
31553	PreviewSupport.prototype.addFrame = function(shape, group) {
31554
31555	  var frame = create$1('rect', {
31556	    class: 'djs-resize-overlay',
31557	    width:  shape.width,
31558	    height: shape.height,
31559	    x: shape.x,
31560	    y: shape.y
31561	  });
31562
31563	  append(group, frame);
31564
31565	  return frame;
31566	};
31567
31568	/**
31569	 * Clone all markers referenced by a node and its child nodes.
31570	 *
31571	 * @param {SVGElement} gfx
31572	 */
31573	PreviewSupport.prototype._cloneMarkers = function(gfx) {
31574	  var self = this;
31575
31576	  if (gfx.childNodes) {
31577
31578	    // TODO: use forEach once we drop PhantomJS
31579	    for (var i = 0; i < gfx.childNodes.length; i++) {
31580
31581	      // recursively clone markers of child nodes
31582	      self._cloneMarkers(gfx.childNodes[ i ]);
31583	    }
31584	  }
31585
31586	  if (!canHaveMarker(gfx)) {
31587	    return;
31588	  }
31589
31590	  MARKER_TYPES.forEach(function(markerType) {
31591	    if (attr(gfx, markerType)) {
31592	      var marker = getMarker(gfx, markerType, self._canvas.getContainer());
31593
31594	      self._cloneMarker(gfx, marker, markerType);
31595	    }
31596	  });
31597	};
31598
31599	/**
31600	 * Clone marker referenced by an element.
31601	 *
31602	 * @param {SVGElement} gfx
31603	 * @param {SVGElement} marker
31604	 * @param {string} markerType
31605	 */
31606	PreviewSupport.prototype._cloneMarker = function(gfx, marker, markerType) {
31607	  var markerId = marker.id;
31608
31609	  var clonedMarker = this._clonedMarkers[ markerId ];
31610
31611	  if (!clonedMarker) {
31612	    clonedMarker = clone$1(marker);
31613
31614	    var clonedMarkerId = markerId + '-clone';
31615
31616	    clonedMarker.id = clonedMarkerId;
31617
31618	    classes(clonedMarker)
31619	      .add('djs-dragger')
31620	      .add('djs-dragger-marker');
31621
31622	    this._clonedMarkers[ markerId ] = clonedMarker;
31623
31624	    var defs = query('defs', this._canvas._svg);
31625
31626	    if (!defs) {
31627	      defs = create$1('defs');
31628
31629	      append(this._canvas._svg, defs);
31630	    }
31631
31632	    append(defs, clonedMarker);
31633	  }
31634
31635	  var reference = idToReference(this._clonedMarkers[ markerId ].id);
31636
31637	  attr(gfx, markerType, reference);
31638	};
31639
31640	// helpers //////////
31641
31642	/**
31643	 * Get marker of given type referenced by node.
31644	 *
31645	 * @param {Node} node
31646	 * @param {string} markerType
31647	 * @param {Node} [parentNode]
31648	 *
31649	 * @param {Node}
31650	 */
31651	function getMarker(node, markerType, parentNode) {
31652	  var id = referenceToId(attr(node, markerType));
31653
31654	  return query('marker#' + id, parentNode || document);
31655	}
31656
31657	/**
31658	 * Get ID of fragment within current document from its functional IRI reference.
31659	 * References may use single or double quotes.
31660	 *
31661	 * @param {string} reference
31662	 *
31663	 * @returns {string}
31664	 */
31665	function referenceToId(reference) {
31666	  return reference.match(/url\(['"]?#([^'"]*)['"]?\)/)[1];
31667	}
31668
31669	/**
31670	 * Get functional IRI reference for given ID of fragment within current document.
31671	 *
31672	 * @param {string} id
31673	 *
31674	 * @returns {string}
31675	 */
31676	function idToReference(id) {
31677	  return 'url(#' + id + ')';
31678	}
31679
31680	/**
31681	 * Check wether node type can have marker attributes.
31682	 *
31683	 * @param {Node} node
31684	 *
31685	 * @returns {boolean}
31686	 */
31687	function canHaveMarker(node) {
31688	  return NODES_CAN_HAVE_MARKER.indexOf(node.nodeName) !== -1;
31689	}
31690
31691	var PreviewSupportModule = {
31692	  __init__: [ 'previewSupport' ],
31693	  previewSupport: [ 'type', PreviewSupport ]
31694	};
31695
31696	var MARKER_OK$2 = 'drop-ok',
31697	    MARKER_NOT_OK$2 = 'drop-not-ok',
31698	    MARKER_ATTACH$2 = 'attach-ok',
31699	    MARKER_NEW_PARENT$1 = 'new-parent';
31700
31701	var PREFIX = 'create';
31702
31703	var HIGH_PRIORITY$g = 2000;
31704
31705
31706	/**
31707	 * Create new elements through drag and drop.
31708	 *
31709	 * @param {Canvas} canvas
31710	 * @param {Dragging} dragging
31711	 * @param {EventBus} eventBus
31712	 * @param {Modeling} modeling
31713	 * @param {Rules} rules
31714	 */
31715	function Create(
31716	    canvas,
31717	    dragging,
31718	    eventBus,
31719	    modeling,
31720	    rules
31721	) {
31722
31723	  // rules //////////
31724
31725	  /**
31726	   * Check wether elements can be created.
31727	   *
31728	   * @param {Array<djs.model.Base>} elements
31729	   * @param {djs.model.Base} target
31730	   * @param {Point} position
31731	   * @param {djs.model.Base} [source]
31732	   *
31733	   * @returns {boolean|null|Object}
31734	   */
31735	  function canCreate(elements, target, position, source, hints) {
31736	    if (!target) {
31737	      return false;
31738	    }
31739
31740	    // ignore child elements and external labels
31741	    elements = filter(elements, function(element) {
31742	      var labelTarget = element.labelTarget;
31743
31744	      return !element.parent && !(isLabel$5(element) && elements.indexOf(labelTarget) !== -1);
31745	    });
31746
31747	    var shape = find(elements, function(element) {
31748	      return !isConnection$b(element);
31749	    });
31750
31751	    var attach = false,
31752	        connect = false,
31753	        create = false;
31754
31755	    // (1) attaching single shapes
31756	    if (isSingleShape(elements)) {
31757	      attach = rules.allowed('shape.attach', {
31758	        position: position,
31759	        shape: shape,
31760	        target: target
31761	      });
31762	    }
31763
31764	    if (!attach) {
31765
31766	      // (2) creating elements
31767	      if (isSingleShape(elements)) {
31768	        create = rules.allowed('shape.create', {
31769	          position: position,
31770	          shape: shape,
31771	          source: source,
31772	          target: target
31773	        });
31774	      } else {
31775	        create = rules.allowed('elements.create', {
31776	          elements: elements,
31777	          position: position,
31778	          target: target
31779	        });
31780	      }
31781
31782	    }
31783
31784	    var connectionTarget = hints.connectionTarget;
31785
31786	    // (3) appending single shapes
31787	    if (create || attach) {
31788	      if (shape && source) {
31789	        connect = rules.allowed('connection.create', {
31790	          source: connectionTarget === source ? shape : source,
31791	          target: connectionTarget === source ? source : shape,
31792	          hints: {
31793	            targetParent: target,
31794	            targetAttach: attach
31795	          }
31796	        });
31797	      }
31798
31799	      return {
31800	        attach: attach,
31801	        connect: connect
31802	      };
31803	    }
31804
31805	    // ignore wether or not elements can be created
31806	    if (create === null || attach === null) {
31807	      return null;
31808	    }
31809
31810	    return false;
31811	  }
31812
31813	  function setMarker(element, marker) {
31814	    [ MARKER_ATTACH$2, MARKER_OK$2, MARKER_NOT_OK$2, MARKER_NEW_PARENT$1 ].forEach(function(m) {
31815
31816	      if (m === marker) {
31817	        canvas.addMarker(element, m);
31818	      } else {
31819	        canvas.removeMarker(element, m);
31820	      }
31821	    });
31822	  }
31823
31824	  // event handling //////////
31825
31826	  eventBus.on([ 'create.move', 'create.hover' ], function(event) {
31827	    var context = event.context,
31828	        elements = context.elements,
31829	        hover = event.hover,
31830	        source = context.source,
31831	        hints = context.hints || {};
31832
31833	    if (!hover) {
31834	      context.canExecute = false;
31835	      context.target = null;
31836
31837	      return;
31838	    }
31839
31840	    ensureConstraints$2(event);
31841
31842	    var position = {
31843	      x: event.x,
31844	      y: event.y
31845	    };
31846
31847	    var canExecute = context.canExecute = hover && canCreate(elements, hover, position, source, hints);
31848
31849	    if (hover && canExecute !== null) {
31850	      context.target = hover;
31851
31852	      if (canExecute && canExecute.attach) {
31853	        setMarker(hover, MARKER_ATTACH$2);
31854	      } else {
31855	        setMarker(hover, canExecute ? MARKER_NEW_PARENT$1 : MARKER_NOT_OK$2);
31856	      }
31857	    }
31858	  });
31859
31860	  eventBus.on([ 'create.end', 'create.out', 'create.cleanup' ], function(event) {
31861	    var hover = event.hover;
31862
31863	    if (hover) {
31864	      setMarker(hover, null);
31865	    }
31866	  });
31867
31868	  eventBus.on('create.end', function(event) {
31869	    var context = event.context,
31870	        source = context.source,
31871	        shape = context.shape,
31872	        elements = context.elements,
31873	        target = context.target,
31874	        canExecute = context.canExecute,
31875	        attach = canExecute && canExecute.attach,
31876	        connect = canExecute && canExecute.connect,
31877	        hints = context.hints || {};
31878
31879	    if (canExecute === false || !target) {
31880	      return false;
31881	    }
31882
31883	    ensureConstraints$2(event);
31884
31885	    var position = {
31886	      x: event.x,
31887	      y: event.y
31888	    };
31889
31890	    if (connect) {
31891	      shape = modeling.appendShape(source, shape, position, target, {
31892	        attach: attach,
31893	        connection: connect === true ? {} : connect,
31894	        connectionTarget: hints.connectionTarget
31895	      });
31896	    } else {
31897	      elements = modeling.createElements(elements, position, target, assign({}, hints, {
31898	        attach: attach
31899	      }));
31900
31901	      // update shape
31902	      shape = find(elements, function(element) {
31903	        return !isConnection$b(element);
31904	      });
31905	    }
31906
31907	    // update elements and shape
31908	    assign(context, {
31909	      elements: elements,
31910	      shape: shape
31911	    });
31912
31913	    assign(event, {
31914	      elements: elements,
31915	      shape: shape
31916	    });
31917	  });
31918
31919	  function cancel() {
31920	    var context = dragging.context();
31921
31922	    if (context && context.prefix === PREFIX) {
31923	      dragging.cancel();
31924	    }
31925	  }
31926
31927	  // cancel on <elements.changed> that is not result of <drag.end>
31928	  eventBus.on('create.init', function() {
31929	    eventBus.on('elements.changed', cancel);
31930
31931	    eventBus.once([ 'create.cancel', 'create.end' ], HIGH_PRIORITY$g, function() {
31932	      eventBus.off('elements.changed', cancel);
31933	    });
31934	  });
31935
31936	  // API //////////
31937
31938	  this.start = function(event, elements, context) {
31939	    if (!isArray$2(elements)) {
31940	      elements = [ elements ];
31941	    }
31942
31943	    var shape = find(elements, function(element) {
31944	      return !isConnection$b(element);
31945	    });
31946
31947	    if (!shape) {
31948
31949	      // at least one shape is required
31950	      return;
31951	    }
31952
31953	    context = assign({
31954	      elements: elements,
31955	      hints: {},
31956	      shape: shape
31957	    }, context || {});
31958
31959	    // make sure each element has x and y
31960	    forEach(elements, function(element) {
31961	      if (!isNumber(element.x)) {
31962	        element.x = 0;
31963	      }
31964
31965	      if (!isNumber(element.y)) {
31966	        element.y = 0;
31967	      }
31968	    });
31969
31970	    var bbox = getBBox(elements);
31971
31972	    // center elements around cursor
31973	    forEach(elements, function(element) {
31974	      if (isConnection$b(element)) {
31975	        element.waypoints = map$1(element.waypoints, function(waypoint) {
31976	          return {
31977	            x: waypoint.x - bbox.x - bbox.width / 2,
31978	            y: waypoint.y - bbox.y - bbox.height / 2
31979	          };
31980	        });
31981	      }
31982
31983	      assign(element, {
31984	        x: element.x - bbox.x - bbox.width / 2,
31985	        y: element.y - bbox.y - bbox.height / 2
31986	      });
31987	    });
31988
31989	    dragging.init(event, PREFIX, {
31990	      cursor: 'grabbing',
31991	      autoActivate: true,
31992	      data: {
31993	        shape: shape,
31994	        elements: elements,
31995	        context: context
31996	      }
31997	    });
31998	  };
31999	}
32000
32001	Create.$inject = [
32002	  'canvas',
32003	  'dragging',
32004	  'eventBus',
32005	  'modeling',
32006	  'rules'
32007	];
32008
32009	// helpers //////////
32010
32011	function ensureConstraints$2(event) {
32012	  var context = event.context,
32013	      createConstraints = context.createConstraints;
32014
32015	  if (!createConstraints) {
32016	    return;
32017	  }
32018
32019	  if (createConstraints.left) {
32020	    event.x = Math.max(event.x, createConstraints.left);
32021	  }
32022
32023	  if (createConstraints.right) {
32024	    event.x = Math.min(event.x, createConstraints.right);
32025	  }
32026
32027	  if (createConstraints.top) {
32028	    event.y = Math.max(event.y, createConstraints.top);
32029	  }
32030
32031	  if (createConstraints.bottom) {
32032	    event.y = Math.min(event.y, createConstraints.bottom);
32033	  }
32034	}
32035
32036	function isConnection$b(element) {
32037	  return !!element.waypoints;
32038	}
32039
32040	function isSingleShape(elements) {
32041	  return elements && elements.length === 1 && !isConnection$b(elements[0]);
32042	}
32043
32044	function isLabel$5(element) {
32045	  return !!element.labelTarget;
32046	}
32047
32048	var LOW_PRIORITY$g = 750;
32049
32050
32051	function CreatePreview(
32052	    canvas,
32053	    eventBus,
32054	    graphicsFactory,
32055	    previewSupport,
32056	    styles
32057	) {
32058	  function createDragGroup(elements) {
32059	    var dragGroup = create$1('g');
32060
32061	    attr(dragGroup, styles.cls('djs-drag-group', [ 'no-events' ]));
32062
32063	    var childrenGfx = create$1('g');
32064
32065	    elements.forEach(function(element) {
32066
32067	      // create graphics
32068	      var gfx;
32069
32070	      if (element.hidden) {
32071	        return;
32072	      }
32073
32074	      if (element.waypoints) {
32075	        gfx = graphicsFactory._createContainer('connection', childrenGfx);
32076
32077	        graphicsFactory.drawConnection(getVisual(gfx), element);
32078	      } else {
32079	        gfx = graphicsFactory._createContainer('shape', childrenGfx);
32080
32081	        graphicsFactory.drawShape(getVisual(gfx), element);
32082
32083	        translate$2(gfx, element.x, element.y);
32084	      }
32085
32086	      // add preview
32087	      previewSupport.addDragger(element, dragGroup, gfx);
32088	    });
32089
32090	    return dragGroup;
32091	  }
32092
32093	  eventBus.on('create.move', LOW_PRIORITY$g, function(event) {
32094
32095	    var hover = event.hover,
32096	        context = event.context,
32097	        elements = context.elements,
32098	        dragGroup = context.dragGroup;
32099
32100	    // lazily create previews
32101	    if (!dragGroup) {
32102	      dragGroup = context.dragGroup = createDragGroup(elements);
32103	    }
32104
32105	    var activeLayer;
32106
32107	    if (hover) {
32108	      if (!dragGroup.parentNode) {
32109	        activeLayer = canvas.getActiveLayer();
32110
32111	        append(activeLayer, dragGroup);
32112	      }
32113
32114	      translate$2(dragGroup, event.x, event.y);
32115	    } else {
32116	      remove$1(dragGroup);
32117	    }
32118	  });
32119
32120	  eventBus.on('create.cleanup', function(event) {
32121	    var context = event.context,
32122	        dragGroup = context.dragGroup;
32123
32124	    if (dragGroup) {
32125	      remove$1(dragGroup);
32126	    }
32127	  });
32128	}
32129
32130	CreatePreview.$inject = [
32131	  'canvas',
32132	  'eventBus',
32133	  'graphicsFactory',
32134	  'previewSupport',
32135	  'styles'
32136	];
32137
32138	var CreateModule = {
32139	  __depends__: [
32140	    DraggingModule,
32141	    PreviewSupportModule,
32142	    RulesModule$1,
32143	    SelectionModule
32144	  ],
32145	  __init__: [
32146	    'create',
32147	    'createPreview'
32148	  ],
32149	  create: [ 'type', Create ],
32150	  createPreview: [ 'type', CreatePreview ]
32151	};
32152
32153	var DATA_REF = 'data-id';
32154
32155	var CLOSE_EVENTS = [
32156	  'contextPad.close',
32157	  'canvas.viewbox.changing',
32158	  'commandStack.changed'
32159	];
32160
32161	var DEFAULT_PRIORITY$1 = 1000;
32162
32163
32164	/**
32165	 * A popup menu that can be used to display a list of actions anywhere in the canvas.
32166	 *
32167	 * @param {Object} config
32168	 * @param {boolean|Object} [config.scale={ min: 1.0, max: 1.5 }]
32169	 * @param {number} [config.scale.min]
32170	 * @param {number} [config.scale.max]
32171	 * @param {EventBus} eventBus
32172	 * @param {Canvas} canvas
32173	 *
32174	 * @class
32175	 * @constructor
32176	 */
32177	function PopupMenu(config, eventBus, canvas) {
32178
32179	  var scale = isDefined(config && config.scale) ? config.scale : {
32180	    min: 1,
32181	    max: 1.5
32182	  };
32183
32184	  this._config = {
32185	    scale: scale
32186	  };
32187
32188	  this._eventBus = eventBus;
32189	  this._canvas = canvas;
32190	  this._providers = {};
32191	  this._current = {};
32192	}
32193
32194	PopupMenu.$inject = [
32195	  'config.popupMenu',
32196	  'eventBus',
32197	  'canvas'
32198	];
32199
32200	/**
32201	 * Registers a popup menu provider
32202	 *
32203	 * @param  {string} id
32204	 * @param {number} [priority=1000]
32205	 * @param  {Object} provider
32206	 *
32207	 * @example
32208	 * const popupMenuProvider = {
32209	 *   getPopupMenuEntries: function(element) {
32210	 *     return {
32211	 *       'entry-1': {
32212	 *         label: 'My Entry',
32213	 *         action: function() { alert("I have been clicked!"); }
32214	 *       }
32215	 *     }
32216	 *   }
32217	 * };
32218	 *
32219	 * popupMenu.registerProvider('myMenuID', popupMenuProvider);
32220	 */
32221	PopupMenu.prototype.registerProvider = function(id, priority, provider) {
32222	  if (!provider) {
32223	    provider = priority;
32224	    priority = DEFAULT_PRIORITY$1;
32225	  }
32226
32227	  this._eventBus.on('popupMenu.getProviders.' + id, priority, function(event) {
32228	    event.providers.push(provider);
32229	  });
32230	};
32231
32232	/**
32233	 * Determine if the popup menu has entries.
32234	 *
32235	 * @return {boolean} true if empty
32236	 */
32237	PopupMenu.prototype.isEmpty = function(element, providerId) {
32238	  if (!element) {
32239	    throw new Error('element parameter is missing');
32240	  }
32241
32242	  if (!providerId) {
32243	    throw new Error('providerId parameter is missing');
32244	  }
32245
32246	  var providers = this._getProviders(providerId);
32247
32248	  if (!providers) {
32249	    return true;
32250	  }
32251
32252	  var entries = this._getEntries(element, providers),
32253	      headerEntries = this._getHeaderEntries(element, providers);
32254
32255	  var hasEntries = size(entries) > 0,
32256	      hasHeaderEntries = headerEntries && size(headerEntries) > 0;
32257
32258	  return !hasEntries && !hasHeaderEntries;
32259	};
32260
32261
32262	/**
32263	 * Create entries and open popup menu at given position
32264	 *
32265	 * @param  {Object} element
32266	 * @param  {string} id provider id
32267	 * @param  {Object} position
32268	 *
32269	 * @return {Object} popup menu instance
32270	 */
32271	PopupMenu.prototype.open = function(element, id, position) {
32272
32273	  var providers = this._getProviders(id);
32274
32275	  if (!element) {
32276	    throw new Error('Element is missing');
32277	  }
32278
32279	  if (!providers || !providers.length) {
32280	    throw new Error('No registered providers for: ' + id);
32281	  }
32282
32283	  if (!position) {
32284	    throw new Error('the position argument is missing');
32285	  }
32286
32287	  if (this.isOpen()) {
32288	    this.close();
32289	  }
32290
32291	  this._emit('open');
32292
32293	  var current = this._current = {
32294	    className: id,
32295	    element: element,
32296	    position: position
32297	  };
32298
32299	  var entries = this._getEntries(element, providers),
32300	      headerEntries = this._getHeaderEntries(element, providers);
32301
32302	  current.entries = assign({}, entries, headerEntries);
32303
32304	  current.container = this._createContainer();
32305
32306	  if (size(headerEntries)) {
32307	    current.container.appendChild(
32308	      this._createEntries(headerEntries, 'djs-popup-header')
32309	    );
32310	  }
32311
32312	  if (size(entries)) {
32313	    current.container.appendChild(
32314	      this._createEntries(entries, 'djs-popup-body')
32315	    );
32316	  }
32317
32318	  var canvas = this._canvas,
32319	      parent = canvas.getContainer();
32320
32321	  this._attachContainer(current.container, parent, position.cursor);
32322	  this._bindAutoClose();
32323	};
32324
32325
32326	/**
32327	 * Removes the popup menu and unbinds the event handlers.
32328	 */
32329	PopupMenu.prototype.close = function() {
32330
32331	  if (!this.isOpen()) {
32332	    return;
32333	  }
32334
32335	  this._emit('close');
32336
32337	  this._unbindAutoClose();
32338	  remove$2(this._current.container);
32339	  this._current.container = null;
32340	};
32341
32342
32343	/**
32344	 * Determine if an open popup menu exist.
32345	 *
32346	 * @return {boolean} true if open
32347	 */
32348	PopupMenu.prototype.isOpen = function() {
32349	  return !!this._current.container;
32350	};
32351
32352
32353	/**
32354	 * Trigger an action associated with an entry.
32355	 *
32356	 * @param {Object} event
32357	 *
32358	 * @return the result of the action callback, if any
32359	 */
32360	PopupMenu.prototype.trigger = function(event) {
32361
32362	  // silence other actions
32363	  event.preventDefault();
32364
32365	  var element = event.delegateTarget || event.target,
32366	      entryId = attr$1(element, DATA_REF);
32367
32368	  var entry = this._getEntry(entryId);
32369
32370	  if (entry.action) {
32371	    return entry.action.call(null, event, entry);
32372	  }
32373	};
32374
32375	PopupMenu.prototype._getProviders = function(id) {
32376
32377	  var event = this._eventBus.createEvent({
32378	    type: 'popupMenu.getProviders.' + id,
32379	    providers: []
32380	  });
32381
32382	  this._eventBus.fire(event);
32383
32384	  return event.providers;
32385	};
32386
32387	PopupMenu.prototype._getEntries = function(element, providers) {
32388
32389	  var entries = {};
32390
32391	  forEach(providers, function(provider) {
32392
32393	    // handle legacy method
32394	    if (!provider.getPopupMenuEntries) {
32395	      forEach(provider.getEntries(element), function(entry) {
32396	        var id = entry.id;
32397
32398	        if (!id) {
32399	          throw new Error('every entry must have the id property set');
32400	        }
32401
32402	        entries[id] = omit(entry, [ 'id' ]);
32403	      });
32404
32405	      return;
32406	    }
32407
32408	    var entriesOrUpdater = provider.getPopupMenuEntries(element);
32409
32410	    if (isFunction(entriesOrUpdater)) {
32411	      entries = entriesOrUpdater(entries);
32412	    } else {
32413	      forEach(entriesOrUpdater, function(entry, id) {
32414	        entries[id] = entry;
32415	      });
32416	    }
32417	  });
32418
32419	  return entries;
32420	};
32421
32422	PopupMenu.prototype._getHeaderEntries = function(element, providers) {
32423
32424	  var entries = {};
32425
32426	  forEach(providers, function(provider) {
32427
32428	    // handle legacy method
32429	    if (!provider.getPopupMenuHeaderEntries) {
32430	      if (!provider.getHeaderEntries) {
32431	        return;
32432	      }
32433
32434	      forEach(provider.getHeaderEntries(element), function(entry) {
32435	        var id = entry.id;
32436
32437	        if (!id) {
32438	          throw new Error('every entry must have the id property set');
32439	        }
32440
32441	        entries[id] = omit(entry, [ 'id' ]);
32442	      });
32443
32444	      return;
32445	    }
32446
32447	    var entriesOrUpdater = provider.getPopupMenuHeaderEntries(element);
32448
32449	    if (isFunction(entriesOrUpdater)) {
32450	      entries = entriesOrUpdater(entries);
32451	    } else {
32452	      forEach(entriesOrUpdater, function(entry, id) {
32453	        entries[id] = entry;
32454	      });
32455	    }
32456	  });
32457
32458	  return entries;
32459
32460
32461	};
32462
32463	/**
32464	 * Gets an entry instance (either entry or headerEntry) by id.
32465	 *
32466	 * @param  {string} entryId
32467	 *
32468	 * @return {Object} entry instance
32469	 */
32470	PopupMenu.prototype._getEntry = function(entryId) {
32471
32472	  var entry = this._current.entries[entryId];
32473
32474	  if (!entry) {
32475	    throw new Error('entry not found');
32476	  }
32477
32478	  return entry;
32479	};
32480
32481	PopupMenu.prototype._emit = function(eventName) {
32482	  this._eventBus.fire('popupMenu.' + eventName);
32483	};
32484
32485	/**
32486	 * Creates the popup menu container.
32487	 *
32488	 * @return {Object} a DOM container
32489	 */
32490	PopupMenu.prototype._createContainer = function() {
32491	  var container = domify('<div class="djs-popup">'),
32492	      position = this._current.position,
32493	      className = this._current.className;
32494
32495	  assign(container.style, {
32496	    position: 'absolute',
32497	    left: position.x + 'px',
32498	    top: position.y + 'px',
32499	    visibility: 'hidden'
32500	  });
32501
32502	  classes$1(container).add(className);
32503
32504	  return container;
32505	};
32506
32507
32508	/**
32509	 * Attaches the container to the DOM.
32510	 *
32511	 * @param {Object} container
32512	 * @param {Object} parent
32513	 */
32514	PopupMenu.prototype._attachContainer = function(container, parent, cursor) {
32515	  var self = this;
32516
32517	  // Event handler
32518	  delegate.bind(container, '.entry' ,'click', function(event) {
32519	    self.trigger(event);
32520	  });
32521
32522	  this._updateScale(container);
32523
32524	  // Attach to DOM
32525	  parent.appendChild(container);
32526
32527	  if (cursor) {
32528	    this._assureIsInbounds(container, cursor);
32529	  }
32530	};
32531
32532
32533	/**
32534	 * Updates popup style.transform with respect to the config and zoom level.
32535	 *
32536	 * @method _updateScale
32537	 *
32538	 * @param {Object} container
32539	 */
32540	PopupMenu.prototype._updateScale = function(container) {
32541	  var zoom = this._canvas.zoom();
32542
32543	  var scaleConfig = this._config.scale,
32544	      minScale,
32545	      maxScale,
32546	      scale = zoom;
32547
32548	  if (scaleConfig !== true) {
32549
32550	    if (scaleConfig === false) {
32551	      minScale = 1;
32552	      maxScale = 1;
32553	    } else {
32554	      minScale = scaleConfig.min;
32555	      maxScale = scaleConfig.max;
32556	    }
32557
32558	    if (isDefined(minScale) && zoom < minScale) {
32559	      scale = minScale;
32560	    }
32561
32562	    if (isDefined(maxScale) && zoom > maxScale) {
32563	      scale = maxScale;
32564	    }
32565
32566	  }
32567
32568	  setTransform(container, 'scale(' + scale + ')');
32569	};
32570
32571
32572	/**
32573	 * Make sure that the menu is always fully shown
32574	 *
32575	 * @method function
32576	 *
32577	 * @param  {Object} container
32578	 * @param  {Position} cursor {x, y}
32579	 */
32580	PopupMenu.prototype._assureIsInbounds = function(container, cursor) {
32581	  var canvas = this._canvas,
32582	      clientRect = canvas._container.getBoundingClientRect();
32583
32584	  var containerX = container.offsetLeft,
32585	      containerY = container.offsetTop,
32586	      containerWidth = container.scrollWidth,
32587	      containerHeight = container.scrollHeight,
32588	      overAxis = {},
32589	      left, top;
32590
32591	  var cursorPosition = {
32592	    x: cursor.x - clientRect.left,
32593	    y: cursor.y - clientRect.top
32594	  };
32595
32596	  if (containerX + containerWidth > clientRect.width) {
32597	    overAxis.x = true;
32598	  }
32599
32600	  if (containerY + containerHeight > clientRect.height) {
32601	    overAxis.y = true;
32602	  }
32603
32604	  if (overAxis.x && overAxis.y) {
32605	    left = cursorPosition.x - containerWidth + 'px';
32606	    top = cursorPosition.y - containerHeight + 'px';
32607	  } else if (overAxis.x) {
32608	    left = cursorPosition.x - containerWidth + 'px';
32609	    top = cursorPosition.y + 'px';
32610	  } else if (overAxis.y && cursorPosition.y < containerHeight) {
32611	    left = cursorPosition.x + 'px';
32612	    top = 10 + 'px';
32613	  } else if (overAxis.y) {
32614	    left = cursorPosition.x + 'px';
32615	    top = cursorPosition.y - containerHeight + 'px';
32616	  }
32617
32618	  assign(container.style, { left: left, top: top }, { visibility: 'visible', 'z-index': 1000 });
32619	};
32620
32621
32622	/**
32623	 * Creates a list of entries and returns them as a DOM container.
32624	 *
32625	 * @param {Array<Object>} entries an array of entry objects
32626	 * @param {string} className the class name of the entry container
32627	 *
32628	 * @return {Object} a DOM container
32629	 */
32630	PopupMenu.prototype._createEntries = function(entries, className) {
32631
32632	  var entriesContainer = domify('<div>'),
32633	      self = this;
32634
32635	  classes$1(entriesContainer).add(className);
32636
32637	  forEach(entries, function(entry, id) {
32638	    var entryContainer = self._createEntry(entry, id);
32639	    entriesContainer.appendChild(entryContainer);
32640	  });
32641
32642	  return entriesContainer;
32643	};
32644
32645
32646	/**
32647	 * Creates a single entry and returns it as a DOM container.
32648	 *
32649	 * @param  {Object} entry
32650	 *
32651	 * @return {Object} a DOM container
32652	 */
32653	PopupMenu.prototype._createEntry = function(entry, id) {
32654
32655	  var entryContainer = domify('<div>'),
32656	      entryClasses = classes$1(entryContainer);
32657
32658	  entryClasses.add('entry');
32659
32660	  if (entry.className) {
32661	    entry.className.split(' ').forEach(function(className) {
32662	      entryClasses.add(className);
32663	    });
32664	  }
32665
32666	  attr$1(entryContainer, DATA_REF, id);
32667
32668	  if (entry.label) {
32669	    var label = domify('<span>');
32670	    label.textContent = entry.label;
32671	    entryContainer.appendChild(label);
32672	  }
32673
32674	  if (entry.imageUrl) {
32675	    entryContainer.appendChild(domify('<img src="' + entry.imageUrl + '" />'));
32676	  }
32677
32678	  if (entry.active === true) {
32679	    entryClasses.add('active');
32680	  }
32681
32682	  if (entry.disabled === true) {
32683	    entryClasses.add('disabled');
32684	  }
32685
32686	  if (entry.title) {
32687	    entryContainer.title = entry.title;
32688	  }
32689
32690	  return entryContainer;
32691	};
32692
32693
32694	/**
32695	 * Set up listener to close popup automatically on certain events.
32696	 */
32697	PopupMenu.prototype._bindAutoClose = function() {
32698	  this._eventBus.once(CLOSE_EVENTS, this.close, this);
32699	};
32700
32701
32702	/**
32703	 * Remove the auto-closing listener.
32704	 */
32705	PopupMenu.prototype._unbindAutoClose = function() {
32706	  this._eventBus.off(CLOSE_EVENTS, this.close, this);
32707	};
32708
32709
32710
32711	// helpers /////////////////////////////
32712
32713	function setTransform(element, transform) {
32714	  element.style['transform-origin'] = 'top left';
32715
32716	  [ '', '-ms-', '-webkit-' ].forEach(function(prefix) {
32717	    element.style[prefix + 'transform'] = transform;
32718	  });
32719	}
32720
32721	var PopupMenuModule$1 = {
32722	  __init__: [ 'popupMenu' ],
32723	  popupMenu: [ 'type', PopupMenu ]
32724	};
32725
32726	/**
32727	 * A clip board stub
32728	 */
32729	function Clipboard() {}
32730
32731
32732	Clipboard.prototype.get = function() {
32733	  return this._data;
32734	};
32735
32736	Clipboard.prototype.set = function(data) {
32737	  this._data = data;
32738	};
32739
32740	Clipboard.prototype.clear = function() {
32741	  var data = this._data;
32742
32743	  delete this._data;
32744
32745	  return data;
32746	};
32747
32748	Clipboard.prototype.isEmpty = function() {
32749	  return !this._data;
32750	};
32751
32752	var ClipboardModule = {
32753	  clipboard: [ 'type', Clipboard ]
32754	};
32755
32756	function Mouse(eventBus) {
32757	  var self = this;
32758
32759	  this._lastMoveEvent = null;
32760
32761	  function setLastMoveEvent(mousemoveEvent) {
32762	    self._lastMoveEvent = mousemoveEvent;
32763	  }
32764
32765	  eventBus.on('canvas.init', function(context) {
32766	    var svg = self._svg = context.svg;
32767
32768	    svg.addEventListener('mousemove', setLastMoveEvent);
32769	  });
32770
32771	  eventBus.on('canvas.destroy', function() {
32772	    self._lastMouseEvent = null;
32773
32774	    self._svg.removeEventListener('mousemove', setLastMoveEvent);
32775	  });
32776	}
32777
32778	Mouse.$inject = [ 'eventBus' ];
32779
32780	Mouse.prototype.getLastMoveEvent = function() {
32781	  return this._lastMoveEvent || createMoveEvent(0, 0);
32782	};
32783
32784	// helpers //////////
32785
32786	function createMoveEvent(x, y) {
32787	  var event = document.createEvent('MouseEvent');
32788
32789	  var screenX = x,
32790	      screenY = y,
32791	      clientX = x,
32792	      clientY = y;
32793
32794	  if (event.initMouseEvent) {
32795	    event.initMouseEvent(
32796	      'mousemove',
32797	      true,
32798	      true,
32799	      window,
32800	      0,
32801	      screenX,
32802	      screenY,
32803	      clientX,
32804	      clientY,
32805	      false,
32806	      false,
32807	      false,
32808	      false,
32809	      0,
32810	      null
32811	    );
32812	  }
32813
32814	  return event;
32815	}
32816
32817	var MouseModule = {
32818	  __init__: [ 'mouse' ],
32819	  mouse: [ 'type', Mouse ]
32820	};
32821
32822	/**
32823	 * @typedef {Function} <copyPaste.canCopyElements> listener
32824	 *
32825	 * @param {Object} context
32826	 * @param {Array<djs.model.Base>} context.elements
32827	 *
32828	 * @returns {Array<djs.model.Base>|boolean} - Return elements to be copied or false to disallow
32829	 * copying.
32830	 */
32831
32832	/**
32833	 * @typedef {Function} <copyPaste.copyElement> listener
32834	 *
32835	 * @param {Object} context
32836	 * @param {Object} context.descriptor
32837	 * @param {djs.model.Base} context.element
32838	 * @param {Array<djs.model.Base>} context.elements
32839	 */
32840
32841	/**
32842	 * @typedef {Function} <copyPaste.elementsCopied> listener
32843	 *
32844	 * @param {Object} context
32845	 * @param {Object} context.elements
32846	 * @param {Object} context.tree
32847	 */
32848
32849	/**
32850	 * @typedef {Function} <copyPaste.pasteElement> listener
32851	 *
32852	 * @param {Object} context
32853	 * @param {Object} context.cache - Already created elements.
32854	 * @param {Object} context.descriptor
32855	 */
32856
32857	/**
32858	 * @typedef {Function} <copyPaste.pasteElements> listener
32859	 *
32860	 * @param {Object} context
32861	 * @param {Object} context.hints - Add hints before pasting.
32862	 */
32863
32864	/**
32865	 * Copy and paste elements.
32866	 *
32867	 * @param {Canvas} canvas
32868	 * @param {Create} create
32869	 * @param {Clipboard} clipboard
32870	 * @param {ElementFactory} elementFactory
32871	 * @param {EventBus} eventBus
32872	 * @param {Modeling} modeling
32873	 * @param {Mouse} mouse
32874	 * @param {Rules} rules
32875	 */
32876	function CopyPaste(
32877	    canvas,
32878	    create,
32879	    clipboard,
32880	    elementFactory,
32881	    eventBus,
32882	    modeling,
32883	    mouse,
32884	    rules
32885	) {
32886
32887	  this._canvas = canvas;
32888	  this._create = create;
32889	  this._clipboard = clipboard;
32890	  this._elementFactory = elementFactory;
32891	  this._eventBus = eventBus;
32892	  this._modeling = modeling;
32893	  this._mouse = mouse;
32894	  this._rules = rules;
32895
32896	  eventBus.on('copyPaste.copyElement', function(context) {
32897	    var descriptor = context.descriptor,
32898	        element = context.element,
32899	        elements = context.elements;
32900
32901	    // default priority (priority = 1)
32902	    descriptor.priority = 1;
32903
32904	    descriptor.id = element.id;
32905
32906	    var parentCopied = find(elements, function(e) {
32907	      return e === element.parent;
32908	    });
32909
32910	    // do NOT reference parent if parent wasn't copied
32911	    if (parentCopied) {
32912	      descriptor.parent = element.parent.id;
32913	    }
32914
32915	    // attachers (priority = 2)
32916	    if (isAttacher$1(element)) {
32917	      descriptor.priority = 2;
32918
32919	      descriptor.host = element.host.id;
32920	    }
32921
32922	    // connections (priority = 3)
32923	    if (isConnection$a(element)) {
32924	      descriptor.priority = 3;
32925
32926	      descriptor.source = element.source.id;
32927	      descriptor.target = element.target.id;
32928
32929	      descriptor.waypoints = copyWaypoints$1(element);
32930	    }
32931
32932	    // labels (priority = 4)
32933	    if (isLabel$4(element)) {
32934	      descriptor.priority = 4;
32935
32936	      descriptor.labelTarget = element.labelTarget.id;
32937	    }
32938
32939	    forEach([ 'x', 'y', 'width', 'height' ], function(property) {
32940	      if (isNumber(element[ property ])) {
32941	        descriptor[ property ] = element[ property ];
32942	      }
32943	    });
32944
32945	    descriptor.hidden = element.hidden;
32946	    descriptor.collapsed = element.collapsed;
32947
32948	  });
32949
32950	  eventBus.on('copyPaste.pasteElements', function(context) {
32951	    var hints = context.hints;
32952
32953	    assign(hints, {
32954	      createElementsBehavior: false
32955	    });
32956	  });
32957	}
32958
32959	CopyPaste.$inject = [
32960	  'canvas',
32961	  'create',
32962	  'clipboard',
32963	  'elementFactory',
32964	  'eventBus',
32965	  'modeling',
32966	  'mouse',
32967	  'rules'
32968	];
32969
32970
32971	/**
32972	 * Copy elements.
32973	 *
32974	 * @param {Array<djs.model.Base>} elements
32975	 *
32976	 * @returns {Object}
32977	 */
32978	CopyPaste.prototype.copy = function(elements) {
32979	  var allowed,
32980	      tree;
32981
32982	  if (!isArray$2(elements)) {
32983	    elements = elements ? [ elements ] : [];
32984	  }
32985
32986	  allowed = this._eventBus.fire('copyPaste.canCopyElements', {
32987	    elements: elements
32988	  });
32989
32990	  if (allowed === false) {
32991	    tree = {};
32992	  } else {
32993	    tree = this.createTree(isArray$2(allowed) ? allowed : elements);
32994	  }
32995
32996	  // we set an empty tree, selection of elements
32997	  // to copy was empty.
32998	  this._clipboard.set(tree);
32999
33000	  this._eventBus.fire('copyPaste.elementsCopied', {
33001	    elements: elements,
33002	    tree: tree
33003	  });
33004
33005	  return tree;
33006	};
33007
33008	/**
33009	 * Paste elements.
33010	 *
33011	 * @param {Object} [context]
33012	 * @param {djs.model.base} [context.element] - Parent.
33013	 * @param {Point} [context.point] - Position.
33014	 * @param {Object} [context.hints] - Hints.
33015	 */
33016	CopyPaste.prototype.paste = function(context) {
33017	  var tree = this._clipboard.get();
33018
33019	  if (this._clipboard.isEmpty()) {
33020	    return;
33021	  }
33022
33023	  var hints = context && context.hints || {};
33024
33025	  this._eventBus.fire('copyPaste.pasteElements', {
33026	    hints: hints
33027	  });
33028
33029	  var elements = this._createElements(tree);
33030
33031	  // paste directly
33032	  if (context && context.element && context.point) {
33033	    return this._paste(elements, context.element, context.point, hints);
33034	  }
33035
33036	  this._create.start(this._mouse.getLastMoveEvent(), elements, {
33037	    hints: hints || {}
33038	  });
33039	};
33040
33041	/**
33042	 * Paste elements directly.
33043	 *
33044	 * @param {Array<djs.model.Base>} elements
33045	 * @param {djs.model.base} target
33046	 * @param {Point} position
33047	 * @param {Object} [hints]
33048	 */
33049	CopyPaste.prototype._paste = function(elements, target, position, hints) {
33050
33051	  // make sure each element has x and y
33052	  forEach(elements, function(element) {
33053	    if (!isNumber(element.x)) {
33054	      element.x = 0;
33055	    }
33056
33057	    if (!isNumber(element.y)) {
33058	      element.y = 0;
33059	    }
33060	  });
33061
33062	  var bbox = getBBox(elements);
33063
33064	  // center elements around cursor
33065	  forEach(elements, function(element) {
33066	    if (isConnection$a(element)) {
33067	      element.waypoints = map$1(element.waypoints, function(waypoint) {
33068	        return {
33069	          x: waypoint.x - bbox.x - bbox.width / 2,
33070	          y: waypoint.y - bbox.y - bbox.height / 2
33071	        };
33072	      });
33073	    }
33074
33075	    assign(element, {
33076	      x: element.x - bbox.x - bbox.width / 2,
33077	      y: element.y - bbox.y - bbox.height / 2
33078	    });
33079	  });
33080
33081	  return this._modeling.createElements(elements, position, target, assign({}, hints));
33082	};
33083
33084	/**
33085	 * Create elements from tree.
33086	 */
33087	CopyPaste.prototype._createElements = function(tree) {
33088	  var self = this;
33089
33090	  var eventBus = this._eventBus;
33091
33092	  var cache = {};
33093
33094	  var elements = [];
33095
33096	  forEach(tree, function(branch, depth) {
33097
33098	    // sort by priority
33099	    branch = sortBy(branch, 'priority');
33100
33101	    forEach(branch, function(descriptor) {
33102
33103	      // remove priority
33104	      var attrs = assign({}, omit(descriptor, [ 'priority' ]));
33105
33106	      if (cache[ descriptor.parent ]) {
33107	        attrs.parent = cache[ descriptor.parent ];
33108	      } else {
33109	        delete attrs.parent;
33110	      }
33111
33112	      eventBus.fire('copyPaste.pasteElement', {
33113	        cache: cache,
33114	        descriptor: attrs
33115	      });
33116
33117	      var element;
33118
33119	      if (isConnection$a(attrs)) {
33120	        attrs.source = cache[ descriptor.source ];
33121	        attrs.target = cache[ descriptor.target ];
33122
33123	        element = cache[ descriptor.id ] = self.createConnection(attrs);
33124
33125	        elements.push(element);
33126
33127	        return;
33128	      }
33129
33130	      if (isLabel$4(attrs)) {
33131	        attrs.labelTarget = cache[ attrs.labelTarget ];
33132
33133	        element = cache[ descriptor.id ] = self.createLabel(attrs);
33134
33135	        elements.push(element);
33136
33137	        return;
33138	      }
33139
33140	      if (attrs.host) {
33141	        attrs.host = cache[ attrs.host ];
33142	      }
33143
33144	      element = cache[ descriptor.id ] = self.createShape(attrs);
33145
33146	      elements.push(element);
33147	    });
33148
33149	  });
33150
33151	  return elements;
33152	};
33153
33154	CopyPaste.prototype.createConnection = function(attrs) {
33155	  var connection = this._elementFactory.createConnection(omit(attrs, [ 'id' ]));
33156
33157	  return connection;
33158	};
33159
33160	CopyPaste.prototype.createLabel = function(attrs) {
33161	  var label = this._elementFactory.createLabel(omit(attrs, [ 'id' ]));
33162
33163	  return label;
33164	};
33165
33166	CopyPaste.prototype.createShape = function(attrs) {
33167	  var shape = this._elementFactory.createShape(omit(attrs, [ 'id' ]));
33168
33169	  return shape;
33170	};
33171
33172	/**
33173	 * Check wether element has relations to other elements e.g. attachers, labels and connections.
33174	 *
33175	 * @param  {Object} element
33176	 * @param  {Array<djs.model.Base>} elements
33177	 *
33178	 * @returns {boolean}
33179	 */
33180	CopyPaste.prototype.hasRelations = function(element, elements) {
33181	  var labelTarget,
33182	      source,
33183	      target;
33184
33185	  if (isConnection$a(element)) {
33186	    source = find(elements, matchPattern({ id: element.source.id }));
33187	    target = find(elements, matchPattern({ id: element.target.id }));
33188
33189	    if (!source || !target) {
33190	      return false;
33191	    }
33192	  }
33193
33194	  if (isLabel$4(element)) {
33195	    labelTarget = find(elements, matchPattern({ id: element.labelTarget.id }));
33196
33197	    if (!labelTarget) {
33198	      return false;
33199	    }
33200	  }
33201
33202	  return true;
33203	};
33204
33205	/**
33206	 * Create a tree-like structure from elements.
33207	 *
33208	 * @example
33209	 * tree: {
33210	  *  0: [
33211	  *    { id: 'Shape_1', priority: 1, ... },
33212	  *    { id: 'Shape_2', priority: 1, ... },
33213	  *    { id: 'Connection_1', source: 'Shape_1', target: 'Shape_2', priority: 3, ... },
33214	  *    ...
33215	  *  ],
33216	  *  1: [
33217	  *    { id: 'Shape_3', parent: 'Shape1', priority: 1, ... },
33218	  *    ...
33219	  *  ]
33220	  * };
33221	  *
33222	  * @param  {Array<djs.model.base>} elements
33223	  *
33224	  * @return {Object}
33225	  */
33226	CopyPaste.prototype.createTree = function(elements) {
33227	  var rules = this._rules,
33228	      self = this;
33229
33230	  var tree = {},
33231	      elementsData = [];
33232
33233	  var parents = getParents$1(elements);
33234
33235	  function canCopy(element, elements) {
33236	    return rules.allowed('element.copy', {
33237	      element: element,
33238	      elements: elements
33239	    });
33240	  }
33241
33242	  function addElementData(element, depth) {
33243
33244	    // (1) check wether element has already been added
33245	    var foundElementData = find(elementsData, function(elementsData) {
33246	      return element === elementsData.element;
33247	    });
33248
33249	    // (2) add element if not already added
33250	    if (!foundElementData) {
33251	      elementsData.push({
33252	        element: element,
33253	        depth: depth
33254	      });
33255
33256	      return;
33257	    }
33258
33259	    // (3) update depth
33260	    if (foundElementData.depth < depth) {
33261	      elementsData = removeElementData(foundElementData, elementsData);
33262
33263	      elementsData.push({
33264	        element: foundElementData.element,
33265	        depth: depth
33266	      });
33267	    }
33268	  }
33269
33270	  function removeElementData(elementData, elementsData) {
33271	    var index = elementsData.indexOf(elementData);
33272
33273	    if (index !== -1) {
33274	      elementsData.splice(index, 1);
33275	    }
33276
33277	    return elementsData;
33278	  }
33279
33280	  // (1) add elements
33281	  eachElement(parents, function(element, _index, depth) {
33282
33283	    // do NOT add external labels directly
33284	    if (isLabel$4(element)) {
33285	      return;
33286	    }
33287
33288	    // always copy external labels
33289	    forEach(element.labels, function(label) {
33290	      addElementData(label, depth);
33291	    });
33292
33293	    function addRelatedElements(elements) {
33294	      elements && elements.length && forEach(elements, function(element) {
33295
33296	        // add external labels
33297	        forEach(element.labels, function(label) {
33298	          addElementData(label, depth);
33299	        });
33300
33301	        addElementData(element, depth);
33302	      });
33303	    }
33304
33305	    forEach([ element.attachers, element.incoming, element.outgoing ], addRelatedElements);
33306
33307	    addElementData(element, depth);
33308
33309	    return element.children;
33310	  });
33311
33312	  elements = map$1(elementsData, function(elementData) {
33313	    return elementData.element;
33314	  });
33315
33316	  // (2) copy elements
33317	  elementsData = map$1(elementsData, function(elementData) {
33318	    elementData.descriptor = {};
33319
33320	    self._eventBus.fire('copyPaste.copyElement', {
33321	      descriptor: elementData.descriptor,
33322	      element: elementData.element,
33323	      elements: elements
33324	    });
33325
33326	    return elementData;
33327	  });
33328
33329	  // (3) sort elements by priority
33330	  elementsData = sortBy(elementsData, function(elementData) {
33331	    return elementData.descriptor.priority;
33332	  });
33333
33334	  elements = map$1(elementsData, function(elementData) {
33335	    return elementData.element;
33336	  });
33337
33338	  // (4) create tree
33339	  forEach(elementsData, function(elementData) {
33340	    var depth = elementData.depth;
33341
33342	    if (!self.hasRelations(elementData.element, elements)) {
33343	      removeElement(elementData.element, elements);
33344
33345	      return;
33346	    }
33347
33348	    if (!canCopy(elementData.element, elements)) {
33349	      removeElement(elementData.element, elements);
33350
33351	      return;
33352	    }
33353
33354	    if (!tree[depth]) {
33355	      tree[depth] = [];
33356	    }
33357
33358	    tree[depth].push(elementData.descriptor);
33359	  });
33360
33361	  return tree;
33362	};
33363
33364	// helpers //////////
33365
33366	function isAttacher$1(element) {
33367	  return !!element.host;
33368	}
33369
33370	function isConnection$a(element) {
33371	  return !!element.waypoints;
33372	}
33373
33374	function isLabel$4(element) {
33375	  return !!element.labelTarget;
33376	}
33377
33378	function copyWaypoints$1(element) {
33379	  return map$1(element.waypoints, function(waypoint) {
33380
33381	    waypoint = copyWaypoint$1(waypoint);
33382
33383	    if (waypoint.original) {
33384	      waypoint.original = copyWaypoint$1(waypoint.original);
33385	    }
33386
33387	    return waypoint;
33388	  });
33389	}
33390
33391	function copyWaypoint$1(waypoint) {
33392	  return assign({}, waypoint);
33393	}
33394
33395	function removeElement(element, elements) {
33396	  var index = elements.indexOf(element);
33397
33398	  if (index === -1) {
33399	    return elements;
33400	  }
33401
33402	  return elements.splice(index, 1);
33403	}
33404
33405	var CopyPasteModule$1 = {
33406	  __depends__: [
33407	    ClipboardModule,
33408	    CreateModule,
33409	    MouseModule,
33410	    RulesModule$1
33411	  ],
33412	  __init__: [ 'copyPaste' ],
33413	  copyPaste: [ 'type', CopyPaste ]
33414	};
33415
33416	function copyProperties$1(source, target, properties) {
33417	  if (!isArray$2(properties)) {
33418	    properties = [ properties ];
33419	  }
33420
33421	  forEach(properties, function(property) {
33422	    if (!isUndefined$1(source[property])) {
33423	      target[property] = source[property];
33424	    }
33425	  });
33426	}
33427
33428	function removeProperties(element, properties) {
33429	  if (!isArray$2(properties)) {
33430	    properties = [ properties ];
33431	  }
33432
33433	  forEach(properties, function(property) {
33434	    if (element[property]) {
33435	      delete element[property];
33436	    }
33437	  });
33438	}
33439
33440	var LOW_PRIORITY$f = 750;
33441
33442
33443	function BpmnCopyPaste(bpmnFactory, eventBus, moddleCopy) {
33444
33445	  eventBus.on('copyPaste.copyElement', LOW_PRIORITY$f, function(context) {
33446	    var descriptor = context.descriptor,
33447	        element = context.element;
33448
33449	    var businessObject = descriptor.oldBusinessObject = getBusinessObject(element);
33450
33451	    descriptor.type = element.type;
33452
33453	    copyProperties$1(businessObject, descriptor, 'name');
33454
33455	    descriptor.di = {};
33456
33457	    // colors will be set to DI
33458	    copyProperties$1(businessObject.di, descriptor.di, [
33459	      'fill',
33460	      'stroke',
33461	      'background-color',
33462	      'border-color',
33463	      'color'
33464	    ]);
33465
33466	    copyProperties$1(businessObject.di, descriptor, 'isExpanded');
33467
33468	    if (isLabel$3(descriptor)) {
33469	      return descriptor;
33470	    }
33471
33472	    // default sequence flow
33473	    if (businessObject.default) {
33474	      descriptor.default = businessObject.default.id;
33475	    }
33476	  });
33477
33478	  eventBus.on('moddleCopy.canCopyProperty', function(context) {
33479	    var parent = context.parent,
33480	        property = context.property,
33481	        propertyName = context.propertyName,
33482	        bpmnProcess;
33483
33484	    if (
33485	      propertyName === 'processRef' &&
33486	      is$1(parent, 'bpmn:Participant') &&
33487	      is$1(property, 'bpmn:Process')
33488	    ) {
33489	      bpmnProcess = bpmnFactory.create('bpmn:Process');
33490
33491	      // return copy of process
33492	      return moddleCopy.copyElement(property, bpmnProcess);
33493	    }
33494	  });
33495
33496	  var references;
33497
33498	  function resolveReferences(descriptor, cache) {
33499	    var businessObject = getBusinessObject(descriptor);
33500
33501	    // default sequence flows
33502	    if (descriptor.default) {
33503
33504	      // relationship cannot be resolved immediately
33505	      references[ descriptor.default ] = {
33506	        element: businessObject,
33507	        property: 'default'
33508	      };
33509	    }
33510
33511	    // boundary events
33512	    if (descriptor.host) {
33513
33514	      // relationship can be resolved immediately
33515	      getBusinessObject(descriptor).attachedToRef = getBusinessObject(cache[ descriptor.host ]);
33516	    }
33517
33518	    references = omit(references, reduce(references, function(array, reference, key) {
33519	      var element = reference.element,
33520	          property = reference.property;
33521
33522	      if (key === descriptor.id) {
33523	        element[ property ] = businessObject;
33524
33525	        array.push(descriptor.id);
33526	      }
33527
33528	      return array;
33529	    }, []));
33530	  }
33531
33532	  eventBus.on('copyPaste.pasteElements', function() {
33533	    references = {};
33534	  });
33535
33536	  eventBus.on('copyPaste.pasteElement', function(context) {
33537	    var cache = context.cache,
33538	        descriptor = context.descriptor,
33539	        oldBusinessObject = descriptor.oldBusinessObject,
33540	        newBusinessObject;
33541
33542	    // do NOT copy business object if external label
33543	    if (isLabel$3(descriptor)) {
33544	      descriptor.businessObject = getBusinessObject(cache[ descriptor.labelTarget ]);
33545
33546	      return;
33547	    }
33548
33549	    newBusinessObject = bpmnFactory.create(oldBusinessObject.$type);
33550
33551	    descriptor.businessObject = moddleCopy.copyElement(
33552	      oldBusinessObject,
33553	      newBusinessObject
33554	    );
33555
33556	    // resolve references e.g. default sequence flow
33557	    resolveReferences(descriptor, cache);
33558
33559	    copyProperties$1(descriptor, newBusinessObject, [
33560	      'isExpanded',
33561	      'name'
33562	    ]);
33563
33564	    removeProperties(descriptor, 'oldBusinessObject');
33565	  });
33566
33567	}
33568
33569
33570	BpmnCopyPaste.$inject = [
33571	  'bpmnFactory',
33572	  'eventBus',
33573	  'moddleCopy'
33574	];
33575
33576	// helpers //////////
33577
33578	function isLabel$3(element) {
33579	  return !!element.labelTarget;
33580	}
33581
33582	var DISALLOWED_PROPERTIES = [
33583	  'artifacts',
33584	  'dataInputAssociations',
33585	  'dataOutputAssociations',
33586	  'default',
33587	  'flowElements',
33588	  'lanes',
33589	  'incoming',
33590	  'outgoing'
33591	];
33592
33593	/**
33594	 * @typedef {Function} <moddleCopy.canCopyProperties> listener
33595	 *
33596	 * @param {Object} context
33597	 * @param {Array<string>} context.propertyNames
33598	 * @param {ModdleElement} context.sourceElement
33599	 * @param {ModdleElement} context.targetElement
33600	 *
33601	 * @returns {Array<string>|boolean} - Return properties to be copied or false to disallow
33602	 * copying.
33603	 */
33604
33605	/**
33606	 * @typedef {Function} <moddleCopy.canCopyProperty> listener
33607	 *
33608	 * @param {Object} context
33609	 * @param {ModdleElement} context.parent
33610	 * @param {*} context.property
33611	 * @param {string} context.propertyName
33612	 *
33613	 * @returns {*|boolean} - Return copied property or false to disallow
33614	 * copying.
33615	 */
33616
33617	/**
33618	 * @typedef {Function} <moddleCopy.canSetCopiedProperty> listener
33619	 *
33620	 * @param {Object} context
33621	 * @param {ModdleElement} context.parent
33622	 * @param {*} context.property
33623	 * @param {string} context.propertyName
33624	 *
33625	 * @returns {boolean} - Return false to disallow
33626	 * setting copied property.
33627	 */
33628
33629	/**
33630	 * Utility for copying model properties from source element to target element.
33631	 *
33632	 * @param {EventBus} eventBus
33633	 * @param {BpmnFactory} bpmnFactory
33634	 * @param {BpmnModdle} moddle
33635	 */
33636	function ModdleCopy(eventBus, bpmnFactory, moddle) {
33637	  this._bpmnFactory = bpmnFactory;
33638	  this._eventBus = eventBus;
33639	  this._moddle = moddle;
33640
33641	  // copy extension elements last
33642	  eventBus.on('moddleCopy.canCopyProperties', function(context) {
33643	    var propertyNames = context.propertyNames;
33644
33645	    if (!propertyNames || !propertyNames.length) {
33646	      return;
33647	    }
33648
33649	    return sortBy(propertyNames, function(propertyName) {
33650	      return propertyName === 'extensionElements';
33651	    });
33652	  });
33653
33654	  // default check whether property can be copied
33655	  eventBus.on('moddleCopy.canCopyProperty', function(context) {
33656	    var parent = context.parent,
33657	        parentDescriptor = isObject(parent) && parent.$descriptor,
33658	        propertyName = context.propertyName;
33659
33660	    if (propertyName && DISALLOWED_PROPERTIES.indexOf(propertyName) !== -1) {
33661
33662	      // disallow copying property
33663	      return false;
33664	    }
33665
33666	    if (propertyName &&
33667	      parentDescriptor &&
33668	      !find(parentDescriptor.properties, matchPattern({ name: propertyName }))) {
33669
33670	      // disallow copying property
33671	      return false;
33672	    }
33673	  });
33674
33675	  // do NOT allow to copy empty extension elements
33676	  eventBus.on('moddleCopy.canSetCopiedProperty', function(context) {
33677	    var property = context.property;
33678
33679	    if (is(property, 'bpmn:ExtensionElements') && (!property.values || !property.values.length)) {
33680
33681	      // disallow setting copied property
33682	      return false;
33683	    }
33684	  });
33685	}
33686
33687	ModdleCopy.$inject = [
33688	  'eventBus',
33689	  'bpmnFactory',
33690	  'moddle'
33691	];
33692
33693	/**
33694	 * Copy model properties of source element to target element.
33695	 *
33696	 * @param {ModdleElement} sourceElement
33697	 * @param {ModdleElement} targetElement
33698	 * @param {Array<string>} [propertyNames]
33699	 *
33700	 * @param {ModdleElement}
33701	 */
33702	ModdleCopy.prototype.copyElement = function(sourceElement, targetElement, propertyNames) {
33703	  var self = this;
33704
33705	  if (propertyNames && !isArray$2(propertyNames)) {
33706	    propertyNames = [ propertyNames ];
33707	  }
33708
33709	  propertyNames = propertyNames || getPropertyNames(sourceElement.$descriptor);
33710
33711	  var canCopyProperties = this._eventBus.fire('moddleCopy.canCopyProperties', {
33712	    propertyNames: propertyNames,
33713	    sourceElement: sourceElement,
33714	    targetElement: targetElement
33715	  });
33716
33717	  if (canCopyProperties === false) {
33718	    return targetElement;
33719	  }
33720
33721	  if (isArray$2(canCopyProperties)) {
33722	    propertyNames = canCopyProperties;
33723	  }
33724
33725	  // copy properties
33726	  forEach(propertyNames, function(propertyName) {
33727	    var sourceProperty;
33728
33729	    if (has(sourceElement, propertyName)) {
33730	      sourceProperty = sourceElement.get(propertyName);
33731	    }
33732
33733	    var copiedProperty = self.copyProperty(sourceProperty, targetElement, propertyName);
33734
33735	    var canSetProperty = self._eventBus.fire('moddleCopy.canSetCopiedProperty', {
33736	      parent: targetElement,
33737	      property: copiedProperty,
33738	      propertyName: propertyName
33739	    });
33740
33741	    if (canSetProperty === false) {
33742	      return;
33743	    }
33744
33745	    if (isDefined(copiedProperty)) {
33746	      targetElement.set(propertyName, copiedProperty);
33747	    }
33748	  });
33749
33750	  return targetElement;
33751	};
33752
33753	/**
33754	 * Copy model property.
33755	 *
33756	 * @param {*} property
33757	 * @param {ModdleElement} parent
33758	 * @param {string} propertyName
33759	 *
33760	 * @returns {*}
33761	 */
33762	ModdleCopy.prototype.copyProperty = function(property, parent, propertyName) {
33763	  var self = this;
33764
33765	  // allow others to copy property
33766	  var copiedProperty = this._eventBus.fire('moddleCopy.canCopyProperty', {
33767	    parent: parent,
33768	    property: property,
33769	    propertyName: propertyName
33770	  });
33771
33772	  // return if copying is NOT allowed
33773	  if (copiedProperty === false) {
33774	    return;
33775	  }
33776
33777	  if (copiedProperty) {
33778	    if (isObject(copiedProperty) && copiedProperty.$type && !copiedProperty.$parent) {
33779	      copiedProperty.$parent = parent;
33780	    }
33781
33782	    return copiedProperty;
33783	  }
33784
33785	  var propertyDescriptor = this._moddle.getPropertyDescriptor(parent, propertyName);
33786
33787	  // do NOT copy references
33788	  if (propertyDescriptor.isReference) {
33789	    return;
33790	  }
33791
33792	  // copy id
33793	  if (propertyDescriptor.isId) {
33794	    return this._copyId(property, parent);
33795	  }
33796
33797	  // copy arrays
33798	  if (isArray$2(property)) {
33799	    return reduce(property, function(childProperties, childProperty) {
33800
33801	      // recursion
33802	      copiedProperty = self.copyProperty(childProperty, parent, propertyName);
33803
33804	      // copying might NOT be allowed
33805	      if (copiedProperty) {
33806	        copiedProperty.$parent = parent;
33807
33808	        return childProperties.concat(copiedProperty);
33809	      }
33810
33811	      return childProperties;
33812	    }, []);
33813	  }
33814
33815	  // copy model elements
33816	  if (isObject(property) && property.$type) {
33817	    if (this._moddle.getElementDescriptor(property).isGeneric) {
33818	      return;
33819	    }
33820
33821	    copiedProperty = self._bpmnFactory.create(property.$type);
33822
33823	    copiedProperty.$parent = parent;
33824
33825	    // recursion
33826	    copiedProperty = self.copyElement(property, copiedProperty);
33827
33828	    return copiedProperty;
33829	  }
33830
33831	  // copy primitive properties
33832	  return property;
33833	};
33834
33835	ModdleCopy.prototype._copyId = function(id, element) {
33836
33837	  // disallow if already taken
33838	  if (this._moddle.ids.assigned(id)) {
33839	    return;
33840	  } else {
33841
33842	    this._moddle.ids.claim(id, element);
33843	    return id;
33844	  }
33845	};
33846
33847	// helpers //////////
33848
33849	function getPropertyNames(descriptor, keepDefaultProperties) {
33850	  return reduce(descriptor.properties, function(properties, property) {
33851
33852	    if (keepDefaultProperties && property.default) {
33853	      return properties;
33854	    }
33855
33856	    return properties.concat(property.name);
33857	  }, []);
33858	}
33859
33860	function is(element, type) {
33861	  return element && (typeof element.$instanceOf === 'function') && element.$instanceOf(type);
33862	}
33863
33864	var CopyPasteModule = {
33865	  __depends__: [
33866	    CopyPasteModule$1
33867	  ],
33868	  __init__: [ 'bpmnCopyPaste', 'moddleCopy' ],
33869	  bpmnCopyPaste: [ 'type', BpmnCopyPaste ],
33870	  moddleCopy: [ 'type', ModdleCopy ]
33871	};
33872
33873	var round$5 = Math.round;
33874
33875	/**
33876	 * Service that allow replacing of elements.
33877	 */
33878	function Replace(modeling) {
33879
33880	  this._modeling = modeling;
33881	}
33882
33883	Replace.$inject = [ 'modeling' ];
33884
33885	/**
33886	 * @param {Element} oldElement - Element to be replaced
33887	 * @param {Object}  newElementData - Containing information about the new element,
33888	 *                                   for example the new bounds and type.
33889	 * @param {Object}  options - Custom options that will be attached to the context. It can be used to inject data
33890	 *                            that is needed in the command chain. For example it could be used in
33891	 *                            eventbus.on('commandStack.shape.replace.postExecute') to change shape attributes after
33892	 *                            shape creation.
33893	 */
33894	Replace.prototype.replaceElement = function(oldElement, newElementData, options) {
33895
33896	  if (oldElement.waypoints) {
33897
33898	    // TODO(nikku): we do not replace connections, yet
33899	    return null;
33900	  }
33901
33902	  var modeling = this._modeling;
33903
33904	  var width = newElementData.width || oldElement.width,
33905	      height = newElementData.height || oldElement.height,
33906	      x = newElementData.x || oldElement.x,
33907	      y = newElementData.y || oldElement.y,
33908	      centerX = round$5(x + width / 2),
33909	      centerY = round$5(y + height / 2);
33910
33911	  // modeling API requires center coordinates,
33912	  // account for that when handling shape bounds
33913
33914	  return modeling.replaceShape(
33915	    oldElement,
33916	    assign(
33917	      {},
33918	      newElementData,
33919	      {
33920	        x: centerX,
33921	        y: centerY,
33922	        width: width,
33923	        height: height
33924	      }
33925	    ),
33926	    options
33927	  );
33928	};
33929
33930	var ReplaceModule$1 = {
33931	  __init__: [ 'replace' ],
33932	  replace: [ 'type', Replace ]
33933	};
33934
33935	function copyProperties(source, target, properties) {
33936	  if (!isArray$2(properties)) {
33937	    properties = [ properties ];
33938	  }
33939
33940	  forEach(properties, function(property) {
33941	    if (!isUndefined$1(source[property])) {
33942	      target[property] = source[property];
33943	    }
33944	  });
33945	}
33946
33947	var CUSTOM_PROPERTIES = [
33948	  'cancelActivity',
33949	  'instantiate',
33950	  'eventGatewayType',
33951	  'triggeredByEvent',
33952	  'isInterrupting'
33953	];
33954
33955
33956	function toggeling(element, target) {
33957
33958	  var oldCollapsed = (
33959	    element && has(element, 'collapsed') ? element.collapsed : !isExpanded(element)
33960	  );
33961
33962	  var targetCollapsed;
33963
33964	  if (target && (has(target, 'collapsed') || has(target, 'isExpanded'))) {
33965
33966	    // property is explicitly set so use it
33967	    targetCollapsed = (
33968	      has(target, 'collapsed') ? target.collapsed : !target.isExpanded
33969	    );
33970	  } else {
33971
33972	    // keep old state
33973	    targetCollapsed = oldCollapsed;
33974	  }
33975
33976	  if (oldCollapsed !== targetCollapsed) {
33977	    element.collapsed = oldCollapsed;
33978	    return true;
33979	  }
33980
33981	  return false;
33982	}
33983
33984
33985
33986	/**
33987	 * This module takes care of replacing BPMN elements
33988	 */
33989	function BpmnReplace(
33990	    bpmnFactory,
33991	    elementFactory,
33992	    moddleCopy,
33993	    modeling,
33994	    replace,
33995	    rules,
33996	    selection
33997	) {
33998
33999	  /**
34000	   * Prepares a new business object for the replacement element
34001	   * and triggers the replace operation.
34002	   *
34003	   * @param  {djs.model.Base} element
34004	   * @param  {Object} target
34005	   * @param  {Object} [hints]
34006	   *
34007	   * @return {djs.model.Base} the newly created element
34008	   */
34009	  function replaceElement(element, target, hints) {
34010
34011	    hints = hints || {};
34012
34013	    var type = target.type,
34014	        oldBusinessObject = element.businessObject;
34015
34016	    if (isSubProcess(oldBusinessObject)) {
34017	      if (type === 'bpmn:SubProcess') {
34018	        if (toggeling(element, target)) {
34019
34020	          // expanding or collapsing process
34021	          modeling.toggleCollapse(element);
34022
34023	          return element;
34024	        }
34025	      }
34026	    }
34027
34028	    var newBusinessObject = bpmnFactory.create(type);
34029
34030	    var newElement = {
34031	      type: type,
34032	      businessObject: newBusinessObject
34033	    };
34034
34035	    var elementProps = getPropertyNames(oldBusinessObject.$descriptor),
34036	        newElementProps = getPropertyNames(newBusinessObject.$descriptor, true),
34037	        copyProps = intersection(elementProps, newElementProps);
34038
34039	    // initialize special properties defined in target definition
34040	    assign(newBusinessObject, pick(target, CUSTOM_PROPERTIES));
34041
34042	    var properties = filter(copyProps, function(propertyName) {
34043
34044	      // copying event definitions, unless we replace
34045	      if (propertyName === 'eventDefinitions') {
34046	        return hasEventDefinition$1(element, target.eventDefinitionType);
34047	      }
34048
34049	      // retain loop characteristics if the target element
34050	      // is not an event sub process
34051	      if (propertyName === 'loopCharacteristics') {
34052	        return !isEventSubProcess(newBusinessObject);
34053	      }
34054
34055	      // so the applied properties from 'target' don't get lost
34056	      if (has(newBusinessObject, propertyName)) {
34057	        return false;
34058	      }
34059
34060	      if (propertyName === 'processRef' && target.isExpanded === false) {
34061	        return false;
34062	      }
34063
34064	      if (propertyName === 'triggeredByEvent') {
34065	        return false;
34066	      }
34067
34068	      return true;
34069	    });
34070
34071	    newBusinessObject = moddleCopy.copyElement(
34072	      oldBusinessObject,
34073	      newBusinessObject,
34074	      properties
34075	    );
34076
34077	    // initialize custom BPMN extensions
34078	    if (target.eventDefinitionType) {
34079
34080	      // only initialize with new eventDefinition
34081	      // if we did not set an event definition yet,
34082	      // i.e. because we copied it
34083	      if (!hasEventDefinition$1(newBusinessObject, target.eventDefinitionType)) {
34084	        newElement.eventDefinitionType = target.eventDefinitionType;
34085	        newElement.eventDefinitionAttrs = target.eventDefinitionAttrs;
34086	      }
34087	    }
34088
34089	    if (is$1(oldBusinessObject, 'bpmn:Activity')) {
34090
34091	      if (isSubProcess(oldBusinessObject)) {
34092
34093	        // no toggeling, so keep old state
34094	        newElement.isExpanded = isExpanded(oldBusinessObject);
34095	      }
34096
34097	      // else if property is explicitly set, use it
34098	      else if (target && has(target, 'isExpanded')) {
34099	        newElement.isExpanded = target.isExpanded;
34100	      }
34101
34102	      // TODO: need also to respect min/max Size
34103	      // copy size, from an expanded subprocess to an expanded alternative subprocess
34104	      // except bpmn:Task, because Task is always expanded
34105	      if ((isExpanded(oldBusinessObject) && !is$1(oldBusinessObject, 'bpmn:Task')) && newElement.isExpanded) {
34106	        newElement.width = element.width;
34107	        newElement.height = element.height;
34108	      }
34109	    }
34110
34111	    // remove children if not expanding sub process
34112	    if (isSubProcess(oldBusinessObject) && !isSubProcess(newBusinessObject)) {
34113	      hints.moveChildren = false;
34114	    }
34115
34116	    // transform collapsed/expanded pools
34117	    if (is$1(oldBusinessObject, 'bpmn:Participant')) {
34118
34119	      // create expanded pool
34120	      if (target.isExpanded === true) {
34121	        newBusinessObject.processRef = bpmnFactory.create('bpmn:Process');
34122	      } else {
34123
34124	        // remove children when transforming to collapsed pool
34125	        hints.moveChildren = false;
34126	      }
34127
34128	      // apply same width and default height
34129	      newElement.width = element.width;
34130	      newElement.height = elementFactory._getDefaultSize(newBusinessObject).height;
34131	    }
34132
34133	    if (!rules.allowed('shape.resize', { shape: newBusinessObject })) {
34134	      newElement.height = elementFactory._getDefaultSize(newBusinessObject).height;
34135	      newElement.width = elementFactory._getDefaultSize(newBusinessObject).width;
34136	    }
34137
34138	    newBusinessObject.name = oldBusinessObject.name;
34139
34140	    // retain default flow's reference between inclusive <-> exclusive gateways and activities
34141	    if (
34142	      isAny(oldBusinessObject, [
34143	        'bpmn:ExclusiveGateway',
34144	        'bpmn:InclusiveGateway',
34145	        'bpmn:Activity'
34146	      ]) &&
34147	      isAny(newBusinessObject, [
34148	        'bpmn:ExclusiveGateway',
34149	        'bpmn:InclusiveGateway',
34150	        'bpmn:Activity'
34151	      ])
34152	    ) {
34153	      newBusinessObject.default = oldBusinessObject.default;
34154	    }
34155
34156	    if (
34157	      target.host &&
34158	      !is$1(oldBusinessObject, 'bpmn:BoundaryEvent') &&
34159	      is$1(newBusinessObject, 'bpmn:BoundaryEvent')
34160	    ) {
34161	      newElement.host = target.host;
34162	    }
34163
34164	    // The DataStoreReference element is 14px wider than the DataObjectReference element
34165	    // This ensures that they stay centered on the x axis when replaced
34166	    if (
34167	      newElement.type === 'bpmn:DataStoreReference' ||
34168	      newElement.type === 'bpmn:DataObjectReference'
34169	    ) {
34170	      newElement.x = element.x + (element.width - newElement.width) / 2;
34171	    }
34172
34173	    newElement.di = {};
34174
34175	    // colors will be set to DI
34176	    copyProperties(oldBusinessObject.di, newElement.di, [
34177	      'fill',
34178	      'stroke',
34179	      'background-color',
34180	      'border-color',
34181	      'color'
34182	    ]);
34183
34184	    newElement = replace.replaceElement(element, newElement, hints);
34185
34186	    if (hints.select !== false) {
34187	      selection.select(newElement);
34188	    }
34189
34190	    return newElement;
34191	  }
34192
34193	  this.replaceElement = replaceElement;
34194	}
34195
34196	BpmnReplace.$inject = [
34197	  'bpmnFactory',
34198	  'elementFactory',
34199	  'moddleCopy',
34200	  'modeling',
34201	  'replace',
34202	  'rules',
34203	  'selection'
34204	];
34205
34206
34207	function isSubProcess(bo) {
34208	  return is$1(bo, 'bpmn:SubProcess');
34209	}
34210
34211	function hasEventDefinition$1(element, type) {
34212
34213	  var bo = getBusinessObject(element);
34214
34215	  return type && bo.get('eventDefinitions').some(function(definition) {
34216	    return is$1(definition, type);
34217	  });
34218	}
34219
34220	/**
34221	 * Compute intersection between two arrays.
34222	 */
34223	function intersection(a1, a2) {
34224	  return a1.filter(function(el) {
34225	    return a2.indexOf(el) !== -1;
34226	  });
34227	}
34228
34229	var ReplaceModule = {
34230	  __depends__: [
34231	    CopyPasteModule,
34232	    ReplaceModule$1,
34233	    SelectionModule
34234	  ],
34235	  bpmnReplace: [ 'type', BpmnReplace ]
34236	};
34237
34238	/**
34239	 * Returns true, if an element is from a different type
34240	 * than a target definition. Takes into account the type,
34241	 * event definition type and triggeredByEvent property.
34242	 *
34243	 * @param {djs.model.Base} element
34244	 *
34245	 * @return {boolean}
34246	 */
34247	function isDifferentType(element) {
34248
34249	  return function(entry) {
34250	    var target = entry.target;
34251
34252	    var businessObject = getBusinessObject(element),
34253	        eventDefinition = businessObject.eventDefinitions && businessObject.eventDefinitions[0];
34254
34255	    var isTypeEqual = businessObject.$type === target.type;
34256
34257	    var isEventDefinitionEqual = (
34258	      (eventDefinition && eventDefinition.$type) === target.eventDefinitionType
34259	    );
34260
34261	    var isTriggeredByEventEqual = (
34262	      businessObject.triggeredByEvent === target.triggeredByEvent
34263	    );
34264
34265	    var isExpandedEqual = (
34266	      target.isExpanded === undefined ||
34267	      target.isExpanded === isExpanded(businessObject)
34268	    );
34269
34270	    return !isTypeEqual || !isEventDefinitionEqual || !isTriggeredByEventEqual || !isExpandedEqual;
34271	  };
34272	}
34273
34274	var START_EVENT = [
34275	  {
34276	    label: 'Start Event',
34277	    actionName: 'replace-with-none-start',
34278	    className: 'bpmn-icon-start-event-none',
34279	    target: {
34280	      type: 'bpmn:StartEvent'
34281	    }
34282	  },
34283	  {
34284	    label: 'Intermediate Throw Event',
34285	    actionName: 'replace-with-none-intermediate-throwing',
34286	    className: 'bpmn-icon-intermediate-event-none',
34287	    target: {
34288	      type: 'bpmn:IntermediateThrowEvent'
34289	    }
34290	  },
34291	  {
34292	    label: 'End Event',
34293	    actionName: 'replace-with-none-end',
34294	    className: 'bpmn-icon-end-event-none',
34295	    target: {
34296	      type: 'bpmn:EndEvent'
34297	    }
34298	  },
34299	  {
34300	    label: 'Message Start Event',
34301	    actionName: 'replace-with-message-start',
34302	    className: 'bpmn-icon-start-event-message',
34303	    target: {
34304	      type: 'bpmn:StartEvent',
34305	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34306	    }
34307	  },
34308	  {
34309	    label: 'Timer Start Event',
34310	    actionName: 'replace-with-timer-start',
34311	    className: 'bpmn-icon-start-event-timer',
34312	    target: {
34313	      type: 'bpmn:StartEvent',
34314	      eventDefinitionType: 'bpmn:TimerEventDefinition'
34315	    }
34316	  },
34317	  {
34318	    label: 'Conditional Start Event',
34319	    actionName: 'replace-with-conditional-start',
34320	    className: 'bpmn-icon-start-event-condition',
34321	    target: {
34322	      type: 'bpmn:StartEvent',
34323	      eventDefinitionType: 'bpmn:ConditionalEventDefinition'
34324	    }
34325	  },
34326	  {
34327	    label: 'Signal Start Event',
34328	    actionName: 'replace-with-signal-start',
34329	    className: 'bpmn-icon-start-event-signal',
34330	    target: {
34331	      type: 'bpmn:StartEvent',
34332	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34333	    }
34334	  }
34335	];
34336
34337	var START_EVENT_SUB_PROCESS = [
34338	  {
34339	    label: 'Start Event',
34340	    actionName: 'replace-with-none-start',
34341	    className: 'bpmn-icon-start-event-none',
34342	    target: {
34343	      type: 'bpmn:StartEvent'
34344	    }
34345	  },
34346	  {
34347	    label: 'Intermediate Throw Event',
34348	    actionName: 'replace-with-none-intermediate-throwing',
34349	    className: 'bpmn-icon-intermediate-event-none',
34350	    target: {
34351	      type: 'bpmn:IntermediateThrowEvent'
34352	    }
34353	  },
34354	  {
34355	    label: 'End Event',
34356	    actionName: 'replace-with-none-end',
34357	    className: 'bpmn-icon-end-event-none',
34358	    target: {
34359	      type: 'bpmn:EndEvent'
34360	    }
34361	  }
34362	];
34363
34364	var INTERMEDIATE_EVENT = [
34365	  {
34366	    label: 'Start Event',
34367	    actionName: 'replace-with-none-start',
34368	    className: 'bpmn-icon-start-event-none',
34369	    target: {
34370	      type: 'bpmn:StartEvent'
34371	    }
34372	  },
34373	  {
34374	    label: 'Intermediate Throw Event',
34375	    actionName: 'replace-with-none-intermediate-throw',
34376	    className: 'bpmn-icon-intermediate-event-none',
34377	    target: {
34378	      type: 'bpmn:IntermediateThrowEvent'
34379	    }
34380	  },
34381	  {
34382	    label: 'End Event',
34383	    actionName: 'replace-with-none-end',
34384	    className: 'bpmn-icon-end-event-none',
34385	    target: {
34386	      type: 'bpmn:EndEvent'
34387	    }
34388	  },
34389	  {
34390	    label: 'Message Intermediate Catch Event',
34391	    actionName: 'replace-with-message-intermediate-catch',
34392	    className: 'bpmn-icon-intermediate-event-catch-message',
34393	    target: {
34394	      type: 'bpmn:IntermediateCatchEvent',
34395	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34396	    }
34397	  },
34398	  {
34399	    label: 'Message Intermediate Throw Event',
34400	    actionName: 'replace-with-message-intermediate-throw',
34401	    className: 'bpmn-icon-intermediate-event-throw-message',
34402	    target: {
34403	      type: 'bpmn:IntermediateThrowEvent',
34404	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34405	    }
34406	  },
34407	  {
34408	    label: 'Timer Intermediate Catch Event',
34409	    actionName: 'replace-with-timer-intermediate-catch',
34410	    className: 'bpmn-icon-intermediate-event-catch-timer',
34411	    target: {
34412	      type: 'bpmn:IntermediateCatchEvent',
34413	      eventDefinitionType: 'bpmn:TimerEventDefinition'
34414	    }
34415	  },
34416	  {
34417	    label: 'Escalation Intermediate Throw Event',
34418	    actionName: 'replace-with-escalation-intermediate-throw',
34419	    className: 'bpmn-icon-intermediate-event-throw-escalation',
34420	    target: {
34421	      type: 'bpmn:IntermediateThrowEvent',
34422	      eventDefinitionType: 'bpmn:EscalationEventDefinition'
34423	    }
34424	  },
34425	  {
34426	    label: 'Conditional Intermediate Catch Event',
34427	    actionName: 'replace-with-conditional-intermediate-catch',
34428	    className: 'bpmn-icon-intermediate-event-catch-condition',
34429	    target: {
34430	      type: 'bpmn:IntermediateCatchEvent',
34431	      eventDefinitionType: 'bpmn:ConditionalEventDefinition'
34432	    }
34433	  },
34434	  {
34435	    label: 'Link Intermediate Catch Event',
34436	    actionName: 'replace-with-link-intermediate-catch',
34437	    className: 'bpmn-icon-intermediate-event-catch-link',
34438	    target: {
34439	      type: 'bpmn:IntermediateCatchEvent',
34440	      eventDefinitionType: 'bpmn:LinkEventDefinition',
34441	      eventDefinitionAttrs: {
34442	        name: ''
34443	      }
34444	    }
34445	  },
34446	  {
34447	    label: 'Link Intermediate Throw Event',
34448	    actionName: 'replace-with-link-intermediate-throw',
34449	    className: 'bpmn-icon-intermediate-event-throw-link',
34450	    target: {
34451	      type: 'bpmn:IntermediateThrowEvent',
34452	      eventDefinitionType: 'bpmn:LinkEventDefinition',
34453	      eventDefinitionAttrs: {
34454	        name: ''
34455	      }
34456	    }
34457	  },
34458	  {
34459	    label: 'Compensation Intermediate Throw Event',
34460	    actionName: 'replace-with-compensation-intermediate-throw',
34461	    className: 'bpmn-icon-intermediate-event-throw-compensation',
34462	    target: {
34463	      type: 'bpmn:IntermediateThrowEvent',
34464	      eventDefinitionType: 'bpmn:CompensateEventDefinition'
34465	    }
34466	  },
34467	  {
34468	    label: 'Signal Intermediate Catch Event',
34469	    actionName: 'replace-with-signal-intermediate-catch',
34470	    className: 'bpmn-icon-intermediate-event-catch-signal',
34471	    target: {
34472	      type: 'bpmn:IntermediateCatchEvent',
34473	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34474	    }
34475	  },
34476	  {
34477	    label: 'Signal Intermediate Throw Event',
34478	    actionName: 'replace-with-signal-intermediate-throw',
34479	    className: 'bpmn-icon-intermediate-event-throw-signal',
34480	    target: {
34481	      type: 'bpmn:IntermediateThrowEvent',
34482	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34483	    }
34484	  }
34485	];
34486
34487	var END_EVENT = [
34488	  {
34489	    label: 'Start Event',
34490	    actionName: 'replace-with-none-start',
34491	    className: 'bpmn-icon-start-event-none',
34492	    target: {
34493	      type: 'bpmn:StartEvent'
34494	    }
34495	  },
34496	  {
34497	    label: 'Intermediate Throw Event',
34498	    actionName: 'replace-with-none-intermediate-throw',
34499	    className: 'bpmn-icon-intermediate-event-none',
34500	    target: {
34501	      type: 'bpmn:IntermediateThrowEvent'
34502	    }
34503	  },
34504	  {
34505	    label: 'End Event',
34506	    actionName: 'replace-with-none-end',
34507	    className: 'bpmn-icon-end-event-none',
34508	    target: {
34509	      type: 'bpmn:EndEvent'
34510	    }
34511	  },
34512	  {
34513	    label: 'Message End Event',
34514	    actionName: 'replace-with-message-end',
34515	    className: 'bpmn-icon-end-event-message',
34516	    target: {
34517	      type: 'bpmn:EndEvent',
34518	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34519	    }
34520	  },
34521	  {
34522	    label: 'Escalation End Event',
34523	    actionName: 'replace-with-escalation-end',
34524	    className: 'bpmn-icon-end-event-escalation',
34525	    target: {
34526	      type: 'bpmn:EndEvent',
34527	      eventDefinitionType: 'bpmn:EscalationEventDefinition'
34528	    }
34529	  },
34530	  {
34531	    label: 'Error End Event',
34532	    actionName: 'replace-with-error-end',
34533	    className: 'bpmn-icon-end-event-error',
34534	    target: {
34535	      type: 'bpmn:EndEvent',
34536	      eventDefinitionType: 'bpmn:ErrorEventDefinition'
34537	    }
34538	  },
34539	  {
34540	    label: 'Cancel End Event',
34541	    actionName: 'replace-with-cancel-end',
34542	    className: 'bpmn-icon-end-event-cancel',
34543	    target: {
34544	      type: 'bpmn:EndEvent',
34545	      eventDefinitionType: 'bpmn:CancelEventDefinition'
34546	    }
34547	  },
34548	  {
34549	    label: 'Compensation End Event',
34550	    actionName: 'replace-with-compensation-end',
34551	    className: 'bpmn-icon-end-event-compensation',
34552	    target: {
34553	      type: 'bpmn:EndEvent',
34554	      eventDefinitionType: 'bpmn:CompensateEventDefinition'
34555	    }
34556	  },
34557	  {
34558	    label: 'Signal End Event',
34559	    actionName: 'replace-with-signal-end',
34560	    className: 'bpmn-icon-end-event-signal',
34561	    target: {
34562	      type: 'bpmn:EndEvent',
34563	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34564	    }
34565	  },
34566	  {
34567	    label: 'Terminate End Event',
34568	    actionName: 'replace-with-terminate-end',
34569	    className: 'bpmn-icon-end-event-terminate',
34570	    target: {
34571	      type: 'bpmn:EndEvent',
34572	      eventDefinitionType: 'bpmn:TerminateEventDefinition'
34573	    }
34574	  }
34575	];
34576
34577	var GATEWAY = [
34578	  {
34579	    label: 'Exclusive Gateway',
34580	    actionName: 'replace-with-exclusive-gateway',
34581	    className: 'bpmn-icon-gateway-xor',
34582	    target: {
34583	      type: 'bpmn:ExclusiveGateway'
34584	    }
34585	  },
34586	  {
34587	    label: 'Parallel Gateway',
34588	    actionName: 'replace-with-parallel-gateway',
34589	    className: 'bpmn-icon-gateway-parallel',
34590	    target: {
34591	      type: 'bpmn:ParallelGateway'
34592	    }
34593	  },
34594	  {
34595	    label: 'Inclusive Gateway',
34596	    actionName: 'replace-with-inclusive-gateway',
34597	    className: 'bpmn-icon-gateway-or',
34598	    target: {
34599	      type: 'bpmn:InclusiveGateway'
34600	    }
34601	  },
34602	  {
34603	    label: 'Complex Gateway',
34604	    actionName: 'replace-with-complex-gateway',
34605	    className: 'bpmn-icon-gateway-complex',
34606	    target: {
34607	      type: 'bpmn:ComplexGateway'
34608	    }
34609	  },
34610	  {
34611	    label: 'Event based Gateway',
34612	    actionName: 'replace-with-event-based-gateway',
34613	    className: 'bpmn-icon-gateway-eventbased',
34614	    target: {
34615	      type: 'bpmn:EventBasedGateway',
34616	      instantiate: false,
34617	      eventGatewayType: 'Exclusive'
34618	    }
34619	  }
34620
34621	  // Gateways deactivated until https://github.com/bpmn-io/bpmn-js/issues/194
34622	  // {
34623	  //   label: 'Event based instantiating Gateway',
34624	  //   actionName: 'replace-with-exclusive-event-based-gateway',
34625	  //   className: 'bpmn-icon-exclusive-event-based',
34626	  //   target: {
34627	  //     type: 'bpmn:EventBasedGateway'
34628	  //   },
34629	  //   options: {
34630	  //     businessObject: { instantiate: true, eventGatewayType: 'Exclusive' }
34631	  //   }
34632	  // },
34633	  // {
34634	  //   label: 'Parallel Event based instantiating Gateway',
34635	  //   actionName: 'replace-with-parallel-event-based-instantiate-gateway',
34636	  //   className: 'bpmn-icon-parallel-event-based-instantiate-gateway',
34637	  //   target: {
34638	  //     type: 'bpmn:EventBasedGateway'
34639	  //   },
34640	  //   options: {
34641	  //     businessObject: { instantiate: true, eventGatewayType: 'Parallel' }
34642	  //   }
34643	  // }
34644	];
34645
34646	var SUBPROCESS_EXPANDED = [
34647	  {
34648	    label: 'Transaction',
34649	    actionName: 'replace-with-transaction',
34650	    className: 'bpmn-icon-transaction',
34651	    target: {
34652	      type: 'bpmn:Transaction',
34653	      isExpanded: true
34654	    }
34655	  },
34656	  {
34657	    label: 'Event Sub Process',
34658	    actionName: 'replace-with-event-subprocess',
34659	    className: 'bpmn-icon-event-subprocess-expanded',
34660	    target: {
34661	      type: 'bpmn:SubProcess',
34662	      triggeredByEvent: true,
34663	      isExpanded: true
34664	    }
34665	  },
34666	  {
34667	    label: 'Sub Process (collapsed)',
34668	    actionName: 'replace-with-collapsed-subprocess',
34669	    className: 'bpmn-icon-subprocess-collapsed',
34670	    target: {
34671	      type: 'bpmn:SubProcess',
34672	      isExpanded: false
34673	    }
34674	  }
34675	];
34676
34677	var TRANSACTION = [
34678	  {
34679	    label: 'Sub Process',
34680	    actionName: 'replace-with-subprocess',
34681	    className: 'bpmn-icon-subprocess-expanded',
34682	    target: {
34683	      type: 'bpmn:SubProcess',
34684	      isExpanded: true
34685	    }
34686	  },
34687	  {
34688	    label: 'Event Sub Process',
34689	    actionName: 'replace-with-event-subprocess',
34690	    className: 'bpmn-icon-event-subprocess-expanded',
34691	    target: {
34692	      type: 'bpmn:SubProcess',
34693	      triggeredByEvent: true,
34694	      isExpanded: true
34695	    }
34696	  }
34697	];
34698
34699	var EVENT_SUB_PROCESS = [
34700	  {
34701	    label: 'Sub Process',
34702	    actionName: 'replace-with-subprocess',
34703	    className: 'bpmn-icon-subprocess-expanded',
34704	    target: {
34705	      type: 'bpmn:SubProcess',
34706	      isExpanded: true
34707	    }
34708	  },
34709	  {
34710	    label: 'Transaction',
34711	    actionName: 'replace-with-transaction',
34712	    className: 'bpmn-icon-transaction',
34713	    target: {
34714	      type: 'bpmn:Transaction',
34715	      isExpanded: true
34716	    }
34717	  }
34718	];
34719
34720	var TASK = [
34721	  {
34722	    label: 'Task',
34723	    actionName: 'replace-with-task',
34724	    className: 'bpmn-icon-task',
34725	    target: {
34726	      type: 'bpmn:Task'
34727	    }
34728	  },
34729	  {
34730	    label: 'Send Task',
34731	    actionName: 'replace-with-send-task',
34732	    className: 'bpmn-icon-send',
34733	    target: {
34734	      type: 'bpmn:SendTask'
34735	    }
34736	  },
34737	  {
34738	    label: 'Receive Task',
34739	    actionName: 'replace-with-receive-task',
34740	    className: 'bpmn-icon-receive',
34741	    target: {
34742	      type: 'bpmn:ReceiveTask'
34743	    }
34744	  },
34745	  {
34746	    label: 'User Task',
34747	    actionName: 'replace-with-user-task',
34748	    className: 'bpmn-icon-user',
34749	    target: {
34750	      type: 'bpmn:UserTask'
34751	    }
34752	  },
34753	  {
34754	    label: 'Manual Task',
34755	    actionName: 'replace-with-manual-task',
34756	    className: 'bpmn-icon-manual',
34757	    target: {
34758	      type: 'bpmn:ManualTask'
34759	    }
34760	  },
34761	  {
34762	    label: 'Business Rule Task',
34763	    actionName: 'replace-with-rule-task',
34764	    className: 'bpmn-icon-business-rule',
34765	    target: {
34766	      type: 'bpmn:BusinessRuleTask'
34767	    }
34768	  },
34769	  {
34770	    label: 'Service Task',
34771	    actionName: 'replace-with-service-task',
34772	    className: 'bpmn-icon-service',
34773	    target: {
34774	      type: 'bpmn:ServiceTask'
34775	    }
34776	  },
34777	  {
34778	    label: 'Script Task',
34779	    actionName: 'replace-with-script-task',
34780	    className: 'bpmn-icon-script',
34781	    target: {
34782	      type: 'bpmn:ScriptTask'
34783	    }
34784	  },
34785	  {
34786	    label: 'Call Activity',
34787	    actionName: 'replace-with-call-activity',
34788	    className: 'bpmn-icon-call-activity',
34789	    target: {
34790	      type: 'bpmn:CallActivity'
34791	    }
34792	  },
34793	  {
34794	    label: 'Sub Process (collapsed)',
34795	    actionName: 'replace-with-collapsed-subprocess',
34796	    className: 'bpmn-icon-subprocess-collapsed',
34797	    target: {
34798	      type: 'bpmn:SubProcess',
34799	      isExpanded: false
34800	    }
34801	  },
34802	  {
34803	    label: 'Sub Process (expanded)',
34804	    actionName: 'replace-with-expanded-subprocess',
34805	    className: 'bpmn-icon-subprocess-expanded',
34806	    target: {
34807	      type: 'bpmn:SubProcess',
34808	      isExpanded: true
34809	    }
34810	  }
34811	];
34812
34813	var DATA_OBJECT_REFERENCE = [
34814	  {
34815	    label: 'Data Store Reference',
34816	    actionName: 'replace-with-data-store-reference',
34817	    className: 'bpmn-icon-data-store',
34818	    target: {
34819	      type: 'bpmn:DataStoreReference'
34820	    }
34821	  }
34822	];
34823
34824	var DATA_STORE_REFERENCE = [
34825	  {
34826	    label: 'Data Object Reference',
34827	    actionName: 'replace-with-data-object-reference',
34828	    className: 'bpmn-icon-data-object',
34829	    target: {
34830	      type: 'bpmn:DataObjectReference'
34831	    }
34832	  }
34833	];
34834
34835	var BOUNDARY_EVENT = [
34836	  {
34837	    label: 'Message Boundary Event',
34838	    actionName: 'replace-with-message-boundary',
34839	    className: 'bpmn-icon-intermediate-event-catch-message',
34840	    target: {
34841	      type: 'bpmn:BoundaryEvent',
34842	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34843	    }
34844	  },
34845	  {
34846	    label: 'Timer Boundary Event',
34847	    actionName: 'replace-with-timer-boundary',
34848	    className: 'bpmn-icon-intermediate-event-catch-timer',
34849	    target: {
34850	      type: 'bpmn:BoundaryEvent',
34851	      eventDefinitionType: 'bpmn:TimerEventDefinition'
34852	    }
34853	  },
34854	  {
34855	    label: 'Escalation Boundary Event',
34856	    actionName: 'replace-with-escalation-boundary',
34857	    className: 'bpmn-icon-intermediate-event-catch-escalation',
34858	    target: {
34859	      type: 'bpmn:BoundaryEvent',
34860	      eventDefinitionType: 'bpmn:EscalationEventDefinition'
34861	    }
34862	  },
34863	  {
34864	    label: 'Conditional Boundary Event',
34865	    actionName: 'replace-with-conditional-boundary',
34866	    className: 'bpmn-icon-intermediate-event-catch-condition',
34867	    target: {
34868	      type: 'bpmn:BoundaryEvent',
34869	      eventDefinitionType: 'bpmn:ConditionalEventDefinition'
34870	    }
34871	  },
34872	  {
34873	    label: 'Error Boundary Event',
34874	    actionName: 'replace-with-error-boundary',
34875	    className: 'bpmn-icon-intermediate-event-catch-error',
34876	    target: {
34877	      type: 'bpmn:BoundaryEvent',
34878	      eventDefinitionType: 'bpmn:ErrorEventDefinition'
34879	    }
34880	  },
34881	  {
34882	    label: 'Cancel Boundary Event',
34883	    actionName: 'replace-with-cancel-boundary',
34884	    className: 'bpmn-icon-intermediate-event-catch-cancel',
34885	    target: {
34886	      type: 'bpmn:BoundaryEvent',
34887	      eventDefinitionType: 'bpmn:CancelEventDefinition'
34888	    }
34889	  },
34890	  {
34891	    label: 'Signal Boundary Event',
34892	    actionName: 'replace-with-signal-boundary',
34893	    className: 'bpmn-icon-intermediate-event-catch-signal',
34894	    target: {
34895	      type: 'bpmn:BoundaryEvent',
34896	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34897	    }
34898	  },
34899	  {
34900	    label: 'Compensation Boundary Event',
34901	    actionName: 'replace-with-compensation-boundary',
34902	    className: 'bpmn-icon-intermediate-event-catch-compensation',
34903	    target: {
34904	      type: 'bpmn:BoundaryEvent',
34905	      eventDefinitionType: 'bpmn:CompensateEventDefinition'
34906	    }
34907	  },
34908	  {
34909	    label: 'Message Boundary Event (non-interrupting)',
34910	    actionName: 'replace-with-non-interrupting-message-boundary',
34911	    className: 'bpmn-icon-intermediate-event-catch-non-interrupting-message',
34912	    target: {
34913	      type: 'bpmn:BoundaryEvent',
34914	      eventDefinitionType: 'bpmn:MessageEventDefinition',
34915	      cancelActivity: false
34916	    }
34917	  },
34918	  {
34919	    label: 'Timer Boundary Event (non-interrupting)',
34920	    actionName: 'replace-with-non-interrupting-timer-boundary',
34921	    className: 'bpmn-icon-intermediate-event-catch-non-interrupting-timer',
34922	    target: {
34923	      type: 'bpmn:BoundaryEvent',
34924	      eventDefinitionType: 'bpmn:TimerEventDefinition',
34925	      cancelActivity: false
34926	    }
34927	  },
34928	  {
34929	    label: 'Escalation Boundary Event (non-interrupting)',
34930	    actionName: 'replace-with-non-interrupting-escalation-boundary',
34931	    className: 'bpmn-icon-intermediate-event-catch-non-interrupting-escalation',
34932	    target: {
34933	      type: 'bpmn:BoundaryEvent',
34934	      eventDefinitionType: 'bpmn:EscalationEventDefinition',
34935	      cancelActivity: false
34936	    }
34937	  },
34938	  {
34939	    label: 'Conditional Boundary Event (non-interrupting)',
34940	    actionName: 'replace-with-non-interrupting-conditional-boundary',
34941	    className: 'bpmn-icon-intermediate-event-catch-non-interrupting-condition',
34942	    target: {
34943	      type: 'bpmn:BoundaryEvent',
34944	      eventDefinitionType: 'bpmn:ConditionalEventDefinition',
34945	      cancelActivity: false
34946	    }
34947	  },
34948	  {
34949	    label: 'Signal Boundary Event (non-interrupting)',
34950	    actionName: 'replace-with-non-interrupting-signal-boundary',
34951	    className: 'bpmn-icon-intermediate-event-catch-non-interrupting-signal',
34952	    target: {
34953	      type: 'bpmn:BoundaryEvent',
34954	      eventDefinitionType: 'bpmn:SignalEventDefinition',
34955	      cancelActivity: false
34956	    }
34957	  }
34958	];
34959
34960	var EVENT_SUB_PROCESS_START_EVENT = [
34961	  {
34962	    label: 'Message Start Event',
34963	    actionName: 'replace-with-message-start',
34964	    className: 'bpmn-icon-start-event-message',
34965	    target: {
34966	      type: 'bpmn:StartEvent',
34967	      eventDefinitionType: 'bpmn:MessageEventDefinition'
34968	    }
34969	  },
34970	  {
34971	    label: 'Timer Start Event',
34972	    actionName: 'replace-with-timer-start',
34973	    className: 'bpmn-icon-start-event-timer',
34974	    target: {
34975	      type: 'bpmn:StartEvent',
34976	      eventDefinitionType: 'bpmn:TimerEventDefinition'
34977	    }
34978	  },
34979	  {
34980	    label: 'Conditional Start Event',
34981	    actionName: 'replace-with-conditional-start',
34982	    className: 'bpmn-icon-start-event-condition',
34983	    target: {
34984	      type: 'bpmn:StartEvent',
34985	      eventDefinitionType: 'bpmn:ConditionalEventDefinition'
34986	    }
34987	  },
34988	  {
34989	    label: 'Signal Start Event',
34990	    actionName: 'replace-with-signal-start',
34991	    className: 'bpmn-icon-start-event-signal',
34992	    target: {
34993	      type: 'bpmn:StartEvent',
34994	      eventDefinitionType: 'bpmn:SignalEventDefinition'
34995	    }
34996	  },
34997	  {
34998	    label: 'Error Start Event',
34999	    actionName: 'replace-with-error-start',
35000	    className: 'bpmn-icon-start-event-error',
35001	    target: {
35002	      type: 'bpmn:StartEvent',
35003	      eventDefinitionType: 'bpmn:ErrorEventDefinition'
35004	    }
35005	  },
35006	  {
35007	    label: 'Escalation Start Event',
35008	    actionName: 'replace-with-escalation-start',
35009	    className: 'bpmn-icon-start-event-escalation',
35010	    target: {
35011	      type: 'bpmn:StartEvent',
35012	      eventDefinitionType: 'bpmn:EscalationEventDefinition'
35013	    }
35014	  },
35015	  {
35016	    label: 'Compensation Start Event',
35017	    actionName: 'replace-with-compensation-start',
35018	    className: 'bpmn-icon-start-event-compensation',
35019	    target: {
35020	      type: 'bpmn:StartEvent',
35021	      eventDefinitionType: 'bpmn:CompensateEventDefinition'
35022	    }
35023	  },
35024	  {
35025	    label: 'Message Start Event (non-interrupting)',
35026	    actionName: 'replace-with-non-interrupting-message-start',
35027	    className: 'bpmn-icon-start-event-non-interrupting-message',
35028	    target: {
35029	      type: 'bpmn:StartEvent',
35030	      eventDefinitionType: 'bpmn:MessageEventDefinition',
35031	      isInterrupting: false
35032	    }
35033	  },
35034	  {
35035	    label: 'Timer Start Event (non-interrupting)',
35036	    actionName: 'replace-with-non-interrupting-timer-start',
35037	    className: 'bpmn-icon-start-event-non-interrupting-timer',
35038	    target: {
35039	      type: 'bpmn:StartEvent',
35040	      eventDefinitionType: 'bpmn:TimerEventDefinition',
35041	      isInterrupting: false
35042	    }
35043	  },
35044	  {
35045	    label: 'Conditional Start Event (non-interrupting)',
35046	    actionName: 'replace-with-non-interrupting-conditional-start',
35047	    className: 'bpmn-icon-start-event-non-interrupting-condition',
35048	    target: {
35049	      type: 'bpmn:StartEvent',
35050	      eventDefinitionType: 'bpmn:ConditionalEventDefinition',
35051	      isInterrupting: false
35052	    }
35053	  },
35054	  {
35055	    label: 'Signal Start Event (non-interrupting)',
35056	    actionName: 'replace-with-non-interrupting-signal-start',
35057	    className: 'bpmn-icon-start-event-non-interrupting-signal',
35058	    target: {
35059	      type: 'bpmn:StartEvent',
35060	      eventDefinitionType: 'bpmn:SignalEventDefinition',
35061	      isInterrupting: false
35062	    }
35063	  },
35064	  {
35065	    label: 'Escalation Start Event (non-interrupting)',
35066	    actionName: 'replace-with-non-interrupting-escalation-start',
35067	    className: 'bpmn-icon-start-event-non-interrupting-escalation',
35068	    target: {
35069	      type: 'bpmn:StartEvent',
35070	      eventDefinitionType: 'bpmn:EscalationEventDefinition',
35071	      isInterrupting: false
35072	    }
35073	  }
35074	];
35075
35076	var SEQUENCE_FLOW = [
35077	  {
35078	    label: 'Sequence Flow',
35079	    actionName: 'replace-with-sequence-flow',
35080	    className: 'bpmn-icon-connection'
35081	  },
35082	  {
35083	    label: 'Default Flow',
35084	    actionName: 'replace-with-default-flow',
35085	    className: 'bpmn-icon-default-flow'
35086	  },
35087	  {
35088	    label: 'Conditional Flow',
35089	    actionName: 'replace-with-conditional-flow',
35090	    className: 'bpmn-icon-conditional-flow'
35091	  }
35092	];
35093
35094	var PARTICIPANT = [
35095	  {
35096	    label: 'Expanded Pool',
35097	    actionName: 'replace-with-expanded-pool',
35098	    className: 'bpmn-icon-participant',
35099	    target: {
35100	      type: 'bpmn:Participant',
35101	      isExpanded: true
35102	    }
35103	  },
35104	  {
35105	    label: function(element) {
35106	      var label = 'Empty Pool';
35107
35108	      if (element.children && element.children.length) {
35109	        label += ' (removes content)';
35110	      }
35111
35112	      return label;
35113	    },
35114	    actionName: 'replace-with-collapsed-pool',
35115
35116	    // TODO(@janstuemmel): maybe design new icon
35117	    className: 'bpmn-icon-lane',
35118	    target: {
35119	      type: 'bpmn:Participant',
35120	      isExpanded: false
35121	    }
35122	  }
35123	];
35124
35125	/**
35126	 * This module is an element agnostic replace menu provider for the popup menu.
35127	 */
35128	function ReplaceMenuProvider(
35129	    bpmnFactory, popupMenu, modeling, moddle,
35130	    bpmnReplace, rules, translate) {
35131
35132	  this._bpmnFactory = bpmnFactory;
35133	  this._popupMenu = popupMenu;
35134	  this._modeling = modeling;
35135	  this._moddle = moddle;
35136	  this._bpmnReplace = bpmnReplace;
35137	  this._rules = rules;
35138	  this._translate = translate;
35139
35140	  this.register();
35141	}
35142
35143	ReplaceMenuProvider.$inject = [
35144	  'bpmnFactory',
35145	  'popupMenu',
35146	  'modeling',
35147	  'moddle',
35148	  'bpmnReplace',
35149	  'rules',
35150	  'translate'
35151	];
35152
35153
35154	/**
35155	 * Register replace menu provider in the popup menu
35156	 */
35157	ReplaceMenuProvider.prototype.register = function() {
35158	  this._popupMenu.registerProvider('bpmn-replace', this);
35159	};
35160
35161
35162	/**
35163	 * Get all entries from replaceOptions for the given element and apply filters
35164	 * on them. Get for example only elements, which are different from the current one.
35165	 *
35166	 * @param {djs.model.Base} element
35167	 *
35168	 * @return {Array<Object>} a list of menu entry items
35169	 */
35170	ReplaceMenuProvider.prototype.getEntries = function(element) {
35171
35172	  var businessObject = element.businessObject;
35173
35174	  var rules = this._rules;
35175
35176	  var entries;
35177
35178	  if (!rules.allowed('shape.replace', { element: element })) {
35179	    return [];
35180	  }
35181
35182	  var differentType = isDifferentType(element);
35183
35184	  if (is$1(businessObject, 'bpmn:DataObjectReference')) {
35185	    return this._createEntries(element, DATA_OBJECT_REFERENCE);
35186	  }
35187
35188	  if (is$1(businessObject, 'bpmn:DataStoreReference')) {
35189	    return this._createEntries(element, DATA_STORE_REFERENCE);
35190	  }
35191
35192	  // start events outside sub processes
35193	  if (is$1(businessObject, 'bpmn:StartEvent') && !is$1(businessObject.$parent, 'bpmn:SubProcess')) {
35194
35195	    entries = filter(START_EVENT, differentType);
35196
35197	    return this._createEntries(element, entries);
35198	  }
35199
35200	  // expanded/collapsed pools
35201	  if (is$1(businessObject, 'bpmn:Participant')) {
35202
35203	    entries = filter(PARTICIPANT, function(entry) {
35204	      return isExpanded(businessObject) !== entry.target.isExpanded;
35205	    });
35206
35207	    return this._createEntries(element, entries);
35208	  }
35209
35210	  // start events inside event sub processes
35211	  if (is$1(businessObject, 'bpmn:StartEvent') && isEventSubProcess(businessObject.$parent)) {
35212	    entries = filter(EVENT_SUB_PROCESS_START_EVENT, function(entry) {
35213
35214	      var target = entry.target;
35215
35216	      var isInterrupting = target.isInterrupting !== false;
35217
35218	      var isInterruptingEqual = getBusinessObject(element).isInterrupting === isInterrupting;
35219
35220	      // filters elements which types and event definition are equal but have have different interrupting types
35221	      return differentType(entry) || !differentType(entry) && !isInterruptingEqual;
35222
35223	    });
35224
35225	    return this._createEntries(element, entries);
35226	  }
35227
35228	  // start events inside sub processes
35229	  if (is$1(businessObject, 'bpmn:StartEvent') && !isEventSubProcess(businessObject.$parent)
35230	      && is$1(businessObject.$parent, 'bpmn:SubProcess')) {
35231	    entries = filter(START_EVENT_SUB_PROCESS, differentType);
35232
35233	    return this._createEntries(element, entries);
35234	  }
35235
35236	  // end events
35237	  if (is$1(businessObject, 'bpmn:EndEvent')) {
35238
35239	    entries = filter(END_EVENT, function(entry) {
35240	      var target = entry.target;
35241
35242	      // hide cancel end events outside transactions
35243	      if (target.eventDefinitionType == 'bpmn:CancelEventDefinition' && !is$1(businessObject.$parent, 'bpmn:Transaction')) {
35244	        return false;
35245	      }
35246
35247	      return differentType(entry);
35248	    });
35249
35250	    return this._createEntries(element, entries);
35251	  }
35252
35253	  // boundary events
35254	  if (is$1(businessObject, 'bpmn:BoundaryEvent')) {
35255
35256	    entries = filter(BOUNDARY_EVENT, function(entry) {
35257
35258	      var target = entry.target;
35259
35260	      if (target.eventDefinitionType == 'bpmn:CancelEventDefinition' &&
35261	         !is$1(businessObject.attachedToRef, 'bpmn:Transaction')) {
35262	        return false;
35263	      }
35264	      var cancelActivity = target.cancelActivity !== false;
35265
35266	      var isCancelActivityEqual = businessObject.cancelActivity == cancelActivity;
35267
35268	      return differentType(entry) || !differentType(entry) && !isCancelActivityEqual;
35269	    });
35270
35271	    return this._createEntries(element, entries);
35272	  }
35273
35274	  // intermediate events
35275	  if (is$1(businessObject, 'bpmn:IntermediateCatchEvent') ||
35276	      is$1(businessObject, 'bpmn:IntermediateThrowEvent')) {
35277
35278	    entries = filter(INTERMEDIATE_EVENT, differentType);
35279
35280	    return this._createEntries(element, entries);
35281	  }
35282
35283	  // gateways
35284	  if (is$1(businessObject, 'bpmn:Gateway')) {
35285
35286	    entries = filter(GATEWAY, differentType);
35287
35288	    return this._createEntries(element, entries);
35289	  }
35290
35291	  // transactions
35292	  if (is$1(businessObject, 'bpmn:Transaction')) {
35293
35294	    entries = filter(TRANSACTION, differentType);
35295
35296	    return this._createEntries(element, entries);
35297	  }
35298
35299	  // expanded event sub processes
35300	  if (isEventSubProcess(businessObject) && isExpanded(businessObject)) {
35301
35302	    entries = filter(EVENT_SUB_PROCESS, differentType);
35303
35304	    return this._createEntries(element, entries);
35305	  }
35306
35307	  // expanded sub processes
35308	  if (is$1(businessObject, 'bpmn:SubProcess') && isExpanded(businessObject)) {
35309
35310	    entries = filter(SUBPROCESS_EXPANDED, differentType);
35311
35312	    return this._createEntries(element, entries);
35313	  }
35314
35315	  // collapsed ad hoc sub processes
35316	  if (is$1(businessObject, 'bpmn:AdHocSubProcess') && !isExpanded(businessObject)) {
35317
35318	    entries = filter(TASK, function(entry) {
35319
35320	      var target = entry.target;
35321
35322	      var isTargetSubProcess = target.type === 'bpmn:SubProcess';
35323
35324	      var isTargetExpanded = target.isExpanded === true;
35325
35326	      return isDifferentType(element) && (!isTargetSubProcess || isTargetExpanded);
35327	    });
35328
35329	    return this._createEntries(element, entries);
35330	  }
35331
35332	  // sequence flows
35333	  if (is$1(businessObject, 'bpmn:SequenceFlow')) {
35334	    return this._createSequenceFlowEntries(element, SEQUENCE_FLOW);
35335	  }
35336
35337	  // flow nodes
35338	  if (is$1(businessObject, 'bpmn:FlowNode')) {
35339	    entries = filter(TASK, differentType);
35340
35341	    // collapsed SubProcess can not be replaced with itself
35342	    if (is$1(businessObject, 'bpmn:SubProcess') && !isExpanded(businessObject)) {
35343	      entries = filter(entries, function(entry) {
35344	        return entry.label !== 'Sub Process (collapsed)';
35345	      });
35346	    }
35347
35348	    return this._createEntries(element, entries);
35349	  }
35350
35351	  return [];
35352	};
35353
35354
35355	/**
35356	 * Get a list of header items for the given element. This includes buttons
35357	 * for multi instance markers and for the ad hoc marker.
35358	 *
35359	 * @param {djs.model.Base} element
35360	 *
35361	 * @return {Array<Object>} a list of menu entry items
35362	 */
35363	ReplaceMenuProvider.prototype.getHeaderEntries = function(element) {
35364
35365	  var headerEntries = [];
35366
35367	  if (is$1(element, 'bpmn:Activity') && !isEventSubProcess(element)) {
35368	    headerEntries = headerEntries.concat(this._getLoopEntries(element));
35369	  }
35370
35371	  if (is$1(element, 'bpmn:DataObjectReference')) {
35372	    headerEntries = headerEntries.concat(this._getDataObjectIsCollection(element));
35373	  }
35374
35375	  if (is$1(element, 'bpmn:Participant')) {
35376	    headerEntries = headerEntries.concat(this._getParticipantMultiplicity(element));
35377	  }
35378
35379	  if (is$1(element, 'bpmn:SubProcess') &&
35380	      !is$1(element, 'bpmn:Transaction') &&
35381	      !isEventSubProcess(element)) {
35382	    headerEntries.push(this._getAdHocEntry(element));
35383	  }
35384
35385	  return headerEntries;
35386	};
35387
35388
35389	/**
35390	 * Creates an array of menu entry objects for a given element and filters the replaceOptions
35391	 * according to a filter function.
35392	 *
35393	 * @param  {djs.model.Base} element
35394	 * @param  {Object} replaceOptions
35395	 *
35396	 * @return {Array<Object>} a list of menu items
35397	 */
35398	ReplaceMenuProvider.prototype._createEntries = function(element, replaceOptions) {
35399	  var menuEntries = [];
35400
35401	  var self = this;
35402
35403	  forEach(replaceOptions, function(definition) {
35404	    var entry = self._createMenuEntry(definition, element);
35405
35406	    menuEntries.push(entry);
35407	  });
35408
35409	  return menuEntries;
35410	};
35411
35412	/**
35413	 * Creates an array of menu entry objects for a given sequence flow.
35414	 *
35415	 * @param  {djs.model.Base} element
35416	 * @param  {Object} replaceOptions
35417
35418	 * @return {Array<Object>} a list of menu items
35419	 */
35420	ReplaceMenuProvider.prototype._createSequenceFlowEntries = function(element, replaceOptions) {
35421
35422	  var businessObject = getBusinessObject(element);
35423
35424	  var menuEntries = [];
35425
35426	  var modeling = this._modeling,
35427	      moddle = this._moddle;
35428
35429	  var self = this;
35430
35431	  forEach(replaceOptions, function(entry) {
35432
35433	    switch (entry.actionName) {
35434	    case 'replace-with-default-flow':
35435	      if (businessObject.sourceRef.default !== businessObject &&
35436	            (is$1(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
35437	             is$1(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
35438	             is$1(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
35439	             is$1(businessObject.sourceRef, 'bpmn:Activity'))) {
35440
35441	        menuEntries.push(self._createMenuEntry(entry, element, function() {
35442	          modeling.updateProperties(element.source, { default: businessObject });
35443	        }));
35444	      }
35445	      break;
35446	    case 'replace-with-conditional-flow':
35447	      if (!businessObject.conditionExpression && is$1(businessObject.sourceRef, 'bpmn:Activity')) {
35448
35449	        menuEntries.push(self._createMenuEntry(entry, element, function() {
35450	          var conditionExpression = moddle.create('bpmn:FormalExpression', { body: '' });
35451
35452	          modeling.updateProperties(element, { conditionExpression: conditionExpression });
35453	        }));
35454	      }
35455	      break;
35456	    default:
35457
35458	      // default flows
35459	      if (is$1(businessObject.sourceRef, 'bpmn:Activity') && businessObject.conditionExpression) {
35460	        return menuEntries.push(self._createMenuEntry(entry, element, function() {
35461	          modeling.updateProperties(element, { conditionExpression: undefined });
35462	        }));
35463	      }
35464
35465	      // conditional flows
35466	      if ((is$1(businessObject.sourceRef, 'bpmn:ExclusiveGateway') ||
35467	           is$1(businessObject.sourceRef, 'bpmn:InclusiveGateway') ||
35468	           is$1(businessObject.sourceRef, 'bpmn:ComplexGateway') ||
35469	           is$1(businessObject.sourceRef, 'bpmn:Activity')) &&
35470	           businessObject.sourceRef.default === businessObject) {
35471
35472	        return menuEntries.push(self._createMenuEntry(entry, element, function() {
35473	          modeling.updateProperties(element.source, { default: undefined });
35474	        }));
35475	      }
35476	    }
35477	  });
35478
35479	  return menuEntries;
35480	};
35481
35482
35483	/**
35484	 * Creates and returns a single menu entry item.
35485	 *
35486	 * @param  {Object} definition a single replace options definition object
35487	 * @param  {djs.model.Base} element
35488	 * @param  {Function} [action] an action callback function which gets called when
35489	 *                             the menu entry is being triggered.
35490	 *
35491	 * @return {Object} menu entry item
35492	 */
35493	ReplaceMenuProvider.prototype._createMenuEntry = function(definition, element, action) {
35494	  var translate = this._translate;
35495	  var replaceElement = this._bpmnReplace.replaceElement;
35496
35497	  var replaceAction = function() {
35498	    return replaceElement(element, definition.target);
35499	  };
35500
35501	  var label = definition.label;
35502	  if (label && typeof label === 'function') {
35503	    label = label(element);
35504	  }
35505
35506	  action = action || replaceAction;
35507
35508	  var menuEntry = {
35509	    label: translate(label),
35510	    className: definition.className,
35511	    id: definition.actionName,
35512	    action: action
35513	  };
35514
35515	  return menuEntry;
35516	};
35517
35518	/**
35519	 * Get a list of menu items containing buttons for multi instance markers
35520	 *
35521	 * @param  {djs.model.Base} element
35522	 *
35523	 * @return {Array<Object>} a list of menu items
35524	 */
35525	ReplaceMenuProvider.prototype._getLoopEntries = function(element) {
35526
35527	  var self = this;
35528	  var translate = this._translate;
35529
35530	  function toggleLoopEntry(event, entry) {
35531	    var loopCharacteristics;
35532
35533	    if (entry.active) {
35534	      loopCharacteristics = undefined;
35535	    } else {
35536	      loopCharacteristics = self._moddle.create(entry.options.loopCharacteristics);
35537
35538	      if (entry.options.isSequential) {
35539	        loopCharacteristics.isSequential = entry.options.isSequential;
35540	      }
35541	    }
35542	    self._modeling.updateProperties(element, { loopCharacteristics: loopCharacteristics });
35543	  }
35544
35545	  var businessObject = getBusinessObject(element),
35546	      loopCharacteristics = businessObject.loopCharacteristics;
35547
35548	  var isSequential,
35549	      isLoop,
35550	      isParallel;
35551
35552	  if (loopCharacteristics) {
35553	    isSequential = loopCharacteristics.isSequential;
35554	    isLoop = loopCharacteristics.isSequential === undefined;
35555	    isParallel = loopCharacteristics.isSequential !== undefined && !loopCharacteristics.isSequential;
35556	  }
35557
35558
35559	  var loopEntries = [
35560	    {
35561	      id: 'toggle-parallel-mi',
35562	      className: 'bpmn-icon-parallel-mi-marker',
35563	      title: translate('Parallel Multi Instance'),
35564	      active: isParallel,
35565	      action: toggleLoopEntry,
35566	      options: {
35567	        loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
35568	        isSequential: false
35569	      }
35570	    },
35571	    {
35572	      id: 'toggle-sequential-mi',
35573	      className: 'bpmn-icon-sequential-mi-marker',
35574	      title: translate('Sequential Multi Instance'),
35575	      active: isSequential,
35576	      action: toggleLoopEntry,
35577	      options: {
35578	        loopCharacteristics: 'bpmn:MultiInstanceLoopCharacteristics',
35579	        isSequential: true
35580	      }
35581	    },
35582	    {
35583	      id: 'toggle-loop',
35584	      className: 'bpmn-icon-loop-marker',
35585	      title: translate('Loop'),
35586	      active: isLoop,
35587	      action: toggleLoopEntry,
35588	      options: {
35589	        loopCharacteristics: 'bpmn:StandardLoopCharacteristics'
35590	      }
35591	    }
35592	  ];
35593	  return loopEntries;
35594	};
35595
35596	/**
35597	 * Get a list of menu items containing a button for the collection marker
35598	 *
35599	 * @param  {djs.model.Base} element
35600	 *
35601	 * @return {Array<Object>} a list of menu items
35602	 */
35603	ReplaceMenuProvider.prototype._getDataObjectIsCollection = function(element) {
35604
35605	  var self = this;
35606	  var translate = this._translate;
35607
35608	  function toggleIsCollection(event, entry) {
35609	    self._modeling.updateModdleProperties(
35610	      element,
35611	      dataObject,
35612	      { isCollection: !entry.active });
35613	  }
35614
35615	  var dataObject = element.businessObject.dataObjectRef,
35616	      isCollection = dataObject.isCollection;
35617
35618	  var dataObjectEntries = [
35619	    {
35620	      id: 'toggle-is-collection',
35621	      className: 'bpmn-icon-parallel-mi-marker',
35622	      title: translate('Collection'),
35623	      active: isCollection,
35624	      action: toggleIsCollection,
35625	    }
35626	  ];
35627	  return dataObjectEntries;
35628	};
35629
35630	/**
35631	 * Get a list of menu items containing a button for the participant multiplicity marker
35632	 *
35633	 * @param  {djs.model.Base} element
35634	 *
35635	 * @return {Array<Object>} a list of menu items
35636	 */
35637	ReplaceMenuProvider.prototype._getParticipantMultiplicity = function(element) {
35638
35639	  var self = this;
35640	  var bpmnFactory = this._bpmnFactory;
35641	  var translate = this._translate;
35642
35643	  function toggleParticipantMultiplicity(event, entry) {
35644	    var isActive = entry.active;
35645	    var participantMultiplicity;
35646
35647	    if (!isActive) {
35648	      participantMultiplicity = bpmnFactory.create('bpmn:ParticipantMultiplicity');
35649	    }
35650
35651	    self._modeling.updateProperties(
35652	      element,
35653	      { participantMultiplicity: participantMultiplicity });
35654	  }
35655
35656	  var participantMultiplicity = element.businessObject.participantMultiplicity;
35657
35658	  var participantEntries = [
35659	    {
35660	      id: 'toggle-participant-multiplicity',
35661	      className: 'bpmn-icon-parallel-mi-marker',
35662	      title: translate('Participant Multiplicity'),
35663	      active: !!participantMultiplicity,
35664	      action: toggleParticipantMultiplicity,
35665	    }
35666	  ];
35667	  return participantEntries;
35668	};
35669
35670
35671	/**
35672	 * Get the menu items containing a button for the ad hoc marker
35673	 *
35674	 * @param  {djs.model.Base} element
35675	 *
35676	 * @return {Object} a menu item
35677	 */
35678	ReplaceMenuProvider.prototype._getAdHocEntry = function(element) {
35679	  var translate = this._translate;
35680	  var businessObject = getBusinessObject(element);
35681
35682	  var isAdHoc = is$1(businessObject, 'bpmn:AdHocSubProcess');
35683
35684	  var replaceElement = this._bpmnReplace.replaceElement;
35685
35686	  var adHocEntry = {
35687	    id: 'toggle-adhoc',
35688	    className: 'bpmn-icon-ad-hoc-marker',
35689	    title: translate('Ad-hoc'),
35690	    active: isAdHoc,
35691	    action: function(event, entry) {
35692	      if (isAdHoc) {
35693	        return replaceElement(element, { type: 'bpmn:SubProcess' }, {
35694	          autoResize: false,
35695	          layoutConnection: false
35696	        });
35697	      } else {
35698	        return replaceElement(element, { type: 'bpmn:AdHocSubProcess' }, {
35699	          autoResize: false,
35700	          layoutConnection: false
35701	        });
35702	      }
35703	    }
35704	  };
35705
35706	  return adHocEntry;
35707	};
35708
35709	var PopupMenuModule = {
35710	  __depends__: [
35711	    PopupMenuModule$1,
35712	    ReplaceModule
35713	  ],
35714	  __init__: [ 'replaceMenuProvider' ],
35715	  replaceMenuProvider: [ 'type', ReplaceMenuProvider ]
35716	};
35717
35718	var max$4 = Math.max,
35719	    min$2 = Math.min;
35720
35721	var DEFAULT_CHILD_BOX_PADDING = 20;
35722
35723
35724	/**
35725	 * Substract a TRBL from another
35726	 *
35727	 * @param  {TRBL} trblA
35728	 * @param  {TRBL} trblB
35729	 *
35730	 * @return {TRBL}
35731	 */
35732	function substractTRBL(trblA, trblB) {
35733	  return {
35734	    top: trblA.top - trblB.top,
35735	    right: trblA.right - trblB.right,
35736	    bottom: trblA.bottom - trblB.bottom,
35737	    left: trblA.left - trblB.left
35738	  };
35739	}
35740
35741	/**
35742	 * Resize the given bounds by the specified delta from a given anchor point.
35743	 *
35744	 * @param {Bounds} bounds the bounding box that should be resized
35745	 * @param {string} direction in which the element is resized (nw, ne, se, sw)
35746	 * @param {Point} delta of the resize operation
35747	 *
35748	 * @return {Bounds} resized bounding box
35749	 */
35750	function resizeBounds$1(bounds, direction, delta) {
35751	  var dx = delta.x,
35752	      dy = delta.y;
35753
35754	  var newBounds = {
35755	    x: bounds.x,
35756	    y: bounds.y,
35757	    width: bounds.width,
35758	    height: bounds.height
35759	  };
35760
35761	  if (direction.indexOf('n') !== -1) {
35762	    newBounds.y = bounds.y + dy;
35763	    newBounds.height = bounds.height - dy;
35764	  } else if (direction.indexOf('s') !== -1) {
35765	    newBounds.height = bounds.height + dy;
35766	  }
35767
35768	  if (direction.indexOf('e') !== -1) {
35769	    newBounds.width = bounds.width + dx;
35770	  } else if (direction.indexOf('w') !== -1) {
35771	    newBounds.x = bounds.x + dx;
35772	    newBounds.width = bounds.width - dx;
35773	  }
35774
35775	  return newBounds;
35776	}
35777
35778
35779	/**
35780	 * Resize the given bounds by applying the passed
35781	 * { top, right, bottom, left } delta.
35782	 *
35783	 * @param {Bounds} bounds
35784	 * @param {TRBL} trblResize
35785	 *
35786	 * @return {Bounds}
35787	 */
35788	function resizeTRBL(bounds, resize) {
35789	  return {
35790	    x: bounds.x + (resize.left || 0),
35791	    y: bounds.y + (resize.top || 0),
35792	    width: bounds.width - (resize.left || 0) + (resize.right || 0),
35793	    height: bounds.height - (resize.top || 0) + (resize.bottom || 0)
35794	  };
35795	}
35796
35797
35798	function applyConstraints(attr, trbl, resizeConstraints) {
35799
35800	  var value = trbl[attr],
35801	      minValue = resizeConstraints.min && resizeConstraints.min[attr],
35802	      maxValue = resizeConstraints.max && resizeConstraints.max[attr];
35803
35804	  if (isNumber(minValue)) {
35805	    value = (/top|left/.test(attr) ? min$2 : max$4)(value, minValue);
35806	  }
35807
35808	  if (isNumber(maxValue)) {
35809	    value = (/top|left/.test(attr) ? max$4 : min$2)(value, maxValue);
35810	  }
35811
35812	  return value;
35813	}
35814
35815	function ensureConstraints$1(currentBounds, resizeConstraints) {
35816
35817	  if (!resizeConstraints) {
35818	    return currentBounds;
35819	  }
35820
35821	  var currentTrbl = asTRBL(currentBounds);
35822
35823	  return asBounds({
35824	    top: applyConstraints('top', currentTrbl, resizeConstraints),
35825	    right: applyConstraints('right', currentTrbl, resizeConstraints),
35826	    bottom: applyConstraints('bottom', currentTrbl, resizeConstraints),
35827	    left: applyConstraints('left', currentTrbl, resizeConstraints)
35828	  });
35829	}
35830
35831
35832	function getMinResizeBounds(direction, currentBounds, minDimensions, childrenBounds) {
35833
35834	  var currentBox = asTRBL(currentBounds);
35835
35836	  var minBox = {
35837	    top: /n/.test(direction) ? currentBox.bottom - minDimensions.height : currentBox.top,
35838	    left: /w/.test(direction) ? currentBox.right - minDimensions.width : currentBox.left,
35839	    bottom: /s/.test(direction) ? currentBox.top + minDimensions.height : currentBox.bottom,
35840	    right: /e/.test(direction) ? currentBox.left + minDimensions.width : currentBox.right
35841	  };
35842
35843	  var childrenBox = childrenBounds ? asTRBL(childrenBounds) : minBox;
35844
35845	  var combinedBox = {
35846	    top: min$2(minBox.top, childrenBox.top),
35847	    left: min$2(minBox.left, childrenBox.left),
35848	    bottom: max$4(minBox.bottom, childrenBox.bottom),
35849	    right: max$4(minBox.right, childrenBox.right)
35850	  };
35851
35852	  return asBounds(combinedBox);
35853	}
35854
35855	function asPadding(mayBePadding, defaultValue) {
35856	  if (typeof mayBePadding !== 'undefined') {
35857	    return mayBePadding;
35858	  } else {
35859	    return DEFAULT_CHILD_BOX_PADDING;
35860	  }
35861	}
35862
35863	function addPadding$1(bbox, padding) {
35864	  var left, right, top, bottom;
35865
35866	  if (typeof padding === 'object') {
35867	    left = asPadding(padding.left);
35868	    right = asPadding(padding.right);
35869	    top = asPadding(padding.top);
35870	    bottom = asPadding(padding.bottom);
35871	  } else {
35872	    left = right = top = bottom = asPadding(padding);
35873	  }
35874
35875	  return {
35876	    x: bbox.x - left,
35877	    y: bbox.y - top,
35878	    width: bbox.width + left + right,
35879	    height: bbox.height + top + bottom
35880	  };
35881	}
35882
35883
35884	/**
35885	 * Is the given element part of the resize
35886	 * targets min boundary box?
35887	 *
35888	 * This is the default implementation which excludes
35889	 * connections and labels.
35890	 *
35891	 * @param {djs.model.Base} element
35892	 */
35893	function isBBoxChild(element) {
35894
35895	  // exclude connections
35896	  if (element.waypoints) {
35897	    return false;
35898	  }
35899
35900	  // exclude labels
35901	  if (element.type === 'label') {
35902	    return false;
35903	  }
35904
35905	  return true;
35906	}
35907
35908	/**
35909	 * Return children bounding computed from a shapes children
35910	 * or a list of prefiltered children.
35911	 *
35912	 * @param  {djs.model.Shape|Array<djs.model.Shape>} shapeOrChildren
35913	 * @param  {number|Object} padding
35914	 *
35915	 * @return {Bounds}
35916	 */
35917	function computeChildrenBBox(shapeOrChildren, padding) {
35918
35919	  var elements;
35920
35921	  // compute based on shape
35922	  if (shapeOrChildren.length === undefined) {
35923
35924	    // grab all the children that are part of the
35925	    // parents children box
35926	    elements = filter(shapeOrChildren.children, isBBoxChild);
35927
35928	  } else {
35929	    elements = shapeOrChildren;
35930	  }
35931
35932	  if (elements.length) {
35933	    return addPadding$1(getBBox(elements), padding);
35934	  }
35935	}
35936
35937	var abs$4 = Math.abs;
35938
35939
35940	function getTRBLResize(oldBounds, newBounds) {
35941	  return substractTRBL(asTRBL(newBounds), asTRBL(oldBounds));
35942	}
35943
35944
35945	var LANE_PARENTS = [
35946	  'bpmn:Participant',
35947	  'bpmn:Process',
35948	  'bpmn:SubProcess'
35949	];
35950
35951	var LANE_INDENTATION = 30;
35952
35953
35954	/**
35955	 * Collect all lane shapes in the given paren
35956	 *
35957	 * @param  {djs.model.Shape} shape
35958	 * @param  {Array<djs.model.Base>} [collectedShapes]
35959	 *
35960	 * @return {Array<djs.model.Base>}
35961	 */
35962	function collectLanes(shape, collectedShapes) {
35963
35964	  collectedShapes = collectedShapes || [];
35965
35966	  shape.children.filter(function(s) {
35967	    if (is$1(s, 'bpmn:Lane')) {
35968	      collectLanes(s, collectedShapes);
35969
35970	      collectedShapes.push(s);
35971	    }
35972	  });
35973
35974	  return collectedShapes;
35975	}
35976
35977
35978	/**
35979	 * Return the lane children of the given element.
35980	 *
35981	 * @param {djs.model.Shape} shape
35982	 *
35983	 * @return {Array<djs.model.Shape>}
35984	 */
35985	function getChildLanes(shape) {
35986	  return shape.children.filter(function(c) {
35987	    return is$1(c, 'bpmn:Lane');
35988	  });
35989	}
35990
35991
35992	/**
35993	 * Return the root element containing the given lane shape
35994	 *
35995	 * @param {djs.model.Shape} shape
35996	 *
35997	 * @return {djs.model.Shape}
35998	 */
35999	function getLanesRoot(shape) {
36000	  return getParent(shape, LANE_PARENTS) || shape;
36001	}
36002
36003
36004	/**
36005	 * Compute the required resize operations for lanes
36006	 * adjacent to the given shape, assuming it will be
36007	 * resized to the given new bounds.
36008	 *
36009	 * @param {djs.model.Shape} shape
36010	 * @param {Bounds} newBounds
36011	 *
36012	 * @return {Array<Object>}
36013	 */
36014	function computeLanesResize(shape, newBounds) {
36015
36016	  var rootElement = getLanesRoot(shape);
36017
36018	  var initialShapes = is$1(rootElement, 'bpmn:Process') ? [] : [ rootElement ];
36019
36020	  var allLanes = collectLanes(rootElement, initialShapes),
36021	      shapeTrbl = asTRBL(shape),
36022	      shapeNewTrbl = asTRBL(newBounds),
36023	      trblResize = getTRBLResize(shape, newBounds),
36024	      resizeNeeded = [];
36025
36026	  allLanes.forEach(function(other) {
36027
36028	    if (other === shape) {
36029	      return;
36030	    }
36031
36032	    var topResize = 0,
36033	        rightResize = trblResize.right,
36034	        bottomResize = 0,
36035	        leftResize = trblResize.left;
36036
36037	    var otherTrbl = asTRBL(other);
36038
36039	    if (trblResize.top) {
36040	      if (abs$4(otherTrbl.bottom - shapeTrbl.top) < 10) {
36041	        bottomResize = shapeNewTrbl.top - otherTrbl.bottom;
36042	      }
36043
36044	      if (abs$4(otherTrbl.top - shapeTrbl.top) < 5) {
36045	        topResize = shapeNewTrbl.top - otherTrbl.top;
36046	      }
36047	    }
36048
36049	    if (trblResize.bottom) {
36050	      if (abs$4(otherTrbl.top - shapeTrbl.bottom) < 10) {
36051	        topResize = shapeNewTrbl.bottom - otherTrbl.top;
36052	      }
36053
36054	      if (abs$4(otherTrbl.bottom - shapeTrbl.bottom) < 5) {
36055	        bottomResize = shapeNewTrbl.bottom - otherTrbl.bottom;
36056	      }
36057	    }
36058
36059	    if (topResize || rightResize || bottomResize || leftResize) {
36060
36061	      resizeNeeded.push({
36062	        shape: other,
36063	        newBounds: resizeTRBL(other, {
36064	          top: topResize,
36065	          right: rightResize,
36066	          bottom: bottomResize,
36067	          left: leftResize
36068	        })
36069	      });
36070	    }
36071
36072	  });
36073
36074	  return resizeNeeded;
36075	}
36076
36077	/**
36078	 * A provider for BPMN 2.0 elements context pad
36079	 */
36080	function ContextPadProvider(
36081	    config, injector, eventBus,
36082	    contextPad, modeling, elementFactory,
36083	    connect, create, popupMenu,
36084	    canvas, rules, translate) {
36085
36086	  config = config || {};
36087
36088	  contextPad.registerProvider(this);
36089
36090	  this._contextPad = contextPad;
36091
36092	  this._modeling = modeling;
36093
36094	  this._elementFactory = elementFactory;
36095	  this._connect = connect;
36096	  this._create = create;
36097	  this._popupMenu = popupMenu;
36098	  this._canvas = canvas;
36099	  this._rules = rules;
36100	  this._translate = translate;
36101
36102	  if (config.autoPlace !== false) {
36103	    this._autoPlace = injector.get('autoPlace', false);
36104	  }
36105
36106	  eventBus.on('create.end', 250, function(event) {
36107	    var context = event.context,
36108	        shape = context.shape;
36109
36110	    if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
36111	      return;
36112	    }
36113
36114	    var entries = contextPad.getEntries(shape);
36115
36116	    if (entries.replace) {
36117	      entries.replace.action.click(event, shape);
36118	    }
36119	  });
36120	}
36121
36122	ContextPadProvider.$inject = [
36123	  'config.contextPad',
36124	  'injector',
36125	  'eventBus',
36126	  'contextPad',
36127	  'modeling',
36128	  'elementFactory',
36129	  'connect',
36130	  'create',
36131	  'popupMenu',
36132	  'canvas',
36133	  'rules',
36134	  'translate'
36135	];
36136
36137
36138	ContextPadProvider.prototype.getContextPadEntries = function(element) {
36139
36140	  var contextPad = this._contextPad,
36141	      modeling = this._modeling,
36142
36143	      elementFactory = this._elementFactory,
36144	      connect = this._connect,
36145	      create = this._create,
36146	      popupMenu = this._popupMenu,
36147	      canvas = this._canvas,
36148	      rules = this._rules,
36149	      autoPlace = this._autoPlace,
36150	      translate = this._translate;
36151
36152	  var actions = {};
36153
36154	  if (element.type === 'label') {
36155	    return actions;
36156	  }
36157
36158	  var businessObject = element.businessObject;
36159
36160	  function startConnect(event, element) {
36161	    connect.start(event, element);
36162	  }
36163
36164	  function removeElement(e) {
36165	    modeling.removeElements([ element ]);
36166	  }
36167
36168	  function getReplaceMenuPosition(element) {
36169
36170	    var Y_OFFSET = 5;
36171
36172	    var diagramContainer = canvas.getContainer(),
36173	        pad = contextPad.getPad(element).html;
36174
36175	    var diagramRect = diagramContainer.getBoundingClientRect(),
36176	        padRect = pad.getBoundingClientRect();
36177
36178	    var top = padRect.top - diagramRect.top;
36179	    var left = padRect.left - diagramRect.left;
36180
36181	    var pos = {
36182	      x: left,
36183	      y: top + padRect.height + Y_OFFSET
36184	    };
36185
36186	    return pos;
36187	  }
36188
36189
36190	  /**
36191	   * Create an append action
36192	   *
36193	   * @param {string} type
36194	   * @param {string} className
36195	   * @param {string} [title]
36196	   * @param {Object} [options]
36197	   *
36198	   * @return {Object} descriptor
36199	   */
36200	  function appendAction(type, className, title, options) {
36201
36202	    if (typeof title !== 'string') {
36203	      options = title;
36204	      title = translate('Append {type}', { type: type.replace(/^bpmn:/, '') });
36205	    }
36206
36207	    function appendStart(event, element) {
36208
36209	      var shape = elementFactory.createShape(assign({ type: type }, options));
36210	      create.start(event, shape, {
36211	        source: element
36212	      });
36213	    }
36214
36215
36216	    var append = autoPlace ? function(event, element) {
36217	      var shape = elementFactory.createShape(assign({ type: type }, options));
36218
36219	      autoPlace.append(element, shape);
36220	    } : appendStart;
36221
36222
36223	    return {
36224	      group: 'model',
36225	      className: className,
36226	      title: title,
36227	      action: {
36228	        dragstart: appendStart,
36229	        click: append
36230	      }
36231	    };
36232	  }
36233
36234	  function splitLaneHandler(count) {
36235
36236	    return function(event, element) {
36237
36238	      // actual split
36239	      modeling.splitLane(element, count);
36240
36241	      // refresh context pad after split to
36242	      // get rid of split icons
36243	      contextPad.open(element, true);
36244	    };
36245	  }
36246
36247
36248	  if (isAny(businessObject, [ 'bpmn:Lane', 'bpmn:Participant' ]) && isExpanded(businessObject)) {
36249
36250	    var childLanes = getChildLanes(element);
36251
36252	    assign(actions, {
36253	      'lane-insert-above': {
36254	        group: 'lane-insert-above',
36255	        className: 'bpmn-icon-lane-insert-above',
36256	        title: translate('Add Lane above'),
36257	        action: {
36258	          click: function(event, element) {
36259	            modeling.addLane(element, 'top');
36260	          }
36261	        }
36262	      }
36263	    });
36264
36265	    if (childLanes.length < 2) {
36266
36267	      if (element.height >= 120) {
36268	        assign(actions, {
36269	          'lane-divide-two': {
36270	            group: 'lane-divide',
36271	            className: 'bpmn-icon-lane-divide-two',
36272	            title: translate('Divide into two Lanes'),
36273	            action: {
36274	              click: splitLaneHandler(2)
36275	            }
36276	          }
36277	        });
36278	      }
36279
36280	      if (element.height >= 180) {
36281	        assign(actions, {
36282	          'lane-divide-three': {
36283	            group: 'lane-divide',
36284	            className: 'bpmn-icon-lane-divide-three',
36285	            title: translate('Divide into three Lanes'),
36286	            action: {
36287	              click: splitLaneHandler(3)
36288	            }
36289	          }
36290	        });
36291	      }
36292	    }
36293
36294	    assign(actions, {
36295	      'lane-insert-below': {
36296	        group: 'lane-insert-below',
36297	        className: 'bpmn-icon-lane-insert-below',
36298	        title: translate('Add Lane below'),
36299	        action: {
36300	          click: function(event, element) {
36301	            modeling.addLane(element, 'bottom');
36302	          }
36303	        }
36304	      }
36305	    });
36306
36307	  }
36308
36309	  if (is$1(businessObject, 'bpmn:FlowNode')) {
36310
36311	    if (is$1(businessObject, 'bpmn:EventBasedGateway')) {
36312
36313	      assign(actions, {
36314	        'append.receive-task': appendAction(
36315	          'bpmn:ReceiveTask',
36316	          'bpmn-icon-receive-task',
36317	          translate('Append ReceiveTask')
36318	        ),
36319	        'append.message-intermediate-event': appendAction(
36320	          'bpmn:IntermediateCatchEvent',
36321	          'bpmn-icon-intermediate-event-catch-message',
36322	          translate('Append MessageIntermediateCatchEvent'),
36323	          { eventDefinitionType: 'bpmn:MessageEventDefinition' }
36324	        ),
36325	        'append.timer-intermediate-event': appendAction(
36326	          'bpmn:IntermediateCatchEvent',
36327	          'bpmn-icon-intermediate-event-catch-timer',
36328	          translate('Append TimerIntermediateCatchEvent'),
36329	          { eventDefinitionType: 'bpmn:TimerEventDefinition' }
36330	        ),
36331	        'append.condition-intermediate-event': appendAction(
36332	          'bpmn:IntermediateCatchEvent',
36333	          'bpmn-icon-intermediate-event-catch-condition',
36334	          translate('Append ConditionIntermediateCatchEvent'),
36335	          { eventDefinitionType: 'bpmn:ConditionalEventDefinition' }
36336	        ),
36337	        'append.signal-intermediate-event': appendAction(
36338	          'bpmn:IntermediateCatchEvent',
36339	          'bpmn-icon-intermediate-event-catch-signal',
36340	          translate('Append SignalIntermediateCatchEvent'),
36341	          { eventDefinitionType: 'bpmn:SignalEventDefinition' }
36342	        )
36343	      });
36344	    } else
36345
36346	    if (isEventType(businessObject, 'bpmn:BoundaryEvent', 'bpmn:CompensateEventDefinition')) {
36347
36348	      assign(actions, {
36349	        'append.compensation-activity':
36350	            appendAction(
36351	              'bpmn:Task',
36352	              'bpmn-icon-task',
36353	              translate('Append compensation activity'),
36354	              {
36355	                isForCompensation: true
36356	              }
36357	            )
36358	      });
36359	    } else
36360
36361	    if (!is$1(businessObject, 'bpmn:EndEvent') &&
36362	        !businessObject.isForCompensation &&
36363	        !isEventType(businessObject, 'bpmn:IntermediateThrowEvent', 'bpmn:LinkEventDefinition') &&
36364	        !isEventSubProcess(businessObject)) {
36365
36366	      assign(actions, {
36367	        'append.end-event': appendAction(
36368	          'bpmn:EndEvent',
36369	          'bpmn-icon-end-event-none',
36370	          translate('Append EndEvent')
36371	        ),
36372	        'append.gateway': appendAction(
36373	          'bpmn:ExclusiveGateway',
36374	          'bpmn-icon-gateway-none',
36375	          translate('Append Gateway')
36376	        ),
36377	        'append.append-task': appendAction(
36378	          'bpmn:Task',
36379	          'bpmn-icon-task',
36380	          translate('Append Task')
36381	        ),
36382	        'append.intermediate-event': appendAction(
36383	          'bpmn:IntermediateThrowEvent',
36384	          'bpmn-icon-intermediate-event-none',
36385	          translate('Append Intermediate/Boundary Event')
36386	        )
36387	      });
36388	    }
36389	  }
36390
36391	  if (!popupMenu.isEmpty(element, 'bpmn-replace')) {
36392
36393	    // Replace menu entry
36394	    assign(actions, {
36395	      'replace': {
36396	        group: 'edit',
36397	        className: 'bpmn-icon-screw-wrench',
36398	        title: translate('Change type'),
36399	        action: {
36400	          click: function(event, element) {
36401
36402	            var position = assign(getReplaceMenuPosition(element), {
36403	              cursor: { x: event.x, y: event.y }
36404	            });
36405
36406	            popupMenu.open(element, 'bpmn-replace', position);
36407	          }
36408	        }
36409	      }
36410	    });
36411	  }
36412
36413	  if (
36414	    isAny(businessObject, [
36415	      'bpmn:FlowNode',
36416	      'bpmn:InteractionNode',
36417	      'bpmn:DataObjectReference',
36418	      'bpmn:DataStoreReference',
36419	    ])
36420	  ) {
36421	    assign(actions, {
36422	      'append.text-annotation': appendAction(
36423	        'bpmn:TextAnnotation',
36424	        'bpmn-icon-text-annotation'
36425	      ),
36426
36427	      'connect': {
36428	        group: 'connect',
36429	        className: 'bpmn-icon-connection-multi',
36430	        title: translate(
36431	          'Connect using ' +
36432	            (businessObject.isForCompensation
36433	              ? ''
36434	              : 'Sequence/MessageFlow or ') +
36435	            'Association'
36436	        ),
36437	        action: {
36438	          click: startConnect,
36439	          dragstart: startConnect,
36440	        },
36441	      },
36442	    });
36443	  }
36444
36445	  if (is$1(businessObject, 'bpmn:TextAnnotation')) {
36446	    assign(actions, {
36447	      'connect': {
36448	        group: 'connect',
36449	        className: 'bpmn-icon-connection-multi',
36450	        title: translate('Connect using Association'),
36451	        action: {
36452	          click: startConnect,
36453	          dragstart: startConnect,
36454	        },
36455	      },
36456	    });
36457	  }
36458
36459	  if (isAny(businessObject, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ])) {
36460	    assign(actions, {
36461	      'connect': {
36462	        group: 'connect',
36463	        className: 'bpmn-icon-connection-multi',
36464	        title: translate('Connect using DataInputAssociation'),
36465	        action: {
36466	          click: startConnect,
36467	          dragstart: startConnect
36468	        }
36469	      }
36470	    });
36471	  }
36472
36473	  if (is$1(businessObject, 'bpmn:Group')) {
36474	    assign(actions, {
36475	      'append.text-annotation': appendAction('bpmn:TextAnnotation', 'bpmn-icon-text-annotation')
36476	    });
36477	  }
36478
36479	  // delete element entry, only show if allowed by rules
36480	  var deleteAllowed = rules.allowed('elements.delete', { elements: [ element ] });
36481
36482	  if (isArray$2(deleteAllowed)) {
36483
36484	    // was the element returned as a deletion candidate?
36485	    deleteAllowed = deleteAllowed[0] === element;
36486	  }
36487
36488	  if (deleteAllowed) {
36489	    assign(actions, {
36490	      'delete': {
36491	        group: 'edit',
36492	        className: 'bpmn-icon-trash',
36493	        title: translate('Remove'),
36494	        action: {
36495	          click: removeElement
36496	        }
36497	      }
36498	    });
36499	  }
36500
36501	  return actions;
36502	};
36503
36504
36505	// helpers /////////
36506
36507	function isEventType(eventBo, type, definition) {
36508
36509	  var isType = eventBo.$instanceOf(type);
36510	  var isDefinition = false;
36511
36512	  var definitions = eventBo.eventDefinitions || [];
36513	  forEach(definitions, function(def) {
36514	    if (def.$type === definition) {
36515	      isDefinition = true;
36516	    }
36517	  });
36518
36519	  return isType && isDefinition;
36520	}
36521
36522	var ContextPadModule = {
36523	  __depends__: [
36524	    DirectEditingModule,
36525	    ContextPadModule$1,
36526	    SelectionModule,
36527	    ConnectModule,
36528	    CreateModule,
36529	    PopupMenuModule
36530	  ],
36531	  __init__: [ 'contextPadProvider' ],
36532	  contextPadProvider: [ 'type', ContextPadProvider ]
36533	};
36534
36535	var AXIS_DIMENSIONS = {
36536	  horizontal: [ 'x', 'width' ],
36537	  vertical: [ 'y', 'height' ]
36538	};
36539
36540	var THRESHOLD = 5;
36541
36542
36543	/**
36544	 * Groups and filters elements and then trigger even distribution.
36545	 */
36546	function DistributeElements$1(modeling) {
36547	  this._modeling = modeling;
36548
36549	  this._filters = [];
36550
36551	  // register filter for filtering big elements
36552	  this.registerFilter(function(elements, axis, dimension) {
36553	    var elementsSize = 0,
36554	        numOfShapes = 0,
36555	        avgDimension;
36556
36557	    forEach(elements, function(element) {
36558	      if (element.waypoints || element.labelTarget) {
36559	        return;
36560	      }
36561
36562	      elementsSize += element[dimension];
36563
36564	      numOfShapes += 1;
36565	    });
36566
36567	    avgDimension = Math.round(elementsSize / numOfShapes);
36568
36569	    return filter(elements, function(element) {
36570	      return element[dimension] < (avgDimension + 50);
36571	    });
36572	  });
36573
36574	}
36575
36576	DistributeElements$1.$inject = [ 'modeling' ];
36577
36578
36579	/**
36580	 * Registers filter functions that allow external parties to filter
36581	 * out certain elements.
36582	 *
36583	 * @param  {Function} filterFn
36584	 */
36585	DistributeElements$1.prototype.registerFilter = function(filterFn) {
36586	  if (typeof filterFn !== 'function') {
36587	    throw new Error('the filter has to be a function');
36588	  }
36589
36590	  this._filters.push(filterFn);
36591	};
36592
36593	/**
36594	 * Distributes the elements with a given orientation
36595	 *
36596	 * @param  {Array} elements
36597	 * @param  {string} orientation
36598	 */
36599	DistributeElements$1.prototype.trigger = function(elements, orientation) {
36600	  var modeling = this._modeling;
36601
36602	  var groups,
36603	      distributableElements;
36604
36605	  if (elements.length < 3) {
36606	    return;
36607	  }
36608
36609	  this._setOrientation(orientation);
36610
36611	  distributableElements = this._filterElements(elements);
36612
36613	  groups = this._createGroups(distributableElements);
36614
36615	  // nothing to distribute
36616	  if (groups.length <= 2) {
36617	    return;
36618	  }
36619
36620	  modeling.distributeElements(groups, this._axis, this._dimension);
36621
36622	  return groups;
36623	};
36624
36625	/**
36626	 * Filters the elements with provided filters by external parties
36627	 *
36628	 * @param  {Array[Elements]} elements
36629	 *
36630	 * @return {Array[Elements]}
36631	 */
36632	DistributeElements$1.prototype._filterElements = function(elements) {
36633	  var filters = this._filters,
36634	      axis = this._axis,
36635	      dimension = this._dimension,
36636	      distributableElements = [].concat(elements);
36637
36638	  if (!filters.length) {
36639	    return elements;
36640	  }
36641
36642	  forEach(filters, function(filterFn) {
36643	    distributableElements = filterFn(distributableElements, axis, dimension);
36644	  });
36645
36646	  return distributableElements;
36647	};
36648
36649
36650	/**
36651	 * Create range (min, max) groups. Also tries to group elements
36652	 * together that share the same range.
36653	 *
36654	 * @example
36655	 * 	var distributableElements = [
36656	 * 		{
36657	 * 			range: {
36658	 * 				min: 100,
36659	 * 				max: 200
36660	 * 			},
36661	 * 			elements: [ { id: 'shape1', .. }]
36662	 * 		}
36663	 * 	]
36664	 *
36665	 * @param  {Array} elements
36666	 *
36667	 * @return {Array[Objects]}
36668	 */
36669	DistributeElements$1.prototype._createGroups = function(elements) {
36670	  var rangeGroups = [],
36671	      self = this,
36672	      axis = this._axis,
36673	      dimension = this._dimension;
36674
36675	  if (!axis) {
36676	    throw new Error('must have a defined "axis" and "dimension"');
36677	  }
36678
36679	  // sort by 'left->right' or 'top->bottom'
36680	  var sortedElements = sortBy(elements, axis);
36681
36682	  forEach(sortedElements, function(element, idx) {
36683	    var elementRange = self._findRange(element, axis, dimension),
36684	        range;
36685
36686	    var previous = rangeGroups[rangeGroups.length - 1];
36687
36688	    if (previous && self._hasIntersection(previous.range, elementRange)) {
36689	      rangeGroups[rangeGroups.length - 1].elements.push(element);
36690	    } else {
36691	      range = { range: elementRange, elements: [ element ] };
36692
36693	      rangeGroups.push(range);
36694	    }
36695	  });
36696
36697	  return rangeGroups;
36698	};
36699
36700
36701	/**
36702	 * Maps a direction to the according axis and dimension
36703	 *
36704	 * @param  {string} direction 'horizontal' or 'vertical'
36705	 */
36706	DistributeElements$1.prototype._setOrientation = function(direction) {
36707	  var orientation = AXIS_DIMENSIONS[direction];
36708
36709	  this._axis = orientation[0];
36710	  this._dimension = orientation[1];
36711	};
36712
36713
36714	/**
36715	 * Checks if the two ranges intercept each other
36716	 *
36717	 * @param  {Object} rangeA {min, max}
36718	 * @param  {Object} rangeB {min, max}
36719	 *
36720	 * @return {boolean}
36721	 */
36722	DistributeElements$1.prototype._hasIntersection = function(rangeA, rangeB) {
36723	  return Math.max(rangeA.min, rangeA.max) >= Math.min(rangeB.min, rangeB.max) &&
36724	         Math.min(rangeA.min, rangeA.max) <= Math.max(rangeB.min, rangeB.max);
36725	};
36726
36727
36728	/**
36729	 * Returns the min and max values for an element
36730	 *
36731	 * @param  {Bounds} element
36732	 * @param  {string} axis
36733	 * @param  {string} dimension
36734	 *
36735	 * @return {{ min: number, max: number }}
36736	 */
36737	DistributeElements$1.prototype._findRange = function(element) {
36738	  var axis = element[this._axis],
36739	      dimension = element[this._dimension];
36740
36741	  return {
36742	    min: axis + THRESHOLD,
36743	    max: axis + dimension - THRESHOLD
36744	  };
36745	};
36746
36747	var DistributeElementsModule$1 = {
36748	  __init__: [ 'distributeElements' ],
36749	  distributeElements: [ 'type', DistributeElements$1 ]
36750	};
36751
36752	/**
36753	 * Registers element exclude filters for elements that
36754	 * currently do not support distribution.
36755	 */
36756	function BpmnDistributeElements(distributeElements) {
36757
36758	  distributeElements.registerFilter(function(elements) {
36759	    return filter(elements, function(element) {
36760	      var cannotDistribute = isAny(element, [
36761	        'bpmn:Association',
36762	        'bpmn:BoundaryEvent',
36763	        'bpmn:DataInputAssociation',
36764	        'bpmn:DataOutputAssociation',
36765	        'bpmn:Lane',
36766	        'bpmn:MessageFlow',
36767	        'bpmn:Participant',
36768	        'bpmn:SequenceFlow',
36769	        'bpmn:TextAnnotation'
36770	      ]);
36771
36772	      return !(element.labelTarget || cannotDistribute);
36773	    });
36774	  });
36775	}
36776
36777	BpmnDistributeElements.$inject = [ 'distributeElements' ];
36778
36779	var DistributeElementsModule = {
36780	  __depends__: [
36781	    DistributeElementsModule$1
36782	  ],
36783	  __init__: [ 'bpmnDistributeElements' ],
36784	  bpmnDistributeElements: [ 'type', BpmnDistributeElements ]
36785	};
36786
36787	var NOT_REGISTERED_ERROR = 'is not a registered action',
36788	    IS_REGISTERED_ERROR = 'is already registered';
36789
36790
36791	/**
36792	 * An interface that provides access to modeling actions by decoupling
36793	 * the one who requests the action to be triggered and the trigger itself.
36794	 *
36795	 * It's possible to add new actions by registering them with ´registerAction´
36796	 * and likewise unregister existing ones with ´unregisterAction´.
36797	 *
36798	 *
36799	 * ## Life-Cycle and configuration
36800	 *
36801	 * The editor actions will wait for diagram initialization before
36802	 * registering default actions _and_ firing an `editorActions.init` event.
36803	 *
36804	 * Interested parties may listen to the `editorActions.init` event with
36805	 * low priority to check, which actions got registered. Other components
36806	 * may use the event to register their own actions via `registerAction`.
36807	 *
36808	 * @param {EventBus} eventBus
36809	 * @param {Injector} injector
36810	 */
36811	function EditorActions(eventBus, injector) {
36812
36813	  // initialize actions
36814	  this._actions = {};
36815
36816	  var self = this;
36817
36818	  eventBus.on('diagram.init', function() {
36819
36820	    // all diagram modules got loaded; check which ones
36821	    // are available and register the respective default actions
36822	    self._registerDefaultActions(injector);
36823
36824	    // ask interested parties to register available editor
36825	    // actions on diagram initialization
36826	    eventBus.fire('editorActions.init', {
36827	      editorActions: self
36828	    });
36829	  });
36830
36831	}
36832
36833	EditorActions.$inject = [
36834	  'eventBus',
36835	  'injector'
36836	];
36837
36838	/**
36839	 * Register default actions.
36840	 *
36841	 * @param {Injector} injector
36842	 */
36843	EditorActions.prototype._registerDefaultActions = function(injector) {
36844
36845	  // (1) retrieve optional components to integrate with
36846
36847	  var commandStack = injector.get('commandStack', false);
36848	  var modeling = injector.get('modeling', false);
36849	  var selection = injector.get('selection', false);
36850	  var zoomScroll = injector.get('zoomScroll', false);
36851	  var copyPaste = injector.get('copyPaste', false);
36852	  var canvas = injector.get('canvas', false);
36853	  var rules = injector.get('rules', false);
36854	  var keyboardMove = injector.get('keyboardMove', false);
36855	  var keyboardMoveSelection = injector.get('keyboardMoveSelection', false);
36856
36857	  // (2) check components and register actions
36858
36859	  if (commandStack) {
36860	    this.register('undo', function() {
36861	      commandStack.undo();
36862	    });
36863
36864	    this.register('redo', function() {
36865	      commandStack.redo();
36866	    });
36867	  }
36868
36869	  if (copyPaste && selection) {
36870	    this.register('copy', function() {
36871	      var selectedElements = selection.get();
36872
36873	      copyPaste.copy(selectedElements);
36874	    });
36875	  }
36876
36877	  if (copyPaste) {
36878	    this.register('paste', function() {
36879	      copyPaste.paste();
36880	    });
36881	  }
36882
36883	  if (zoomScroll) {
36884	    this.register('stepZoom', function(opts) {
36885	      zoomScroll.stepZoom(opts.value);
36886	    });
36887	  }
36888
36889	  if (canvas) {
36890	    this.register('zoom', function(opts) {
36891	      canvas.zoom(opts.value);
36892	    });
36893	  }
36894
36895	  if (modeling && selection && rules) {
36896	    this.register('removeSelection', function() {
36897
36898	      var selectedElements = selection.get();
36899
36900	      if (!selectedElements.length) {
36901	        return;
36902	      }
36903
36904	      var allowed = rules.allowed('elements.delete', { elements: selectedElements }),
36905	          removableElements;
36906
36907	      if (allowed === false) {
36908	        return;
36909	      }
36910	      else if (isArray$2(allowed)) {
36911	        removableElements = allowed;
36912	      }
36913	      else {
36914	        removableElements = selectedElements;
36915	      }
36916
36917	      if (removableElements.length) {
36918	        modeling.removeElements(removableElements.slice());
36919	      }
36920	    });
36921	  }
36922
36923	  if (keyboardMove) {
36924	    this.register('moveCanvas', function(opts) {
36925	      keyboardMove.moveCanvas(opts);
36926	    });
36927	  }
36928
36929	  if (keyboardMoveSelection) {
36930	    this.register('moveSelection', function(opts) {
36931	      keyboardMoveSelection.moveSelection(opts.direction, opts.accelerated);
36932	    });
36933	  }
36934
36935	};
36936
36937
36938	/**
36939	 * Triggers a registered action
36940	 *
36941	 * @param  {string} action
36942	 * @param  {Object} opts
36943	 *
36944	 * @return {Unknown} Returns what the registered listener returns
36945	 */
36946	EditorActions.prototype.trigger = function(action, opts) {
36947	  if (!this._actions[action]) {
36948	    throw error(action, NOT_REGISTERED_ERROR);
36949	  }
36950
36951	  return this._actions[action](opts);
36952	};
36953
36954
36955	/**
36956	 * Registers a collections of actions.
36957	 * The key of the object will be the name of the action.
36958	 *
36959	 * @example
36960	 * ´´´
36961	 * var actions = {
36962	 *   spaceTool: function() {
36963	 *     spaceTool.activateSelection();
36964	 *   },
36965	 *   lassoTool: function() {
36966	 *     lassoTool.activateSelection();
36967	 *   }
36968	 * ];
36969	 *
36970	 * editorActions.register(actions);
36971	 *
36972	 * editorActions.isRegistered('spaceTool'); // true
36973	 * ´´´
36974	 *
36975	 * @param  {Object} actions
36976	 */
36977	EditorActions.prototype.register = function(actions, listener) {
36978	  var self = this;
36979
36980	  if (typeof actions === 'string') {
36981	    return this._registerAction(actions, listener);
36982	  }
36983
36984	  forEach(actions, function(listener, action) {
36985	    self._registerAction(action, listener);
36986	  });
36987	};
36988
36989	/**
36990	 * Registers a listener to an action key
36991	 *
36992	 * @param  {string} action
36993	 * @param  {Function} listener
36994	 */
36995	EditorActions.prototype._registerAction = function(action, listener) {
36996	  if (this.isRegistered(action)) {
36997	    throw error(action, IS_REGISTERED_ERROR);
36998	  }
36999
37000	  this._actions[action] = listener;
37001	};
37002
37003	/**
37004	 * Unregister an existing action
37005	 *
37006	 * @param {string} action
37007	 */
37008	EditorActions.prototype.unregister = function(action) {
37009	  if (!this.isRegistered(action)) {
37010	    throw error(action, NOT_REGISTERED_ERROR);
37011	  }
37012
37013	  this._actions[action] = undefined;
37014	};
37015
37016	/**
37017	 * Returns the number of actions that are currently registered
37018	 *
37019	 * @return {number}
37020	 */
37021	EditorActions.prototype.getActions = function() {
37022	  return Object.keys(this._actions);
37023	};
37024
37025	/**
37026	 * Checks wether the given action is registered
37027	 *
37028	 * @param {string} action
37029	 *
37030	 * @return {boolean}
37031	 */
37032	EditorActions.prototype.isRegistered = function(action) {
37033	  return !!this._actions[action];
37034	};
37035
37036
37037	function error(action, message) {
37038	  return new Error(action + ' ' + message);
37039	}
37040
37041	var EditorActionsModule$1 = {
37042	  __init__: [ 'editorActions' ],
37043	  editorActions: [ 'type', EditorActions ]
37044	};
37045
37046	/**
37047	 * Registers and executes BPMN specific editor actions.
37048	 *
37049	 * @param {Injector} injector
37050	 */
37051	function BpmnEditorActions(injector) {
37052	  injector.invoke(EditorActions, this);
37053	}
37054
37055	inherits$1(BpmnEditorActions, EditorActions);
37056
37057	BpmnEditorActions.$inject = [
37058	  'injector'
37059	];
37060
37061	/**
37062	 * Register default actions.
37063	 *
37064	 * @param {Injector} injector
37065	 */
37066	BpmnEditorActions.prototype._registerDefaultActions = function(injector) {
37067
37068	  // (0) invoke super method
37069
37070	  EditorActions.prototype._registerDefaultActions.call(this, injector);
37071
37072	  // (1) retrieve optional components to integrate with
37073
37074	  var canvas = injector.get('canvas', false);
37075	  var elementRegistry = injector.get('elementRegistry', false);
37076	  var selection = injector.get('selection', false);
37077	  var spaceTool = injector.get('spaceTool', false);
37078	  var lassoTool = injector.get('lassoTool', false);
37079	  var handTool = injector.get('handTool', false);
37080	  var globalConnect = injector.get('globalConnect', false);
37081	  var distributeElements = injector.get('distributeElements', false);
37082	  var alignElements = injector.get('alignElements', false);
37083	  var directEditing = injector.get('directEditing', false);
37084	  var searchPad = injector.get('searchPad', false);
37085	  var modeling = injector.get('modeling', false);
37086
37087	  // (2) check components and register actions
37088
37089	  if (canvas && elementRegistry && selection) {
37090	    this._registerAction('selectElements', function() {
37091
37092	      // select all elements except for the invisible
37093	      // root element
37094	      var rootElement = canvas.getRootElement();
37095
37096	      var elements = elementRegistry.filter(function(element) {
37097	        return element !== rootElement;
37098	      });
37099
37100	      selection.select(elements);
37101
37102	      return elements;
37103	    });
37104	  }
37105
37106	  if (spaceTool) {
37107	    this._registerAction('spaceTool', function() {
37108	      spaceTool.toggle();
37109	    });
37110	  }
37111
37112	  if (lassoTool) {
37113	    this._registerAction('lassoTool', function() {
37114	      lassoTool.toggle();
37115	    });
37116	  }
37117
37118	  if (handTool) {
37119	    this._registerAction('handTool', function() {
37120	      handTool.toggle();
37121	    });
37122	  }
37123
37124	  if (globalConnect) {
37125	    this._registerAction('globalConnectTool', function() {
37126	      globalConnect.toggle();
37127	    });
37128	  }
37129
37130	  if (selection && distributeElements) {
37131	    this._registerAction('distributeElements', function(opts) {
37132	      var currentSelection = selection.get(),
37133	          type = opts.type;
37134
37135	      if (currentSelection.length) {
37136	        distributeElements.trigger(currentSelection, type);
37137	      }
37138	    });
37139	  }
37140
37141	  if (selection && alignElements) {
37142	    this._registerAction('alignElements', function(opts) {
37143	      var currentSelection = selection.get(),
37144	          aligneableElements = [],
37145	          type = opts.type;
37146
37147	      if (currentSelection.length) {
37148	        aligneableElements = filter(currentSelection, function(element) {
37149	          return !is$1(element, 'bpmn:Lane');
37150	        });
37151
37152	        alignElements.trigger(aligneableElements, type);
37153	      }
37154	    });
37155	  }
37156
37157	  if (selection && modeling) {
37158	    this._registerAction('setColor', function(opts) {
37159	      var currentSelection = selection.get();
37160
37161	      if (currentSelection.length) {
37162	        modeling.setColor(currentSelection, opts);
37163	      }
37164	    });
37165	  }
37166
37167	  if (selection && directEditing) {
37168	    this._registerAction('directEditing', function() {
37169	      var currentSelection = selection.get();
37170
37171	      if (currentSelection.length) {
37172	        directEditing.activate(currentSelection[0]);
37173	      }
37174	    });
37175	  }
37176
37177	  if (searchPad) {
37178	    this._registerAction('find', function() {
37179	      searchPad.toggle();
37180	    });
37181	  }
37182
37183	  if (canvas && modeling) {
37184	    this._registerAction('moveToOrigin', function() {
37185	      var rootElement = canvas.getRootElement(),
37186	          boundingBox,
37187	          elements;
37188
37189	      if (is$1(rootElement, 'bpmn:Collaboration')) {
37190	        elements = elementRegistry.filter(function(element) {
37191	          return is$1(element.parent, 'bpmn:Collaboration');
37192	        });
37193	      } else {
37194	        elements = elementRegistry.filter(function(element) {
37195	          return element !== rootElement && !is$1(element.parent, 'bpmn:SubProcess');
37196	        });
37197	      }
37198
37199	      boundingBox = getBBox(elements);
37200
37201	      modeling.moveElements(
37202	        elements,
37203	        { x: -boundingBox.x, y: -boundingBox.y },
37204	        rootElement
37205	      );
37206	    });
37207	  }
37208
37209	};
37210
37211	var EditorActionsModule = {
37212	  __depends__: [
37213	    EditorActionsModule$1
37214	  ],
37215	  editorActions: [ 'type', BpmnEditorActions ]
37216	};
37217
37218	function BpmnGridSnapping(eventBus) {
37219	  eventBus.on([
37220	    'create.init',
37221	    'shape.move.init'
37222	  ], function(event) {
37223	    var context = event.context,
37224	        shape = event.shape;
37225
37226	    if (isAny(shape, [
37227	      'bpmn:Participant',
37228	      'bpmn:SubProcess',
37229	      'bpmn:TextAnnotation'
37230	    ])) {
37231	      if (!context.gridSnappingContext) {
37232	        context.gridSnappingContext = {};
37233	      }
37234
37235	      context.gridSnappingContext.snapLocation = 'top-left';
37236	    }
37237	  });
37238	}
37239
37240	BpmnGridSnapping.$inject = [ 'eventBus' ];
37241
37242	var SPACING = 10;
37243
37244	function quantize(value, quantum, fn) {
37245	  if (!fn) {
37246	    fn = 'round';
37247	  }
37248
37249	  return Math[ fn ](value / quantum) * quantum;
37250	}
37251
37252	var LOWER_PRIORITY = 1200;
37253	var LOW_PRIORITY$e = 800;
37254
37255	/**
37256	 * Basic grid snapping that covers connecting, creating, moving, resizing shapes, moving bendpoints
37257	 * and connection segments.
37258	 */
37259	function GridSnapping(elementRegistry, eventBus, config) {
37260
37261	  var active = !config || config.active !== false;
37262
37263	  this._eventBus = eventBus;
37264
37265	  var self = this;
37266
37267	  eventBus.on('diagram.init', LOW_PRIORITY$e, function() {
37268	    self.setActive(active);
37269	  });
37270
37271	  eventBus.on([
37272	    'create.move',
37273	    'create.end',
37274	    'bendpoint.move.move',
37275	    'bendpoint.move.end',
37276	    'connect.move',
37277	    'connect.end',
37278	    'connectionSegment.move.move',
37279	    'connectionSegment.move.end',
37280	    'resize.move',
37281	    'resize.end',
37282	    'shape.move.move',
37283	    'shape.move.end'
37284	  ], LOWER_PRIORITY, function(event) {
37285	    var originalEvent = event.originalEvent;
37286
37287	    if (!self.active || (originalEvent && isCmd(originalEvent))) {
37288	      return;
37289	    }
37290
37291	    var context = event.context,
37292	        gridSnappingContext = context.gridSnappingContext;
37293
37294	    if (!gridSnappingContext) {
37295	      gridSnappingContext = context.gridSnappingContext = {};
37296	    }
37297
37298	    [ 'x', 'y' ].forEach(function(axis) {
37299	      var options = {};
37300
37301	      // allow snapping with offset
37302	      var snapOffset = getSnapOffset(event, axis, elementRegistry);
37303
37304	      if (snapOffset) {
37305	        options.offset = snapOffset;
37306	      }
37307
37308	      // allow snapping with min and max
37309	      var snapConstraints = getSnapConstraints(event, axis);
37310
37311	      if (snapConstraints) {
37312	        assign(options, snapConstraints);
37313	      }
37314
37315	      if (!isSnapped(event, axis)) {
37316	        self.snapEvent(event, axis, options);
37317	      }
37318	    });
37319	  });
37320	}
37321
37322	/**
37323	 * Snap an events x or y with optional min, max and offset.
37324	 *
37325	 * @param {Object} event
37326	 * @param {string} axis
37327	 * @param {number} [options.min]
37328	 * @param {number} [options.max]
37329	 * @param {number} [options.offset]
37330	 */
37331	GridSnapping.prototype.snapEvent = function(event, axis, options) {
37332	  var snappedValue = this.snapValue(event[ axis ], options);
37333
37334	  setSnapped(event, axis, snappedValue);
37335	};
37336
37337	/**
37338	 * Expose grid spacing for third parties (i.e. extensions).
37339	 *
37340	 * @return {number} spacing of grid dots
37341	 */
37342	GridSnapping.prototype.getGridSpacing = function() {
37343	  return SPACING;
37344	};
37345
37346	/**
37347	 * Snap value with optional min, max and offset.
37348	 *
37349	 * @param {number} value
37350	 * @param {Object} options
37351	 * @param {number} [options.min]
37352	 * @param {number} [options.max]
37353	 * @param {number} [options.offset]
37354	 */
37355	GridSnapping.prototype.snapValue = function(value, options) {
37356	  var offset = 0;
37357
37358	  if (options && options.offset) {
37359	    offset = options.offset;
37360	  }
37361
37362	  value += offset;
37363
37364	  value = quantize(value, SPACING);
37365
37366	  var min, max;
37367
37368	  if (options && options.min) {
37369	    min = options.min;
37370
37371	    if (isNumber(min)) {
37372	      min = quantize(min + offset, SPACING, 'ceil');
37373
37374	      value = Math.max(value, min);
37375	    }
37376	  }
37377
37378	  if (options && options.max) {
37379	    max = options.max;
37380
37381	    if (isNumber(max)) {
37382	      max = quantize(max + offset, SPACING, 'floor');
37383
37384	      value = Math.min(value, max);
37385	    }
37386	  }
37387
37388	  value -= offset;
37389
37390	  return value;
37391	};
37392
37393	GridSnapping.prototype.isActive = function() {
37394	  return this.active;
37395	};
37396
37397	GridSnapping.prototype.setActive = function(active) {
37398	  this.active = active;
37399
37400	  this._eventBus.fire('gridSnapping.toggle', { active: active });
37401	};
37402
37403	GridSnapping.prototype.toggleActive = function() {
37404	  this.setActive(!this.active);
37405	};
37406
37407	GridSnapping.$inject = [
37408	  'elementRegistry',
37409	  'eventBus',
37410	  'config.gridSnapping'
37411	];
37412
37413	// helpers //////////
37414
37415	/**
37416	 * Get minimum and maximum snap constraints.
37417	 * Constraints are cached.
37418	 *
37419	 * @param {Object} event
37420	 * @param {Object} event.context
37421	 * @param {string} axis
37422	 *
37423	 * @returns {boolean|Object}
37424	 */
37425	function getSnapConstraints(event, axis) {
37426	  var context = event.context,
37427	      createConstraints = context.createConstraints,
37428	      resizeConstraints = context.resizeConstraints || {},
37429	      gridSnappingContext = context.gridSnappingContext,
37430	      snapConstraints = gridSnappingContext.snapConstraints;
37431
37432	  // cache snap constraints
37433	  if (snapConstraints && snapConstraints[ axis ]) {
37434	    return snapConstraints[ axis ];
37435	  }
37436
37437	  if (!snapConstraints) {
37438	    snapConstraints = gridSnappingContext.snapConstraints = {};
37439	  }
37440
37441	  if (!snapConstraints[ axis ]) {
37442	    snapConstraints[ axis ] = {};
37443	  }
37444
37445	  var direction = context.direction;
37446
37447	  // create
37448	  if (createConstraints) {
37449	    if (isHorizontal$3(axis)) {
37450	      snapConstraints.x.min = createConstraints.left;
37451	      snapConstraints.x.max = createConstraints.right;
37452	    } else {
37453	      snapConstraints.y.min = createConstraints.top;
37454	      snapConstraints.y.max = createConstraints.bottom;
37455	    }
37456	  }
37457
37458	  // resize
37459	  var minResizeConstraints = resizeConstraints.min,
37460	      maxResizeConstraints = resizeConstraints.max;
37461
37462	  if (minResizeConstraints) {
37463	    if (isHorizontal$3(axis)) {
37464
37465	      if (isWest(direction)) {
37466	        snapConstraints.x.max = minResizeConstraints.left;
37467	      } else {
37468	        snapConstraints.x.min = minResizeConstraints.right;
37469	      }
37470
37471	    } else {
37472
37473	      if (isNorth(direction)) {
37474	        snapConstraints.y.max = minResizeConstraints.top;
37475	      } else {
37476	        snapConstraints.y.min = minResizeConstraints.bottom;
37477	      }
37478
37479	    }
37480	  }
37481
37482	  if (maxResizeConstraints) {
37483	    if (isHorizontal$3(axis)) {
37484
37485	      if (isWest(direction)) {
37486	        snapConstraints.x.min = maxResizeConstraints.left;
37487	      } else {
37488	        snapConstraints.x.max = maxResizeConstraints.right;
37489	      }
37490
37491	    } else {
37492
37493	      if (isNorth(direction)) {
37494	        snapConstraints.y.min = maxResizeConstraints.top;
37495	      } else {
37496	        snapConstraints.y.max = maxResizeConstraints.bottom;
37497	      }
37498
37499	    }
37500	  }
37501
37502	  return snapConstraints[ axis ];
37503	}
37504
37505	/**
37506	 * Get snap offset.
37507	 * Offset is cached.
37508	 *
37509	 * @param {Object} event
37510	 * @param {string} axis
37511	 * @param {ElementRegistry} elementRegistry
37512	 *
37513	 * @returns {number}
37514	 */
37515	function getSnapOffset(event, axis, elementRegistry) {
37516	  var context = event.context,
37517	      shape = event.shape,
37518	      gridSnappingContext = context.gridSnappingContext,
37519	      snapLocation = gridSnappingContext.snapLocation,
37520	      snapOffset = gridSnappingContext.snapOffset;
37521
37522	  // cache snap offset
37523	  if (snapOffset && isNumber(snapOffset[ axis ])) {
37524	    return snapOffset[ axis ];
37525	  }
37526
37527	  if (!snapOffset) {
37528	    snapOffset = gridSnappingContext.snapOffset = {};
37529	  }
37530
37531	  if (!isNumber(snapOffset[ axis ])) {
37532	    snapOffset[ axis ] = 0;
37533	  }
37534
37535	  if (!shape) {
37536	    return snapOffset[ axis ];
37537	  }
37538
37539	  if (!elementRegistry.get(shape.id)) {
37540
37541	    if (isHorizontal$3(axis)) {
37542	      snapOffset[ axis ] += shape[ axis ] + shape.width / 2;
37543	    } else {
37544	      snapOffset[ axis ] += shape[ axis ] + shape.height / 2;
37545	    }
37546	  }
37547
37548	  if (!snapLocation) {
37549	    return snapOffset[ axis ];
37550	  }
37551
37552	  if (axis === 'x') {
37553	    if (/left/.test(snapLocation)) {
37554	      snapOffset[ axis ] -= shape.width / 2;
37555	    } else if (/right/.test(snapLocation)) {
37556	      snapOffset[ axis ] += shape.width / 2;
37557	    }
37558	  } else {
37559	    if (/top/.test(snapLocation)) {
37560	      snapOffset[ axis ] -= shape.height / 2;
37561	    } else if (/bottom/.test(snapLocation)) {
37562	      snapOffset[ axis ] += shape.height / 2;
37563	    }
37564	  }
37565
37566	  return snapOffset[ axis ];
37567	}
37568
37569	function isHorizontal$3(axis) {
37570	  return axis === 'x';
37571	}
37572
37573	function isNorth(direction) {
37574	  return direction.indexOf('n') !== -1;
37575	}
37576
37577	function isWest(direction) {
37578	  return direction.indexOf('w') !== -1;
37579	}
37580
37581	/**
37582	 * Integrates resizing with grid snapping.
37583	 */
37584	function ResizeBehavior$1(eventBus, gridSnapping) {
37585	  CommandInterceptor.call(this, eventBus);
37586
37587	  this._gridSnapping = gridSnapping;
37588
37589	  var self = this;
37590
37591	  this.preExecute('shape.resize', function(event) {
37592	    var context = event.context,
37593	        hints = context.hints || {},
37594	        autoResize = hints.autoResize;
37595
37596	    if (!autoResize) {
37597	      return;
37598	    }
37599
37600	    var shape = context.shape,
37601	        newBounds = context.newBounds;
37602
37603	    if (isString(autoResize)) {
37604	      context.newBounds = self.snapComplex(newBounds, autoResize);
37605	    } else {
37606	      context.newBounds = self.snapSimple(shape, newBounds);
37607	    }
37608	  });
37609	}
37610
37611	ResizeBehavior$1.$inject = [
37612	  'eventBus',
37613	  'gridSnapping',
37614	  'modeling'
37615	];
37616
37617	inherits$1(ResizeBehavior$1, CommandInterceptor);
37618
37619	/**
37620	 * Snap width and height in relation to center.
37621	 *
37622	 * @param {djs.model.shape} shape
37623	 * @param {Bounds} newBounds
37624	 *
37625	 * @returns {Bounds} Snapped bounds.
37626	 */
37627	ResizeBehavior$1.prototype.snapSimple = function(shape, newBounds) {
37628	  var gridSnapping = this._gridSnapping;
37629
37630	  newBounds.width = gridSnapping.snapValue(newBounds.width, {
37631	    min: newBounds.width
37632	  });
37633
37634	  newBounds.height = gridSnapping.snapValue(newBounds.height, {
37635	    min: newBounds.height
37636	  });
37637
37638	  newBounds.x = shape.x + (shape.width / 2) - (newBounds.width / 2);
37639	  newBounds.y = shape.y + (shape.height / 2) - (newBounds.height / 2);
37640
37641	  return newBounds;
37642	};
37643
37644	/**
37645	 * Snap x, y, width and height according to given directions.
37646	 *
37647	 * @param {Bounds} newBounds
37648	 * @param {string} directions - Directions as {n|w|s|e}.
37649	 *
37650	 * @returns {Bounds} Snapped bounds.
37651	 */
37652	ResizeBehavior$1.prototype.snapComplex = function(newBounds, directions) {
37653	  if (/w|e/.test(directions)) {
37654	    newBounds = this.snapHorizontally(newBounds, directions);
37655	  }
37656
37657	  if (/n|s/.test(directions)) {
37658	    newBounds = this.snapVertically(newBounds, directions);
37659	  }
37660
37661	  return newBounds;
37662	};
37663
37664	/**
37665	 * Snap in one or both directions horizontally.
37666	 *
37667	 * @param {Bounds} newBounds
37668	 * @param {string} directions - Directions as {n|w|s|e}.
37669	 *
37670	 * @returns {Bounds} Snapped bounds.
37671	 */
37672	ResizeBehavior$1.prototype.snapHorizontally = function(newBounds, directions) {
37673	  var gridSnapping = this._gridSnapping,
37674	      west = /w/.test(directions),
37675	      east = /e/.test(directions);
37676
37677	  var snappedNewBounds = {};
37678
37679	  snappedNewBounds.width = gridSnapping.snapValue(newBounds.width, {
37680	    min: newBounds.width
37681	  });
37682
37683	  if (east) {
37684
37685	    // handle <we>
37686	    if (west) {
37687	      snappedNewBounds.x = gridSnapping.snapValue(newBounds.x, {
37688	        max: newBounds.x
37689	      });
37690
37691	      snappedNewBounds.width += gridSnapping.snapValue(newBounds.x - snappedNewBounds.x, {
37692	        min: newBounds.x - snappedNewBounds.x
37693	      });
37694	    }
37695
37696	    // handle <e>
37697	    else {
37698	      newBounds.x = newBounds.x + newBounds.width - snappedNewBounds.width;
37699	    }
37700	  }
37701
37702	  // assign snapped x and width
37703	  assign(newBounds, snappedNewBounds);
37704
37705	  return newBounds;
37706	};
37707
37708	/**
37709	 * Snap in one or both directions vertically.
37710	 *
37711	 * @param {Bounds} newBounds
37712	 * @param {string} directions - Directions as {n|w|s|e}.
37713	 *
37714	 * @returns {Bounds} Snapped bounds.
37715	 */
37716	ResizeBehavior$1.prototype.snapVertically = function(newBounds, directions) {
37717	  var gridSnapping = this._gridSnapping,
37718	      north = /n/.test(directions),
37719	      south = /s/.test(directions);
37720
37721	  var snappedNewBounds = {};
37722
37723	  snappedNewBounds.height = gridSnapping.snapValue(newBounds.height, {
37724	    min: newBounds.height
37725	  });
37726
37727	  if (north) {
37728
37729	    // handle <ns>
37730	    if (south) {
37731	      snappedNewBounds.y = gridSnapping.snapValue(newBounds.y, {
37732	        max: newBounds.y
37733	      });
37734
37735	      snappedNewBounds.height += gridSnapping.snapValue(newBounds.y - snappedNewBounds.y, {
37736	        min: newBounds.y - snappedNewBounds.y
37737	      });
37738	    }
37739
37740	    // handle <n>
37741	    else {
37742	      newBounds.y = newBounds.y + newBounds.height - snappedNewBounds.height;
37743	    }
37744	  }
37745
37746	  // assign snapped y and height
37747	  assign(newBounds, snappedNewBounds);
37748
37749	  return newBounds;
37750	};
37751
37752	var HIGH_PRIORITY$f = 2000;
37753
37754	/**
37755	 * Integrates space tool with grid snapping.
37756	 */
37757	function SpaceToolBehavior$1(eventBus, gridSnapping) {
37758	  eventBus.on([
37759	    'spaceTool.move',
37760	    'spaceTool.end'
37761	  ], HIGH_PRIORITY$f, function(event) {
37762	    var context = event.context;
37763
37764	    if (!context.initialized) {
37765	      return;
37766	    }
37767
37768	    var axis = context.axis;
37769
37770	    var snapped;
37771
37772	    if (axis === 'x') {
37773
37774	      // snap delta x to multiple of 10
37775	      snapped = gridSnapping.snapValue(event.dx);
37776
37777	      event.x = event.x + snapped - event.dx;
37778	      event.dx = snapped;
37779	    } else {
37780
37781	      // snap delta y to multiple of 10
37782	      snapped = gridSnapping.snapValue(event.dy);
37783
37784	      event.y = event.y + snapped - event.dy;
37785	      event.dy = snapped;
37786	    }
37787	  });
37788	}
37789
37790	SpaceToolBehavior$1.$inject = [
37791	  'eventBus',
37792	  'gridSnapping'
37793	];
37794
37795	var GridSnappingBehaviorModule$1 = {
37796	  __init__: [
37797	    'gridSnappingResizeBehavior',
37798	    'gridSnappingSpaceToolBehavior'
37799	  ],
37800	  gridSnappingResizeBehavior: [ 'type', ResizeBehavior$1 ],
37801	  gridSnappingSpaceToolBehavior: [ 'type', SpaceToolBehavior$1 ]
37802	};
37803
37804	var GridSnappingModule$1 = {
37805	  __depends__: [ GridSnappingBehaviorModule$1 ],
37806	  __init__: [ 'gridSnapping' ],
37807	  gridSnapping: [ 'type', GridSnapping ]
37808	};
37809
37810	var HIGH_PRIORITY$e = 2000;
37811
37812
37813	function AutoPlaceBehavior(eventBus, gridSnapping) {
37814	  eventBus.on('autoPlace', HIGH_PRIORITY$e, function(context) {
37815	    var source = context.source,
37816	        sourceMid = getMid(source),
37817	        shape = context.shape;
37818
37819	    var position = getNewShapePosition(source, shape);
37820
37821	    [ 'x', 'y' ].forEach(function(axis) {
37822	      var options = {};
37823
37824	      // do not snap if x/y equal
37825	      if (position[ axis ] === sourceMid[ axis ]) {
37826	        return;
37827	      }
37828
37829	      if (position[ axis ] > sourceMid[ axis ]) {
37830	        options.min = position[ axis ];
37831	      } else {
37832	        options.max = position[ axis ];
37833	      }
37834
37835	      if (is$1(shape, 'bpmn:TextAnnotation')) {
37836
37837	        if (isHorizontal$2(axis)) {
37838	          options.offset = -shape.width / 2;
37839	        } else {
37840	          options.offset = -shape.height / 2;
37841	        }
37842
37843	      }
37844
37845	      position[ axis ] = gridSnapping.snapValue(position[ axis ], options);
37846
37847	    });
37848
37849	    // must be returned to be considered by auto place
37850	    return position;
37851	  });
37852	}
37853
37854	AutoPlaceBehavior.$inject = [
37855	  'eventBus',
37856	  'gridSnapping'
37857	];
37858
37859	// helpers //////////
37860
37861	function isHorizontal$2(axis) {
37862	  return axis === 'x';
37863	}
37864
37865	var HIGHER_PRIORITY$4 = 1750;
37866
37867
37868	function CreateParticipantBehavior$1(canvas, eventBus, gridSnapping) {
37869	  eventBus.on([
37870	    'create.start',
37871	    'shape.move.start'
37872	  ], HIGHER_PRIORITY$4, function(event) {
37873	    var context = event.context,
37874	        shape = context.shape,
37875	        rootElement = canvas.getRootElement();
37876
37877	    if (!is$1(shape, 'bpmn:Participant') ||
37878	      !is$1(rootElement, 'bpmn:Process') ||
37879	      !rootElement.children.length) {
37880	      return;
37881	    }
37882
37883	    var createConstraints = context.createConstraints;
37884
37885	    if (!createConstraints) {
37886	      return;
37887	    }
37888
37889	    shape.width = gridSnapping.snapValue(shape.width, { min: shape.width });
37890	    shape.height = gridSnapping.snapValue(shape.height, { min: shape.height });
37891	  });
37892	}
37893
37894	CreateParticipantBehavior$1.$inject = [
37895	  'canvas',
37896	  'eventBus',
37897	  'gridSnapping'
37898	];
37899
37900	var HIGH_PRIORITY$d = 3000;
37901
37902
37903	/**
37904	 * Snaps connections with Manhattan layout.
37905	 */
37906	function LayoutConnectionBehavior(eventBus, gridSnapping, modeling) {
37907	  CommandInterceptor.call(this, eventBus);
37908
37909	  this._gridSnapping = gridSnapping;
37910
37911	  var self = this;
37912
37913	  this.postExecuted([
37914	    'connection.create',
37915	    'connection.layout'
37916	  ], HIGH_PRIORITY$d, function(event) {
37917	    var context = event.context,
37918	        connection = context.connection,
37919	        hints = context.hints || {},
37920	        waypoints = connection.waypoints;
37921
37922	    if (hints.connectionStart || hints.connectionEnd || hints.createElementsBehavior === false) {
37923	      return;
37924	    }
37925
37926	    if (!hasMiddleSegments(waypoints)) {
37927	      return;
37928	    }
37929
37930	    modeling.updateWaypoints(connection, self.snapMiddleSegments(waypoints));
37931	  });
37932	}
37933
37934	LayoutConnectionBehavior.$inject = [
37935	  'eventBus',
37936	  'gridSnapping',
37937	  'modeling'
37938	];
37939
37940	inherits$1(LayoutConnectionBehavior, CommandInterceptor);
37941
37942	/**
37943	 * Snap middle segments of a given connection.
37944	 *
37945	 * @param {Array<Point>} waypoints
37946	 *
37947	 * @returns {Array<Point>}
37948	 */
37949	LayoutConnectionBehavior.prototype.snapMiddleSegments = function(waypoints) {
37950	  var gridSnapping = this._gridSnapping,
37951	      snapped;
37952
37953	  waypoints = waypoints.slice();
37954
37955	  for (var i = 1; i < waypoints.length - 2; i++) {
37956
37957	    snapped = snapSegment(gridSnapping, waypoints[i], waypoints[i + 1]);
37958
37959	    waypoints[i] = snapped[0];
37960	    waypoints[i + 1] = snapped[1];
37961	  }
37962
37963	  return waypoints;
37964	};
37965
37966
37967	// helpers //////////
37968
37969	/**
37970	 * Check whether a connection has a middle segments.
37971	 *
37972	 * @param {Array} waypoints
37973	 *
37974	 * @returns {boolean}
37975	 */
37976	function hasMiddleSegments(waypoints) {
37977	  return waypoints.length > 3;
37978	}
37979
37980	/**
37981	 * Check whether an alignment is horizontal.
37982	 *
37983	 * @param {string} aligned
37984	 *
37985	 * @returns {boolean}
37986	 */
37987	function horizontallyAligned(aligned) {
37988	  return aligned === 'h';
37989	}
37990
37991	/**
37992	 * Check whether an alignment is vertical.
37993	 *
37994	 * @param {string} aligned
37995	 *
37996	 * @returns {boolean}
37997	 */
37998	function verticallyAligned(aligned) {
37999	  return aligned === 'v';
38000	}
38001
38002	/**
38003	 * Get middle segments from a given connection.
38004	 *
38005	 * @param {Array} waypoints
38006	 *
38007	 * @returns {Array}
38008	 */
38009	function snapSegment(gridSnapping, segmentStart, segmentEnd) {
38010
38011	  var aligned = pointsAligned(segmentStart, segmentEnd);
38012
38013	  var snapped = {};
38014
38015	  if (horizontallyAligned(aligned)) {
38016
38017	    // snap horizontally
38018	    snapped.y = gridSnapping.snapValue(segmentStart.y);
38019	  }
38020
38021	  if (verticallyAligned(aligned)) {
38022
38023	    // snap vertically
38024	    snapped.x = gridSnapping.snapValue(segmentStart.x);
38025	  }
38026
38027	  if ('x' in snapped || 'y' in snapped) {
38028	    segmentStart = assign({}, segmentStart, snapped);
38029	    segmentEnd = assign({}, segmentEnd, snapped);
38030	  }
38031
38032	  return [ segmentStart, segmentEnd ];
38033	}
38034
38035	var GridSnappingBehaviorModule = {
38036	  __init__: [
38037	    'gridSnappingAutoPlaceBehavior',
38038	    'gridSnappingCreateParticipantBehavior',
38039	    'gridSnappingLayoutConnectionBehavior',
38040	  ],
38041	  gridSnappingAutoPlaceBehavior: [ 'type', AutoPlaceBehavior ],
38042	  gridSnappingCreateParticipantBehavior: [ 'type', CreateParticipantBehavior$1 ],
38043	  gridSnappingLayoutConnectionBehavior: [ 'type', LayoutConnectionBehavior ]
38044	};
38045
38046	var GridSnappingModule = {
38047	  __depends__: [
38048	    GridSnappingModule$1,
38049	    GridSnappingBehaviorModule
38050	  ],
38051	  __init__: [ 'bpmnGridSnapping' ],
38052	  bpmnGridSnapping: [ 'type', BpmnGridSnapping ]
38053	};
38054
38055	var LABEL_WIDTH = 30,
38056	    LABEL_HEIGHT = 30;
38057
38058
38059	/**
38060	 * BPMN-specific hit zones and interaction fixes.
38061	 *
38062	 * @param {EventBus} eventBus
38063	 * @param {InteractionEvents} interactionEvents
38064	 */
38065	function BpmnInteractionEvents(eventBus, interactionEvents) {
38066
38067	  this._interactionEvents = interactionEvents;
38068
38069	  var self = this;
38070
38071	  eventBus.on([
38072	    'interactionEvents.createHit',
38073	    'interactionEvents.updateHit'
38074	  ], function(context) {
38075	    var element = context.element,
38076	        gfx = context.gfx;
38077
38078	    if (is$1(element, 'bpmn:Lane')) {
38079	      return self.createParticipantHit(element, gfx);
38080	    } else
38081
38082	    if (is$1(element, 'bpmn:Participant')) {
38083	      if (isExpanded(element)) {
38084	        return self.createParticipantHit(element, gfx);
38085	      } else {
38086	        return self.createDefaultHit(element, gfx);
38087	      }
38088	    } else
38089
38090	    if (is$1(element, 'bpmn:SubProcess')) {
38091	      if (isExpanded(element)) {
38092	        return self.createSubProcessHit(element, gfx);
38093	      } else {
38094	        return self.createDefaultHit(element, gfx);
38095	      }
38096	    }
38097	  });
38098
38099	}
38100
38101	BpmnInteractionEvents.$inject = [
38102	  'eventBus',
38103	  'interactionEvents'
38104	];
38105
38106
38107	BpmnInteractionEvents.prototype.createDefaultHit = function(element, gfx) {
38108	  this._interactionEvents.removeHits(gfx);
38109
38110	  this._interactionEvents.createDefaultHit(element, gfx);
38111
38112	  // indicate that we created a hit
38113	  return true;
38114	};
38115
38116	BpmnInteractionEvents.prototype.createParticipantHit = function(element, gfx) {
38117
38118	  // remove existing hits
38119	  this._interactionEvents.removeHits(gfx);
38120
38121	  // add outline hit
38122	  this._interactionEvents.createBoxHit(gfx, 'click-stroke', {
38123	    width: element.width,
38124	    height: element.height
38125	  });
38126
38127	  // add label hit
38128	  this._interactionEvents.createBoxHit(gfx, 'all', {
38129	    width: LABEL_WIDTH,
38130	    height: element.height
38131	  });
38132
38133	  // indicate that we created a hit
38134	  return true;
38135	};
38136
38137	BpmnInteractionEvents.prototype.createSubProcessHit = function(element, gfx) {
38138
38139	  // remove existing hits
38140	  this._interactionEvents.removeHits(gfx);
38141
38142	  // add outline hit
38143	  this._interactionEvents.createBoxHit(gfx, 'click-stroke', {
38144	    width: element.width,
38145	    height: element.height
38146	  });
38147
38148	  // add label hit
38149	  this._interactionEvents.createBoxHit(gfx, 'all', {
38150	    width: element.width,
38151	    height: LABEL_HEIGHT
38152	  });
38153
38154	  // indicate that we created a hit
38155	  return true;
38156	};
38157
38158	var InteractionEventsModule = {
38159	  __init__: [ 'bpmnInteractionEvents' ],
38160	  bpmnInteractionEvents: [ 'type', BpmnInteractionEvents ]
38161	};
38162
38163	/**
38164	 * BPMN 2.0 specific keyboard bindings.
38165	 *
38166	 * @param {Injector} injector
38167	 */
38168	function BpmnKeyboardBindings(injector) {
38169	  injector.invoke(KeyboardBindings, this);
38170	}
38171
38172	inherits$1(BpmnKeyboardBindings, KeyboardBindings);
38173
38174	BpmnKeyboardBindings.$inject = [
38175	  'injector'
38176	];
38177
38178
38179	/**
38180	 * Register available keyboard bindings.
38181	 *
38182	 * @param {Keyboard} keyboard
38183	 * @param {EditorActions} editorActions
38184	 */
38185	BpmnKeyboardBindings.prototype.registerBindings = function(keyboard, editorActions) {
38186
38187	  // inherit default bindings
38188	  KeyboardBindings.prototype.registerBindings.call(this, keyboard, editorActions);
38189
38190	  /**
38191	   * Add keyboard binding if respective editor action
38192	   * is registered.
38193	   *
38194	   * @param {string} action name
38195	   * @param {Function} fn that implements the key binding
38196	   */
38197	  function addListener(action, fn) {
38198
38199	    if (editorActions.isRegistered(action)) {
38200	      keyboard.addListener(fn);
38201	    }
38202	  }
38203
38204	  // select all elements
38205	  // CTRL + A
38206	  addListener('selectElements', function(context) {
38207
38208	    var event = context.keyEvent;
38209
38210	    if (keyboard.isKey(['a', 'A'], event) && keyboard.isCmd(event)) {
38211	      editorActions.trigger('selectElements');
38212
38213	      return true;
38214	    }
38215	  });
38216
38217	  // search labels
38218	  // CTRL + F
38219	  addListener('find', function(context) {
38220
38221	    var event = context.keyEvent;
38222
38223	    if (keyboard.isKey(['f', 'F'], event) && keyboard.isCmd(event)) {
38224	      editorActions.trigger('find');
38225
38226	      return true;
38227	    }
38228	  });
38229
38230	  // activate space tool
38231	  // S
38232	  addListener('spaceTool', function(context) {
38233
38234	    var event = context.keyEvent;
38235
38236	    if (keyboard.hasModifier(event)) {
38237	      return;
38238	    }
38239
38240	    if (keyboard.isKey(['s', 'S'], event)) {
38241	      editorActions.trigger('spaceTool');
38242
38243	      return true;
38244	    }
38245	  });
38246
38247	  // activate lasso tool
38248	  // L
38249	  addListener('lassoTool', function(context) {
38250
38251	    var event = context.keyEvent;
38252
38253	    if (keyboard.hasModifier(event)) {
38254	      return;
38255	    }
38256
38257	    if (keyboard.isKey(['l', 'L'], event)) {
38258	      editorActions.trigger('lassoTool');
38259
38260	      return true;
38261	    }
38262	  });
38263
38264	  // activate hand tool
38265	  // H
38266	  addListener('handTool', function(context) {
38267
38268	    var event = context.keyEvent;
38269
38270	    if (keyboard.hasModifier(event)) {
38271	      return;
38272	    }
38273
38274	    if (keyboard.isKey(['h', 'H'], event)) {
38275	      editorActions.trigger('handTool');
38276
38277	      return true;
38278	    }
38279	  });
38280
38281	  // activate global connect tool
38282	  // C
38283	  addListener('globalConnectTool', function(context) {
38284
38285	    var event = context.keyEvent;
38286
38287	    if (keyboard.hasModifier(event)) {
38288	      return;
38289	    }
38290
38291	    if (keyboard.isKey(['c', 'C'], event)) {
38292	      editorActions.trigger('globalConnectTool');
38293
38294	      return true;
38295	    }
38296	  });
38297
38298	  // activate direct editing
38299	  // E
38300	  addListener('directEditing', function(context) {
38301
38302	    var event = context.keyEvent;
38303
38304	    if (keyboard.hasModifier(event)) {
38305	      return;
38306	    }
38307
38308	    if (keyboard.isKey(['e', 'E'], event)) {
38309	      editorActions.trigger('directEditing');
38310
38311	      return true;
38312	    }
38313	  });
38314
38315	};
38316
38317	var KeyboardModule = {
38318	  __depends__: [
38319	    KeyboardModule$1
38320	  ],
38321	  __init__: [ 'keyboardBindings' ],
38322	  keyboardBindings: [ 'type', BpmnKeyboardBindings ]
38323	};
38324
38325	var DEFAULT_CONFIG = {
38326	  moveSpeed: 1,
38327	  moveSpeedAccelerated: 10
38328	};
38329
38330	var HIGHER_PRIORITY$3 = 1500;
38331
38332	var LEFT = 'left';
38333	var UP = 'up';
38334	var RIGHT = 'right';
38335	var DOWN = 'down';
38336
38337	var KEY_TO_DIRECTION = {
38338	  ArrowLeft: LEFT,
38339	  Left: LEFT,
38340	  ArrowUp: UP,
38341	  Up: UP,
38342	  ArrowRight: RIGHT,
38343	  Right: RIGHT,
38344	  ArrowDown: DOWN,
38345	  Down: DOWN
38346	};
38347
38348	var DIRECTIONS_DELTA = {
38349	  left: function(speed) {
38350	    return {
38351	      x: -speed,
38352	      y: 0
38353	    };
38354	  },
38355	  up: function(speed) {
38356	    return {
38357	      x: 0,
38358	      y: -speed
38359	    };
38360	  },
38361	  right: function(speed) {
38362	    return {
38363	      x: speed,
38364	      y: 0
38365	    };
38366	  },
38367	  down: function(speed) {
38368	    return {
38369	      x: 0,
38370	      y: speed
38371	    };
38372	  }
38373	};
38374
38375
38376	/**
38377	 * Enables to move selection with keyboard arrows.
38378	 * Use with Shift for modified speed (default=1, with Shift=10).
38379	 * Pressed Cmd/Ctrl turns the feature off.
38380	 *
38381	 * @param {Object} config
38382	 * @param {number} [config.moveSpeed=1]
38383	 * @param {number} [config.moveSpeedAccelerated=10]
38384	 * @param {Keyboard} keyboard
38385	 * @param {Modeling} modeling
38386	 * @param {Selection} selection
38387	 */
38388	function KeyboardMoveSelection(
38389	    config,
38390	    keyboard,
38391	    modeling,
38392	    rules,
38393	    selection
38394	) {
38395
38396	  var self = this;
38397
38398	  this._config = assign({}, DEFAULT_CONFIG, config || {});
38399
38400	  keyboard.addListener(HIGHER_PRIORITY$3, function(event) {
38401
38402	    var keyEvent = event.keyEvent;
38403
38404	    var direction = KEY_TO_DIRECTION[keyEvent.key];
38405
38406	    if (!direction) {
38407	      return;
38408	    }
38409
38410	    if (keyboard.isCmd(keyEvent)) {
38411	      return;
38412	    }
38413
38414	    var accelerated = keyboard.isShift(keyEvent);
38415
38416	    self.moveSelection(direction, accelerated);
38417
38418	    return true;
38419	  });
38420
38421
38422	  /**
38423	   * Move selected elements in the given direction,
38424	   * optionally specifying accelerated movement.
38425	   *
38426	   * @param {string} direction
38427	   * @param {boolean} [accelerated=false]
38428	   */
38429	  this.moveSelection = function(direction, accelerated) {
38430
38431	    var selectedElements = selection.get();
38432
38433	    if (!selectedElements.length) {
38434	      return;
38435	    }
38436
38437	    var speed = this._config[
38438	      accelerated ?
38439	        'moveSpeedAccelerated' :
38440	        'moveSpeed'
38441	    ];
38442
38443	    var delta = DIRECTIONS_DELTA[direction](speed);
38444
38445	    var canMove = rules.allowed('elements.move', {
38446	      shapes: selectedElements
38447	    });
38448
38449	    if (canMove) {
38450	      modeling.moveElements(selectedElements, delta);
38451	    }
38452	  };
38453
38454	}
38455
38456	KeyboardMoveSelection.$inject = [
38457	  'config.keyboardMoveSelection',
38458	  'keyboard',
38459	  'modeling',
38460	  'rules',
38461	  'selection'
38462	];
38463
38464	var KeyboardMoveSelectionModule = {
38465	  __depends__: [
38466	    KeyboardModule$1,
38467	    SelectionModule
38468	  ],
38469	  __init__: [
38470	    'keyboardMoveSelection'
38471	  ],
38472	  keyboardMoveSelection: [ 'type', KeyboardMoveSelection ]
38473	};
38474
38475	/**
38476	 * Adds change support to the diagram, including
38477	 *
38478	 * <ul>
38479	 *   <li>redrawing shapes and connections on change</li>
38480	 * </ul>
38481	 *
38482	 * @param {EventBus} eventBus
38483	 * @param {Canvas} canvas
38484	 * @param {ElementRegistry} elementRegistry
38485	 * @param {GraphicsFactory} graphicsFactory
38486	 */
38487	function ChangeSupport(
38488	    eventBus, canvas, elementRegistry,
38489	    graphicsFactory) {
38490
38491
38492	  // redraw shapes / connections on change
38493
38494	  eventBus.on('element.changed', function(event) {
38495
38496	    var element = event.element;
38497
38498	    // element might have been deleted and replaced by new element with same ID
38499	    // thus check for parent of element except for root element
38500	    if (element.parent || element === canvas.getRootElement()) {
38501	      event.gfx = elementRegistry.getGraphics(element);
38502	    }
38503
38504	    // shape + gfx may have been deleted
38505	    if (!event.gfx) {
38506	      return;
38507	    }
38508
38509	    eventBus.fire(getType(element) + '.changed', event);
38510	  });
38511
38512	  eventBus.on('elements.changed', function(event) {
38513
38514	    var elements = event.elements;
38515
38516	    elements.forEach(function(e) {
38517	      eventBus.fire('element.changed', { element: e });
38518	    });
38519
38520	    graphicsFactory.updateContainments(elements);
38521	  });
38522
38523	  eventBus.on('shape.changed', function(event) {
38524	    graphicsFactory.update('shape', event.element, event.gfx);
38525	  });
38526
38527	  eventBus.on('connection.changed', function(event) {
38528	    graphicsFactory.update('connection', event.element, event.gfx);
38529	  });
38530	}
38531
38532	ChangeSupport.$inject = [
38533	  'eventBus',
38534	  'canvas',
38535	  'elementRegistry',
38536	  'graphicsFactory'
38537	];
38538
38539	var ChangeSupportModule = {
38540	  __init__: [ 'changeSupport'],
38541	  changeSupport: [ 'type', ChangeSupport ]
38542	};
38543
38544	var DEFAULT_MIN_WIDTH = 10;
38545
38546
38547	/**
38548	 * A component that provides resizing of shapes on the canvas.
38549	 *
38550	 * The following components are part of shape resize:
38551	 *
38552	 *  * adding resize handles,
38553	 *  * creating a visual during resize
38554	 *  * checking resize rules
38555	 *  * committing a change once finished
38556	 *
38557	 *
38558	 * ## Customizing
38559	 *
38560	 * It's possible to customize the resizing behaviour by intercepting 'resize.start'
38561	 * and providing the following parameters through the 'context':
38562	 *
38563	 *   * minDimensions ({ width, height }): minimum shape dimensions
38564	 *
38565	 *   * childrenBoxPadding ({ left, top, bottom, right } || number):
38566	 *     gap between the minimum bounding box and the container
38567	 *
38568	 * f.ex:
38569	 *
38570	 * ```javascript
38571	 * eventBus.on('resize.start', 1500, function(event) {
38572	 *   var context = event.context,
38573	 *
38574	 *  context.minDimensions = { width: 140, height: 120 };
38575	 *
38576	 *  // Passing general padding
38577	 *  context.childrenBoxPadding = 30;
38578	 *
38579	 *  // Passing padding to a specific side
38580	 *  context.childrenBoxPadding.left = 20;
38581	 * });
38582	 * ```
38583	 */
38584	function Resize(eventBus, rules, modeling, dragging) {
38585
38586	  this._dragging = dragging;
38587	  this._rules = rules;
38588
38589	  var self = this;
38590
38591
38592	  /**
38593	   * Handle resize move by specified delta.
38594	   *
38595	   * @param {Object} context
38596	   * @param {Point} delta
38597	   */
38598	  function handleMove(context, delta) {
38599
38600	    var shape = context.shape,
38601	        direction = context.direction,
38602	        resizeConstraints = context.resizeConstraints,
38603	        newBounds;
38604
38605	    context.delta = delta;
38606
38607	    newBounds = resizeBounds$1(shape, direction, delta);
38608
38609	    // ensure constraints during resize
38610	    context.newBounds = ensureConstraints$1(newBounds, resizeConstraints);
38611
38612	    // update + cache executable state
38613	    context.canExecute = self.canResize(context);
38614	  }
38615
38616	  /**
38617	   * Handle resize start.
38618	   *
38619	   * @param  {Object} context
38620	   */
38621	  function handleStart(context) {
38622
38623	    var resizeConstraints = context.resizeConstraints,
38624
38625	        // evaluate minBounds for backwards compatibility
38626	        minBounds = context.minBounds;
38627
38628	    if (resizeConstraints !== undefined) {
38629	      return;
38630	    }
38631
38632	    if (minBounds === undefined) {
38633	      minBounds = self.computeMinResizeBox(context);
38634	    }
38635
38636	    context.resizeConstraints = {
38637	      min: asTRBL(minBounds)
38638	    };
38639	  }
38640
38641	  /**
38642	   * Handle resize end.
38643	   *
38644	   * @param  {Object} context
38645	   */
38646	  function handleEnd(context) {
38647	    var shape = context.shape,
38648	        canExecute = context.canExecute,
38649	        newBounds = context.newBounds;
38650
38651	    if (canExecute) {
38652
38653	      // ensure we have actual pixel values for new bounds
38654	      // (important when zoom level was > 1 during move)
38655	      newBounds = roundBounds(newBounds);
38656
38657	      if (!boundsChanged(shape, newBounds)) {
38658
38659	        // no resize necessary
38660	        return;
38661	      }
38662
38663	      // perform the actual resize
38664	      modeling.resizeShape(shape, newBounds);
38665	    }
38666	  }
38667
38668
38669	  eventBus.on('resize.start', function(event) {
38670	    handleStart(event.context);
38671	  });
38672
38673	  eventBus.on('resize.move', function(event) {
38674	    var delta = {
38675	      x: event.dx,
38676	      y: event.dy
38677	    };
38678
38679	    handleMove(event.context, delta);
38680	  });
38681
38682	  eventBus.on('resize.end', function(event) {
38683	    handleEnd(event.context);
38684	  });
38685
38686	}
38687
38688
38689	Resize.prototype.canResize = function(context) {
38690	  var rules = this._rules;
38691
38692	  var ctx = pick(context, [ 'newBounds', 'shape', 'delta', 'direction' ]);
38693
38694	  return rules.allowed('shape.resize', ctx);
38695	};
38696
38697	/**
38698	 * Activate a resize operation.
38699	 *
38700	 * You may specify additional contextual information and must specify a
38701	 * resize direction during activation of the resize event.
38702	 *
38703	 * @param {MouseEvent} event
38704	 * @param {djs.model.Shape} shape
38705	 * @param {Object|string} contextOrDirection
38706	 */
38707	Resize.prototype.activate = function(event, shape, contextOrDirection) {
38708	  var dragging = this._dragging,
38709	      context,
38710	      direction;
38711
38712	  if (typeof contextOrDirection === 'string') {
38713	    contextOrDirection = {
38714	      direction: contextOrDirection
38715	    };
38716	  }
38717
38718	  context = assign({ shape: shape }, contextOrDirection);
38719
38720	  direction = context.direction;
38721
38722	  if (!direction) {
38723	    throw new Error('must provide a direction (n|w|s|e|nw|se|ne|sw)');
38724	  }
38725
38726	  dragging.init(event, getReferencePoint$1(shape, direction), 'resize', {
38727	    autoActivate: true,
38728	    cursor: getCursor(direction),
38729	    data: {
38730	      shape: shape,
38731	      context: context
38732	    }
38733	  });
38734	};
38735
38736	Resize.prototype.computeMinResizeBox = function(context) {
38737	  var shape = context.shape,
38738	      direction = context.direction,
38739	      minDimensions,
38740	      childrenBounds;
38741
38742	  minDimensions = context.minDimensions || {
38743	    width: DEFAULT_MIN_WIDTH,
38744	    height: DEFAULT_MIN_WIDTH
38745	  };
38746
38747	  // get children bounds
38748	  childrenBounds = computeChildrenBBox(shape, context.childrenBoxPadding);
38749
38750	  // get correct minimum bounds from given resize direction
38751	  // basically ensures that the minBounds is max(childrenBounds, minDimensions)
38752	  return getMinResizeBounds(direction, shape, minDimensions, childrenBounds);
38753	};
38754
38755
38756	Resize.$inject = [
38757	  'eventBus',
38758	  'rules',
38759	  'modeling',
38760	  'dragging'
38761	];
38762
38763	// helpers //////////
38764
38765	function boundsChanged(shape, newBounds) {
38766	  return shape.x !== newBounds.x ||
38767	    shape.y !== newBounds.y ||
38768	    shape.width !== newBounds.width ||
38769	    shape.height !== newBounds.height;
38770	}
38771
38772	function getReferencePoint$1(shape, direction) {
38773	  var mid = getMid(shape),
38774	      trbl = asTRBL(shape);
38775
38776	  var referencePoint = {
38777	    x: mid.x,
38778	    y: mid.y
38779	  };
38780
38781	  if (direction.indexOf('n') !== -1) {
38782	    referencePoint.y = trbl.top;
38783	  } else if (direction.indexOf('s') !== -1) {
38784	    referencePoint.y = trbl.bottom;
38785	  }
38786
38787	  if (direction.indexOf('e') !== -1) {
38788	    referencePoint.x = trbl.right;
38789	  } else if (direction.indexOf('w') !== -1) {
38790	    referencePoint.x = trbl.left;
38791	  }
38792
38793	  return referencePoint;
38794	}
38795
38796	function getCursor(direction) {
38797	  var prefix = 'resize-';
38798
38799	  if (direction === 'n' || direction === 's') {
38800	    return prefix + 'ns';
38801	  } else if (direction === 'e' || direction === 'w') {
38802	    return prefix + 'ew';
38803	  } else if (direction === 'nw' || direction === 'se') {
38804	    return prefix + 'nwse';
38805	  } else {
38806	    return prefix + 'nesw';
38807	  }
38808	}
38809
38810	var MARKER_RESIZING$1 = 'djs-resizing',
38811	    MARKER_RESIZE_NOT_OK = 'resize-not-ok';
38812
38813	var LOW_PRIORITY$d = 500;
38814
38815
38816	/**
38817	 * Provides previews for resizing shapes when resizing.
38818	 *
38819	 * @param {EventBus} eventBus
38820	 * @param {Canvas} canvas
38821	 * @param {PreviewSupport} previewSupport
38822	 */
38823	function ResizePreview(eventBus, canvas, previewSupport) {
38824
38825	  /**
38826	   * Update resizer frame.
38827	   *
38828	   * @param {Object} context
38829	   */
38830	  function updateFrame(context) {
38831
38832	    var shape = context.shape,
38833	        bounds = context.newBounds,
38834	        frame = context.frame;
38835
38836	    if (!frame) {
38837	      frame = context.frame = previewSupport.addFrame(shape, canvas.getActiveLayer());
38838
38839	      canvas.addMarker(shape, MARKER_RESIZING$1);
38840	    }
38841
38842	    if (bounds.width > 5) {
38843	      attr(frame, { x: bounds.x, width: bounds.width });
38844	    }
38845
38846	    if (bounds.height > 5) {
38847	      attr(frame, { y: bounds.y, height: bounds.height });
38848	    }
38849
38850	    if (context.canExecute) {
38851	      classes(frame).remove(MARKER_RESIZE_NOT_OK);
38852	    } else {
38853	      classes(frame).add(MARKER_RESIZE_NOT_OK);
38854	    }
38855	  }
38856
38857	  /**
38858	   * Remove resizer frame.
38859	   *
38860	   * @param {Object} context
38861	   */
38862	  function removeFrame(context) {
38863	    var shape = context.shape,
38864	        frame = context.frame;
38865
38866	    if (frame) {
38867	      remove$1(context.frame);
38868	    }
38869
38870	    canvas.removeMarker(shape, MARKER_RESIZING$1);
38871	  }
38872
38873	  // add and update previews
38874	  eventBus.on('resize.move', LOW_PRIORITY$d, function(event) {
38875	    updateFrame(event.context);
38876	  });
38877
38878	  // remove previews
38879	  eventBus.on('resize.cleanup', function(event) {
38880	    removeFrame(event.context);
38881	  });
38882
38883	}
38884
38885	ResizePreview.$inject = [
38886	  'eventBus',
38887	  'canvas',
38888	  'previewSupport'
38889	];
38890
38891	var HANDLE_OFFSET = -6,
38892	    HANDLE_SIZE = 4,
38893	    HANDLE_HIT_SIZE = 20;
38894
38895	var CLS_RESIZER = 'djs-resizer';
38896
38897	var directions = [ 'n', 'w', 's', 'e', 'nw', 'ne', 'se', 'sw' ];
38898
38899
38900	/**
38901	 * This component is responsible for adding resize handles.
38902	 *
38903	 * @param {EventBus} eventBus
38904	 * @param {Canvas} canvas
38905	 * @param {Selection} selection
38906	 * @param {Resize} resize
38907	 */
38908	function ResizeHandles(eventBus, canvas, selection, resize) {
38909
38910	  this._resize = resize;
38911	  this._canvas = canvas;
38912
38913	  var self = this;
38914
38915	  eventBus.on('selection.changed', function(e) {
38916	    var newSelection = e.newSelection;
38917
38918	    // remove old selection markers
38919	    self.removeResizers();
38920
38921	    // add new selection markers ONLY if single selection
38922	    if (newSelection.length === 1) {
38923	      forEach(newSelection, bind$2(self.addResizer, self));
38924	    }
38925	  });
38926
38927	  eventBus.on('shape.changed', function(e) {
38928	    var shape = e.element;
38929
38930	    if (selection.isSelected(shape)) {
38931	      self.removeResizers();
38932
38933	      self.addResizer(shape);
38934	    }
38935	  });
38936	}
38937
38938
38939	ResizeHandles.prototype.makeDraggable = function(element, gfx, direction) {
38940	  var resize = this._resize;
38941
38942	  function startResize(event) {
38943
38944	    // only trigger on left mouse button
38945	    if (isPrimaryButton(event)) {
38946	      resize.activate(event, element, direction);
38947	    }
38948	  }
38949
38950	  componentEvent.bind(gfx, 'mousedown', startResize);
38951	  componentEvent.bind(gfx, 'touchstart', startResize);
38952	};
38953
38954
38955	ResizeHandles.prototype._createResizer = function(element, x, y, direction) {
38956	  var resizersParent = this._getResizersParent();
38957
38958	  var offset = getHandleOffset(direction);
38959
38960	  var group = create$1('g');
38961
38962	  classes(group).add(CLS_RESIZER);
38963	  classes(group).add(CLS_RESIZER + '-' + element.id);
38964	  classes(group).add(CLS_RESIZER + '-' + direction);
38965
38966	  append(resizersParent, group);
38967
38968	  var visual = create$1('rect');
38969
38970	  attr(visual, {
38971	    x: -HANDLE_SIZE / 2 + offset.x,
38972	    y: -HANDLE_SIZE / 2 + offset.y,
38973	    width: HANDLE_SIZE,
38974	    height: HANDLE_SIZE
38975	  });
38976
38977	  classes(visual).add(CLS_RESIZER + '-visual');
38978
38979	  append(group, visual);
38980
38981	  var hit = create$1('rect');
38982
38983	  attr(hit, {
38984	    x: -HANDLE_HIT_SIZE / 2 + offset.x,
38985	    y: -HANDLE_HIT_SIZE / 2 + offset.y,
38986	    width: HANDLE_HIT_SIZE,
38987	    height: HANDLE_HIT_SIZE
38988	  });
38989
38990	  classes(hit).add(CLS_RESIZER + '-hit');
38991
38992	  append(group, hit);
38993
38994	  transform(group, x, y);
38995
38996	  return group;
38997	};
38998
38999	ResizeHandles.prototype.createResizer = function(element, direction) {
39000	  var point = getReferencePoint$1(element, direction);
39001
39002	  var resizer = this._createResizer(element, point.x, point.y, direction);
39003
39004	  this.makeDraggable(element, resizer, direction);
39005	};
39006
39007	// resize handles implementation ///////////////////////////////
39008
39009	/**
39010	 * Add resizers for a given element.
39011	 *
39012	 * @param {djs.model.Shape} shape
39013	 */
39014	ResizeHandles.prototype.addResizer = function(shape) {
39015	  var self = this;
39016
39017	  var resize = this._resize;
39018
39019	  if (!resize.canResize({ shape: shape })) {
39020	    return;
39021	  }
39022
39023	  forEach(directions, function(direction) {
39024	    self.createResizer(shape, direction);
39025	  });
39026	};
39027
39028	/**
39029	 * Remove all resizers
39030	 */
39031	ResizeHandles.prototype.removeResizers = function() {
39032	  var resizersParent = this._getResizersParent();
39033
39034	  clear(resizersParent);
39035	};
39036
39037	ResizeHandles.prototype._getResizersParent = function() {
39038	  return this._canvas.getLayer('resizers');
39039	};
39040
39041	ResizeHandles.$inject = [
39042	  'eventBus',
39043	  'canvas',
39044	  'selection',
39045	  'resize'
39046	];
39047
39048	// helpers //////////
39049
39050	function getHandleOffset(direction) {
39051	  var offset = {
39052	    x: 0,
39053	    y: 0
39054	  };
39055
39056	  if (direction.indexOf('e') !== -1) {
39057	    offset.x = -HANDLE_OFFSET;
39058	  } else if (direction.indexOf('w') !== -1) {
39059	    offset.x = HANDLE_OFFSET;
39060	  }
39061
39062	  if (direction.indexOf('s') !== -1) {
39063	    offset.y = -HANDLE_OFFSET;
39064	  } else if (direction.indexOf('n') !== -1) {
39065	    offset.y = HANDLE_OFFSET;
39066	  }
39067
39068	  return offset;
39069	}
39070
39071	var ResizeModule = {
39072	  __depends__: [
39073	    RulesModule$1,
39074	    DraggingModule,
39075	    PreviewSupportModule
39076	  ],
39077	  __init__: [
39078	    'resize',
39079	    'resizePreview',
39080	    'resizeHandles'
39081	  ],
39082	  resize: [ 'type', Resize ],
39083	  resizePreview: [ 'type', ResizePreview ],
39084	  resizeHandles: [ 'type', ResizeHandles ]
39085	};
39086
39087	/**
39088	 * Creates a new bpmn:CategoryValue inside a new bpmn:Category
39089	 *
39090	 * @param {ModdleElement} definitions
39091	 * @param {BpmnFactory} bpmnFactory
39092	 *
39093	 * @return {ModdleElement} categoryValue.
39094	 */
39095	function createCategoryValue(definitions, bpmnFactory) {
39096	  var categoryValue = bpmnFactory.create('bpmn:CategoryValue'),
39097	      category = bpmnFactory.create('bpmn:Category', {
39098	        categoryValue: [ categoryValue ]
39099	      });
39100
39101	  // add to correct place
39102	  add(definitions.get('rootElements'), category);
39103	  getBusinessObject(category).$parent = definitions;
39104	  getBusinessObject(categoryValue).$parent = category;
39105
39106	  return categoryValue;
39107
39108	}
39109
39110	function LabelEditingProvider(
39111	    eventBus, bpmnFactory, canvas, directEditing,
39112	    modeling, resizeHandles, textRenderer) {
39113
39114	  this._bpmnFactory = bpmnFactory;
39115	  this._canvas = canvas;
39116	  this._modeling = modeling;
39117	  this._textRenderer = textRenderer;
39118
39119	  directEditing.registerProvider(this);
39120
39121	  // listen to dblclick on non-root elements
39122	  eventBus.on('element.dblclick', function(event) {
39123	    activateDirectEdit(event.element, true);
39124	  });
39125
39126	  // complete on followup canvas operation
39127	  eventBus.on([
39128	    'autoPlace.start',
39129	    'canvas.viewbox.changing',
39130	    'drag.init',
39131	    'element.mousedown',
39132	    'popupMenu.open'
39133	  ], function(event) {
39134
39135	    if (directEditing.isActive()) {
39136	      directEditing.complete();
39137	    }
39138	  });
39139
39140	  // cancel on command stack changes
39141	  eventBus.on([ 'commandStack.changed' ], function(e) {
39142	    if (directEditing.isActive()) {
39143	      directEditing.cancel();
39144	    }
39145	  });
39146
39147
39148	  eventBus.on('directEditing.activate', function(event) {
39149	    resizeHandles.removeResizers();
39150	  });
39151
39152	  eventBus.on('create.end', 500, function(event) {
39153
39154	    var context = event.context,
39155	        element = context.shape,
39156	        canExecute = event.context.canExecute,
39157	        isTouch = event.isTouch;
39158
39159	    // TODO(nikku): we need to find a way to support the
39160	    // direct editing on mobile devices; right now this will
39161	    // break for desworkflowediting on mobile devices
39162	    // as it breaks the user interaction workflow
39163
39164	    // TODO(nre): we should temporarily focus the edited element
39165	    // here and release the focused viewport after the direct edit
39166	    // operation is finished
39167	    if (isTouch) {
39168	      return;
39169	    }
39170
39171	    if (!canExecute) {
39172	      return;
39173	    }
39174
39175	    if (context.hints && context.hints.createElementsBehavior === false) {
39176	      return;
39177	    }
39178
39179	    activateDirectEdit(element);
39180	  });
39181
39182	  eventBus.on('autoPlace.end', 500, function(event) {
39183	    activateDirectEdit(event.shape);
39184	  });
39185
39186
39187	  function activateDirectEdit(element, force) {
39188	    if (force ||
39189	        isAny(element, [ 'bpmn:Task', 'bpmn:TextAnnotation', 'bpmn:Group' ]) ||
39190	        isCollapsedSubProcess(element)) {
39191
39192	      directEditing.activate(element);
39193	    }
39194	  }
39195
39196	}
39197
39198	LabelEditingProvider.$inject = [
39199	  'eventBus',
39200	  'bpmnFactory',
39201	  'canvas',
39202	  'directEditing',
39203	  'modeling',
39204	  'resizeHandles',
39205	  'textRenderer'
39206	];
39207
39208
39209	/**
39210	 * Activate direct editing for activities and text annotations.
39211	 *
39212	 * @param  {djs.model.Base} element
39213	 *
39214	 * @return {Object} an object with properties bounds (position and size), text and options
39215	 */
39216	LabelEditingProvider.prototype.activate = function(element) {
39217
39218	  // text
39219	  var text = getLabel(element);
39220
39221	  if (text === undefined) {
39222	    return;
39223	  }
39224
39225	  var context = {
39226	    text: text
39227	  };
39228
39229	  // bounds
39230	  var bounds = this.getEditingBBox(element);
39231
39232	  assign(context, bounds);
39233
39234	  var options = {};
39235
39236	  // tasks
39237	  if (
39238	    isAny(element, [
39239	      'bpmn:Task',
39240	      'bpmn:Participant',
39241	      'bpmn:Lane',
39242	      'bpmn:CallActivity'
39243	    ]) ||
39244	    isCollapsedSubProcess(element)
39245	  ) {
39246	    assign(options, {
39247	      centerVertically: true
39248	    });
39249	  }
39250
39251	  // external labels
39252	  if (isLabelExternal(element)) {
39253	    assign(options, {
39254	      autoResize: true
39255	    });
39256	  }
39257
39258	  // text annotations
39259	  if (is$1(element, 'bpmn:TextAnnotation')) {
39260	    assign(options, {
39261	      resizable: true,
39262	      autoResize: true
39263	    });
39264	  }
39265
39266	  assign(context, {
39267	    options: options
39268	  });
39269
39270	  return context;
39271	};
39272
39273
39274	/**
39275	 * Get the editing bounding box based on the element's size and position
39276	 *
39277	 * @param  {djs.model.Base} element
39278	 *
39279	 * @return {Object} an object containing information about position
39280	 *                  and size (fixed or minimum and/or maximum)
39281	 */
39282	LabelEditingProvider.prototype.getEditingBBox = function(element) {
39283	  var canvas = this._canvas;
39284
39285	  var target = element.label || element;
39286
39287	  var bbox = canvas.getAbsoluteBBox(target);
39288
39289	  var mid = {
39290	    x: bbox.x + bbox.width / 2,
39291	    y: bbox.y + bbox.height / 2
39292	  };
39293
39294	  // default position
39295	  var bounds = { x: bbox.x, y: bbox.y };
39296
39297	  var zoom = canvas.zoom();
39298
39299	  var defaultStyle = this._textRenderer.getDefaultStyle(),
39300	      externalStyle = this._textRenderer.getExternalStyle();
39301
39302	  // take zoom into account
39303	  var externalFontSize = externalStyle.fontSize * zoom,
39304	      externalLineHeight = externalStyle.lineHeight,
39305	      defaultFontSize = defaultStyle.fontSize * zoom,
39306	      defaultLineHeight = defaultStyle.lineHeight;
39307
39308	  var style = {
39309	    fontFamily: this._textRenderer.getDefaultStyle().fontFamily,
39310	    fontWeight: this._textRenderer.getDefaultStyle().fontWeight
39311	  };
39312
39313	  // adjust for expanded pools AND lanes
39314	  if (is$1(element, 'bpmn:Lane') || isExpandedPool(element)) {
39315
39316	    assign(bounds, {
39317	      width: bbox.height,
39318	      height: 30 * zoom,
39319	      x: bbox.x - bbox.height / 2 + (15 * zoom),
39320	      y: mid.y - (30 * zoom) / 2
39321	    });
39322
39323	    assign(style, {
39324	      fontSize: defaultFontSize + 'px',
39325	      lineHeight: defaultLineHeight,
39326	      paddingTop: (7 * zoom) + 'px',
39327	      paddingBottom: (7 * zoom) + 'px',
39328	      paddingLeft: (5 * zoom) + 'px',
39329	      paddingRight: (5 * zoom) + 'px',
39330	      transform: 'rotate(-90deg)'
39331	    });
39332	  }
39333
39334
39335	  // internal labels for tasks and collapsed call activities,
39336	  // sub processes and participants
39337	  if (isAny(element, [ 'bpmn:Task', 'bpmn:CallActivity']) ||
39338	      isCollapsedPool(element) ||
39339	      isCollapsedSubProcess(element)) {
39340
39341	    assign(bounds, {
39342	      width: bbox.width,
39343	      height: bbox.height
39344	    });
39345
39346	    assign(style, {
39347	      fontSize: defaultFontSize + 'px',
39348	      lineHeight: defaultLineHeight,
39349	      paddingTop: (7 * zoom) + 'px',
39350	      paddingBottom: (7 * zoom) + 'px',
39351	      paddingLeft: (5 * zoom) + 'px',
39352	      paddingRight: (5 * zoom) + 'px'
39353	    });
39354	  }
39355
39356
39357	  // internal labels for expanded sub processes
39358	  if (isExpandedSubProcess$1(element)) {
39359	    assign(bounds, {
39360	      width: bbox.width,
39361	      x: bbox.x
39362	    });
39363
39364	    assign(style, {
39365	      fontSize: defaultFontSize + 'px',
39366	      lineHeight: defaultLineHeight,
39367	      paddingTop: (7 * zoom) + 'px',
39368	      paddingBottom: (7 * zoom) + 'px',
39369	      paddingLeft: (5 * zoom) + 'px',
39370	      paddingRight: (5 * zoom) + 'px'
39371	    });
39372	  }
39373
39374	  var width = 90 * zoom,
39375	      paddingTop = 7 * zoom,
39376	      paddingBottom = 4 * zoom;
39377
39378	  // external labels for events, data elements, gateways, groups and connections
39379	  if (target.labelTarget) {
39380	    assign(bounds, {
39381	      width: width,
39382	      height: bbox.height + paddingTop + paddingBottom,
39383	      x: mid.x - width / 2,
39384	      y: bbox.y - paddingTop
39385	    });
39386
39387	    assign(style, {
39388	      fontSize: externalFontSize + 'px',
39389	      lineHeight: externalLineHeight,
39390	      paddingTop: paddingTop + 'px',
39391	      paddingBottom: paddingBottom + 'px'
39392	    });
39393	  }
39394
39395	  // external label not yet created
39396	  if (isLabelExternal(target)
39397	      && !hasExternalLabel(target)
39398	      && !isLabel$6(target)) {
39399
39400	    var externalLabelMid = getExternalLabelMid(element);
39401
39402	    var absoluteBBox = canvas.getAbsoluteBBox({
39403	      x: externalLabelMid.x,
39404	      y: externalLabelMid.y,
39405	      width: 0,
39406	      height: 0
39407	    });
39408
39409	    var height = externalFontSize + paddingTop + paddingBottom;
39410
39411	    assign(bounds, {
39412	      width: width,
39413	      height: height,
39414	      x: absoluteBBox.x - width / 2,
39415	      y: absoluteBBox.y - height / 2
39416	    });
39417
39418	    assign(style, {
39419	      fontSize: externalFontSize + 'px',
39420	      lineHeight: externalLineHeight,
39421	      paddingTop: paddingTop + 'px',
39422	      paddingBottom: paddingBottom + 'px'
39423	    });
39424	  }
39425
39426	  // text annotations
39427	  if (is$1(element, 'bpmn:TextAnnotation')) {
39428	    assign(bounds, {
39429	      width: bbox.width,
39430	      height: bbox.height,
39431	      minWidth: 30 * zoom,
39432	      minHeight: 10 * zoom
39433	    });
39434
39435	    assign(style, {
39436	      textAlign: 'left',
39437	      paddingTop: (5 * zoom) + 'px',
39438	      paddingBottom: (7 * zoom) + 'px',
39439	      paddingLeft: (7 * zoom) + 'px',
39440	      paddingRight: (5 * zoom) + 'px',
39441	      fontSize: defaultFontSize + 'px',
39442	      lineHeight: defaultLineHeight
39443	    });
39444	  }
39445
39446	  return { bounds: bounds, style: style };
39447	};
39448
39449
39450	LabelEditingProvider.prototype.update = function(
39451	    element, newLabel,
39452	    activeContextText, bounds) {
39453
39454	  var newBounds,
39455	      bbox;
39456
39457	  if (is$1(element, 'bpmn:TextAnnotation')) {
39458
39459	    bbox = this._canvas.getAbsoluteBBox(element);
39460
39461	    newBounds = {
39462	      x: element.x,
39463	      y: element.y,
39464	      width: element.width / bbox.width * bounds.width,
39465	      height: element.height / bbox.height * bounds.height
39466	    };
39467	  }
39468
39469	  if (is$1(element, 'bpmn:Group')) {
39470
39471	    var businessObject = getBusinessObject(element);
39472
39473	    // initialize categoryValue if not existing
39474	    if (!businessObject.categoryValueRef) {
39475
39476	      var rootElement = this._canvas.getRootElement(),
39477	          definitions = getBusinessObject(rootElement).$parent;
39478
39479	      var categoryValue = createCategoryValue(definitions, this._bpmnFactory);
39480
39481	      getBusinessObject(element).categoryValueRef = categoryValue;
39482	    }
39483
39484	  }
39485
39486	  if (isEmptyText$1(newLabel)) {
39487	    newLabel = null;
39488	  }
39489
39490	  this._modeling.updateLabel(element, newLabel, newBounds);
39491	};
39492
39493
39494
39495	// helpers //////////////////////
39496
39497	function isCollapsedSubProcess(element) {
39498	  return is$1(element, 'bpmn:SubProcess') && !isExpanded(element);
39499	}
39500
39501	function isExpandedSubProcess$1(element) {
39502	  return is$1(element, 'bpmn:SubProcess') && isExpanded(element);
39503	}
39504
39505	function isCollapsedPool(element) {
39506	  return is$1(element, 'bpmn:Participant') && !isExpanded(element);
39507	}
39508
39509	function isExpandedPool(element) {
39510	  return is$1(element, 'bpmn:Participant') && isExpanded(element);
39511	}
39512
39513	function isEmptyText$1(label) {
39514	  return !label || !label.trim();
39515	}
39516
39517	var MARKER_HIDDEN = 'djs-element-hidden',
39518	    MARKER_LABEL_HIDDEN = 'djs-label-hidden';
39519
39520
39521	function LabelEditingPreview(
39522	    eventBus, canvas, elementRegistry,
39523	    pathMap) {
39524
39525	  var self = this;
39526
39527	  var defaultLayer = canvas.getDefaultLayer();
39528
39529	  var element, absoluteElementBBox, gfx;
39530
39531	  eventBus.on('directEditing.activate', function(context) {
39532	    var activeProvider = context.active;
39533
39534	    element = activeProvider.element.label || activeProvider.element;
39535
39536	    // text annotation
39537	    if (is$1(element, 'bpmn:TextAnnotation')) {
39538	      absoluteElementBBox = canvas.getAbsoluteBBox(element);
39539
39540	      gfx = create$1('g');
39541
39542	      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
39543	        xScaleFactor: 1,
39544	        yScaleFactor: 1,
39545	        containerWidth: element.width,
39546	        containerHeight: element.height,
39547	        position: {
39548	          mx: 0.0,
39549	          my: 0.0
39550	        }
39551	      });
39552
39553	      var path = self.path = create$1('path');
39554
39555	      attr(path, {
39556	        d: textPathData,
39557	        strokeWidth: 2,
39558	        stroke: getStrokeColor(element)
39559	      });
39560
39561	      append(gfx, path);
39562
39563	      append(defaultLayer, gfx);
39564
39565	      translate$2(gfx, element.x, element.y);
39566	    }
39567
39568	    if (is$1(element, 'bpmn:TextAnnotation') ||
39569	        element.labelTarget) {
39570	      canvas.addMarker(element, MARKER_HIDDEN);
39571	    } else if (is$1(element, 'bpmn:Task') ||
39572	               is$1(element, 'bpmn:CallActivity') ||
39573	               is$1(element, 'bpmn:SubProcess') ||
39574	               is$1(element, 'bpmn:Participant')) {
39575	      canvas.addMarker(element, MARKER_LABEL_HIDDEN);
39576	    }
39577	  });
39578
39579	  eventBus.on('directEditing.resize', function(context) {
39580
39581	    // text annotation
39582	    if (is$1(element, 'bpmn:TextAnnotation')) {
39583	      var height = context.height,
39584	          dy = context.dy;
39585
39586	      var newElementHeight = Math.max(element.height / absoluteElementBBox.height * (height + dy), 0);
39587
39588	      var textPathData = pathMap.getScaledPath('TEXT_ANNOTATION', {
39589	        xScaleFactor: 1,
39590	        yScaleFactor: 1,
39591	        containerWidth: element.width,
39592	        containerHeight: newElementHeight,
39593	        position: {
39594	          mx: 0.0,
39595	          my: 0.0
39596	        }
39597	      });
39598
39599	      attr(self.path, {
39600	        d: textPathData
39601	      });
39602	    }
39603	  });
39604
39605	  eventBus.on([ 'directEditing.complete', 'directEditing.cancel' ], function(context) {
39606	    var activeProvider = context.active;
39607
39608	    if (activeProvider) {
39609	      canvas.removeMarker(activeProvider.element.label || activeProvider.element, MARKER_HIDDEN);
39610	      canvas.removeMarker(element, MARKER_LABEL_HIDDEN);
39611	    }
39612
39613	    element = undefined;
39614	    absoluteElementBBox = undefined;
39615
39616	    if (gfx) {
39617	      remove$1(gfx);
39618
39619	      gfx = undefined;
39620	    }
39621	  });
39622	}
39623
39624	LabelEditingPreview.$inject = [
39625	  'eventBus',
39626	  'canvas',
39627	  'elementRegistry',
39628	  'pathMap'
39629	];
39630
39631
39632	// helpers ///////////////////
39633
39634	function getStrokeColor(element, defaultColor) {
39635	  var bo = getBusinessObject(element);
39636
39637	  return bo.di.get('stroke') || defaultColor || 'black';
39638	}
39639
39640	var LabelEditingModule = {
39641	  __depends__: [
39642	    ChangeSupportModule,
39643	    ResizeModule,
39644	    DirectEditingModule
39645	  ],
39646	  __init__: [
39647	    'labelEditingProvider',
39648	    'labelEditingPreview'
39649	  ],
39650	  labelEditingProvider: [ 'type', LabelEditingProvider ],
39651	  labelEditingPreview: [ 'type', LabelEditingPreview ]
39652	};
39653
39654	var ALIGNMENTS = [
39655	  'top',
39656	  'bottom',
39657	  'left',
39658	  'right'
39659	];
39660
39661	var ELEMENT_LABEL_DISTANCE = 10;
39662
39663	/**
39664	 * A component that makes sure that external labels are added
39665	 * together with respective elements and properly updated (DI wise)
39666	 * during move.
39667	 *
39668	 * @param {EventBus} eventBus
39669	 * @param {Modeling} modeling
39670	 */
39671	function AdaptiveLabelPositioningBehavior(eventBus, modeling) {
39672
39673	  CommandInterceptor.call(this, eventBus);
39674
39675	  this.postExecuted([
39676	    'connection.create',
39677	    'connection.layout',
39678	    'connection.updateWaypoints'
39679	  ], function(event) {
39680	    var context = event.context,
39681	        connection = context.connection,
39682	        source = connection.source,
39683	        target = connection.target,
39684	        hints = context.hints || {};
39685
39686	    if (hints.createElementsBehavior !== false) {
39687	      checkLabelAdjustment(source);
39688	      checkLabelAdjustment(target);
39689	    }
39690	  });
39691
39692
39693	  this.postExecuted([
39694	    'label.create'
39695	  ], function(event) {
39696	    var context = event.context,
39697	        shape = context.shape,
39698	        hints = context.hints || {};
39699
39700	    if (hints.createElementsBehavior !== false) {
39701	      checkLabelAdjustment(shape.labelTarget);
39702	    }
39703	  });
39704
39705
39706	  this.postExecuted([
39707	    'elements.create'
39708	  ], function(event) {
39709	    var context = event.context,
39710	        elements = context.elements,
39711	        hints = context.hints || {};
39712
39713	    if (hints.createElementsBehavior !== false) {
39714	      elements.forEach(function(element) {
39715	        checkLabelAdjustment(element);
39716	      });
39717	    }
39718	  });
39719
39720	  function checkLabelAdjustment(element) {
39721
39722	    // skip non-existing labels
39723	    if (!hasExternalLabel(element)) {
39724	      return;
39725	    }
39726
39727	    var optimalPosition = getOptimalPosition(element);
39728
39729	    // no optimal position found
39730	    if (!optimalPosition) {
39731	      return;
39732	    }
39733
39734	    adjustLabelPosition(element, optimalPosition);
39735	  }
39736
39737	  function adjustLabelPosition(element, orientation) {
39738
39739	    var elementMid = getMid(element),
39740	        label = element.label,
39741	        labelMid = getMid(label);
39742
39743	    // ignore labels that are being created
39744	    if (!label.parent) {
39745	      return;
39746	    }
39747
39748	    var elementTrbl = asTRBL(element);
39749
39750	    var newLabelMid;
39751
39752	    switch (orientation) {
39753	    case 'top':
39754	      newLabelMid = {
39755	        x: elementMid.x,
39756	        y: elementTrbl.top - ELEMENT_LABEL_DISTANCE - label.height / 2
39757	      };
39758
39759	      break;
39760
39761	    case 'left':
39762
39763	      newLabelMid = {
39764	        x: elementTrbl.left - ELEMENT_LABEL_DISTANCE - label.width / 2,
39765	        y: elementMid.y
39766	      };
39767
39768	      break;
39769
39770	    case 'bottom':
39771
39772	      newLabelMid = {
39773	        x: elementMid.x,
39774	        y: elementTrbl.bottom + ELEMENT_LABEL_DISTANCE + label.height / 2
39775	      };
39776
39777	      break;
39778
39779	    case 'right':
39780
39781	      newLabelMid = {
39782	        x: elementTrbl.right + ELEMENT_LABEL_DISTANCE + label.width / 2,
39783	        y: elementMid.y
39784	      };
39785
39786	      break;
39787	    }
39788
39789	    var delta$1 = delta(newLabelMid, labelMid);
39790
39791	    modeling.moveShape(label, delta$1);
39792	  }
39793
39794	}
39795
39796	inherits$1(AdaptiveLabelPositioningBehavior, CommandInterceptor);
39797
39798	AdaptiveLabelPositioningBehavior.$inject = [
39799	  'eventBus',
39800	  'modeling'
39801	];
39802
39803
39804	// helpers //////////////////////
39805
39806	/**
39807	 * Return alignments which are taken by a boundary's host element
39808	 *
39809	 * @param {Shape} element
39810	 *
39811	 * @return {Array<string>}
39812	 */
39813	function getTakenHostAlignments(element) {
39814
39815	  var hostElement = element.host,
39816	      elementMid = getMid(element),
39817	      hostOrientation = getOrientation(elementMid, hostElement);
39818
39819	  var freeAlignments;
39820
39821	  // check whether there is a multi-orientation, e.g. 'top-left'
39822	  if (hostOrientation.indexOf('-') >= 0) {
39823	    freeAlignments = hostOrientation.split('-');
39824	  } else {
39825	    freeAlignments = [ hostOrientation ];
39826	  }
39827
39828	  var takenAlignments = ALIGNMENTS.filter(function(alignment) {
39829
39830	    return freeAlignments.indexOf(alignment) === -1;
39831	  });
39832
39833	  return takenAlignments;
39834
39835	}
39836
39837	/**
39838	 * Return alignments which are taken by related connections
39839	 *
39840	 * @param {Shape} element
39841	 *
39842	 * @return {Array<string>}
39843	 */
39844	function getTakenConnectionAlignments(element) {
39845
39846	  var elementMid = getMid(element);
39847
39848	  var takenAlignments = [].concat(
39849	    element.incoming.map(function(c) {
39850	      return c.waypoints[c.waypoints.length - 2 ];
39851	    }),
39852	    element.outgoing.map(function(c) {
39853	      return c.waypoints[1];
39854	    })
39855	  ).map(function(point) {
39856	    return getApproximateOrientation(elementMid, point);
39857	  });
39858
39859	  return takenAlignments;
39860	}
39861
39862	/**
39863	 * Return the optimal label position around an element
39864	 * or _undefined_, if none was found.
39865	 *
39866	 * @param  {Shape} element
39867	 *
39868	 * @return {string} positioning identifier
39869	 */
39870	function getOptimalPosition(element) {
39871
39872	  var labelMid = getMid(element.label);
39873
39874	  var elementMid = getMid(element);
39875
39876	  var labelOrientation = getApproximateOrientation(elementMid, labelMid);
39877
39878	  if (!isAligned(labelOrientation)) {
39879	    return;
39880	  }
39881
39882	  var takenAlignments = getTakenConnectionAlignments(element);
39883
39884	  if (element.host) {
39885	    var takenHostAlignments = getTakenHostAlignments(element);
39886
39887	    takenAlignments = takenAlignments.concat(takenHostAlignments);
39888	  }
39889
39890	  var freeAlignments = ALIGNMENTS.filter(function(alignment) {
39891
39892	    return takenAlignments.indexOf(alignment) === -1;
39893	  });
39894
39895	  // NOTHING TO DO; label already aligned a.O.K.
39896	  if (freeAlignments.indexOf(labelOrientation) !== -1) {
39897	    return;
39898	  }
39899
39900	  return freeAlignments[0];
39901	}
39902
39903	function getApproximateOrientation(p0, p1) {
39904	  return getOrientation(p1, p0, 5);
39905	}
39906
39907	function isAligned(orientation) {
39908	  return ALIGNMENTS.indexOf(orientation) !== -1;
39909	}
39910
39911	function AppendBehavior(eventBus, elementFactory, bpmnRules) {
39912
39913	  CommandInterceptor.call(this, eventBus);
39914
39915	  // assign correct shape position unless already set
39916
39917	  this.preExecute('shape.append', function(context) {
39918
39919	    var source = context.source,
39920	        shape = context.shape;
39921
39922	    if (!context.position) {
39923
39924	      if (is$1(shape, 'bpmn:TextAnnotation')) {
39925	        context.position = {
39926	          x: source.x + source.width / 2 + 75,
39927	          y: source.y - (50) - shape.height / 2
39928	        };
39929	      } else {
39930	        context.position = {
39931	          x: source.x + source.width + 80 + shape.width / 2,
39932	          y: source.y + source.height / 2
39933	        };
39934	      }
39935	    }
39936	  }, true);
39937	}
39938
39939	inherits$1(AppendBehavior, CommandInterceptor);
39940
39941	AppendBehavior.$inject = [
39942	  'eventBus',
39943	  'elementFactory',
39944	  'bpmnRules'
39945	];
39946
39947	function AssociationBehavior(injector, modeling) {
39948	  injector.invoke(CommandInterceptor, this);
39949
39950	  this.postExecute('shape.move', function(context) {
39951	    var newParent = context.newParent,
39952	        shape = context.shape;
39953
39954	    var associations = filter(shape.incoming.concat(shape.outgoing), function(connection) {
39955	      return is$1(connection, 'bpmn:Association');
39956	    });
39957
39958	    forEach(associations, function(association) {
39959	      modeling.moveConnection(association, { x: 0, y: 0 }, newParent);
39960	    });
39961	  }, true);
39962	}
39963
39964	inherits$1(AssociationBehavior, CommandInterceptor);
39965
39966	AssociationBehavior.$inject = [
39967	  'injector',
39968	  'modeling'
39969	];
39970
39971	var LOW_PRIORITY$c = 500;
39972
39973
39974	/**
39975	 * Replace intermediate event with boundary event when creating or moving results in attached event.
39976	 */
39977	function AttachEventBehavior(bpmnReplace, injector) {
39978	  injector.invoke(CommandInterceptor, this);
39979
39980	  this._bpmnReplace = bpmnReplace;
39981
39982	  var self = this;
39983
39984	  this.postExecuted('elements.create', LOW_PRIORITY$c, function(context) {
39985	    var elements = context.elements;
39986
39987	    elements = elements.filter(function(shape) {
39988	      var host = shape.host;
39989
39990	      return shouldReplace$1(shape, host);
39991	    });
39992
39993	    if (elements.length !== 1) {
39994	      return;
39995	    }
39996
39997	    elements.map(function(element) {
39998	      return elements.indexOf(element);
39999	    }).forEach(function(index) {
40000	      var host = elements[ index ];
40001
40002	      context.elements[ index ] = self.replaceShape(elements[ index ], host);
40003	    });
40004	  }, true);
40005
40006
40007	  this.preExecute('elements.move', LOW_PRIORITY$c, function(context) {
40008	    var shapes = context.shapes,
40009	        host = context.newHost;
40010
40011	    if (shapes.length !== 1) {
40012	      return;
40013	    }
40014
40015	    var shape = shapes[0];
40016
40017	    if (shouldReplace$1(shape, host)) {
40018	      context.shapes = [ self.replaceShape(shape, host) ];
40019	    }
40020	  }, true);
40021	}
40022
40023	AttachEventBehavior.$inject = [
40024	  'bpmnReplace',
40025	  'injector'
40026	];
40027
40028	inherits$1(AttachEventBehavior, CommandInterceptor);
40029
40030	AttachEventBehavior.prototype.replaceShape = function(shape, host) {
40031	  var eventDefinition = getEventDefinition$1(shape);
40032
40033	  var boundaryEvent = {
40034	    type: 'bpmn:BoundaryEvent',
40035	    host: host
40036	  };
40037
40038	  if (eventDefinition) {
40039	    boundaryEvent.eventDefinitionType = eventDefinition.$type;
40040	  }
40041
40042	  return this._bpmnReplace.replaceElement(shape, boundaryEvent, { layoutConnection: false });
40043	};
40044
40045
40046	// helpers //////////
40047
40048	function getEventDefinition$1(element) {
40049	  var businessObject = getBusinessObject(element),
40050	      eventDefinitions = businessObject.eventDefinitions;
40051
40052	  return eventDefinitions && eventDefinitions[0];
40053	}
40054
40055	function shouldReplace$1(shape, host) {
40056	  return !isLabel$6(shape) &&
40057	    isAny(shape, [ 'bpmn:IntermediateThrowEvent', 'bpmn:IntermediateCatchEvent' ]) && !!host;
40058	}
40059
40060	var HIGH_PRIORITY$c = 2000;
40061
40062
40063	/**
40064	 * BPMN specific boundary event behavior
40065	 */
40066	function BoundaryEventBehavior(eventBus, moddle, modeling) {
40067
40068	  CommandInterceptor.call(this, eventBus);
40069
40070	  function getBoundaryEvents(element) {
40071	    return filter(element.attachers, function(attacher) {
40072	      return is$1(attacher, 'bpmn:BoundaryEvent');
40073	    });
40074	  }
40075
40076	  // remove after connecting to event-based gateway
40077	  this.postExecute('connection.create', function(event) {
40078	    var source = event.context.source,
40079	        target = event.context.target,
40080	        boundaryEvents = getBoundaryEvents(target);
40081
40082	    if (
40083	      is$1(source, 'bpmn:EventBasedGateway') &&
40084	      is$1(target, 'bpmn:ReceiveTask') &&
40085	      boundaryEvents.length > 0
40086	    ) {
40087	      modeling.removeElements(boundaryEvents);
40088	    }
40089
40090	  });
40091
40092	  // remove after replacing connected gateway with event-based gateway
40093	  this.postExecute('connection.reconnect', function(event) {
40094	    var oldSource = event.context.oldSource,
40095	        newSource = event.context.newSource;
40096
40097	    if (is$1(oldSource, 'bpmn:Gateway') &&
40098	        is$1(newSource, 'bpmn:EventBasedGateway')) {
40099	      forEach(newSource.outgoing, function(connection) {
40100	        var target = connection.target,
40101	            attachedboundaryEvents = getBoundaryEvents(target);
40102
40103	        if (is$1(target, 'bpmn:ReceiveTask') &&
40104	            attachedboundaryEvents.length > 0) {
40105	          modeling.removeElements(attachedboundaryEvents);
40106	        }
40107	      });
40108	    }
40109	  });
40110
40111	  // copy reference to root element on replace
40112	  eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY$c, function(context) {
40113	    var parent = context.parent,
40114	        property = context.property,
40115	        propertyName = context.propertyName;
40116
40117	    var propertyDescriptor = moddle.getPropertyDescriptor(parent, propertyName);
40118
40119	    if (propertyDescriptor && propertyDescriptor.isReference && is$1(property, 'bpmn:RootElement')) {
40120	      parent.set(propertyName, property);
40121	    }
40122	  });
40123	}
40124
40125	BoundaryEventBehavior.$inject = [
40126	  'eventBus',
40127	  'moddle',
40128	  'modeling'
40129	];
40130
40131	inherits$1(BoundaryEventBehavior, CommandInterceptor);
40132
40133	var LOW_PRIORITY$b = 500;
40134
40135
40136	/**
40137	 * Add referenced root elements (error, escalation, message, signal) if they don't exist.
40138	 * Copy referenced root elements on copy & paste.
40139	 */
40140	function RootElementReferenceBehavior(
40141	    bpmnjs, eventBus, injector, moddleCopy, bpmnFactory
40142	) {
40143	  injector.invoke(CommandInterceptor, this);
40144
40145	  function canHaveRootElementReference(element) {
40146	    return isAny(element, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ]) ||
40147	      hasAnyEventDefinition(element, [
40148	        'bpmn:ErrorEventDefinition',
40149	        'bpmn:EscalationEventDefinition',
40150	        'bpmn:MessageEventDefinition',
40151	        'bpmn:SignalEventDefinition'
40152	      ]);
40153	  }
40154
40155	  function hasRootElement(rootElement) {
40156	    var definitions = bpmnjs.getDefinitions(),
40157	        rootElements = definitions.get('rootElements');
40158
40159	    return !!find(rootElements, matchPattern({ id: rootElement.id }));
40160	  }
40161
40162	  function getRootElementReferencePropertyName(eventDefinition) {
40163	    if (is$1(eventDefinition, 'bpmn:ErrorEventDefinition')) {
40164	      return 'errorRef';
40165	    } else if (is$1(eventDefinition, 'bpmn:EscalationEventDefinition')) {
40166	      return 'escalationRef';
40167	    } else if (is$1(eventDefinition, 'bpmn:MessageEventDefinition')) {
40168	      return 'messageRef';
40169	    } else if (is$1(eventDefinition, 'bpmn:SignalEventDefinition')) {
40170	      return 'signalRef';
40171	    }
40172	  }
40173
40174	  function getRootElement(businessObject) {
40175	    if (isAny(businessObject, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ])) {
40176	      return businessObject.get('messageRef');
40177	    }
40178
40179	    var eventDefinitions = businessObject.get('eventDefinitions'),
40180	        eventDefinition = eventDefinitions[ 0 ];
40181
40182	    return eventDefinition.get(getRootElementReferencePropertyName(eventDefinition));
40183	  }
40184
40185	  function setRootElement(businessObject, rootElement) {
40186	    if (isAny(businessObject, [ 'bpmn:ReceiveTask', 'bpmn:SendTask' ])) {
40187	      return businessObject.set('messageRef', rootElement);
40188	    }
40189
40190	    var eventDefinitions = businessObject.get('eventDefinitions'),
40191	        eventDefinition = eventDefinitions[ 0 ];
40192
40193	    return eventDefinition.set(getRootElementReferencePropertyName(eventDefinition), rootElement);
40194	  }
40195
40196	  // create shape
40197	  this.executed('shape.create', function(context) {
40198	    var shape = context.shape;
40199
40200	    if (!canHaveRootElementReference(shape)) {
40201	      return;
40202	    }
40203
40204	    var businessObject = getBusinessObject(shape),
40205	        rootElement = getRootElement(businessObject),
40206	        rootElements;
40207
40208	    if (rootElement && !hasRootElement(rootElement)) {
40209	      rootElements = bpmnjs.getDefinitions().get('rootElements');
40210
40211	      // add root element
40212	      add(rootElements, rootElement);
40213
40214	      context.addedRootElement = rootElement;
40215	    }
40216	  }, true);
40217
40218	  this.reverted('shape.create', function(context) {
40219	    var addedRootElement = context.addedRootElement;
40220
40221	    if (!addedRootElement) {
40222	      return;
40223	    }
40224
40225	    var rootElements = bpmnjs.getDefinitions().get('rootElements');
40226
40227	    // remove root element
40228	    remove(rootElements, addedRootElement);
40229	  }, true);
40230
40231	  eventBus.on('copyPaste.copyElement', function(context) {
40232	    var descriptor = context.descriptor,
40233	        element = context.element;
40234
40235	    if (!canHaveRootElementReference(element)) {
40236	      return;
40237	    }
40238
40239	    var businessObject = getBusinessObject(element),
40240	        rootElement = getRootElement(businessObject);
40241
40242	    if (rootElement) {
40243	      descriptor.referencedRootElement = rootElement;
40244	    }
40245	  });
40246
40247	  eventBus.on('copyPaste.pasteElement', LOW_PRIORITY$b, function(context) {
40248	    var descriptor = context.descriptor,
40249	        businessObject = descriptor.businessObject;
40250
40251	    if (!canHaveRootElementReference(businessObject)) {
40252	      return;
40253	    }
40254
40255	    var referencedRootElement = descriptor.referencedRootElement;
40256
40257	    if (!referencedRootElement) {
40258	      return;
40259	    }
40260
40261	    if (!hasRootElement(referencedRootElement)) {
40262	      referencedRootElement = moddleCopy.copyElement(
40263	        referencedRootElement,
40264	        bpmnFactory.create(referencedRootElement.$type)
40265	      );
40266	    }
40267
40268	    setRootElement(businessObject, referencedRootElement);
40269	  });
40270	}
40271
40272	RootElementReferenceBehavior.$inject = [
40273	  'bpmnjs',
40274	  'eventBus',
40275	  'injector',
40276	  'moddleCopy',
40277	  'bpmnFactory'
40278	];
40279
40280	inherits$1(RootElementReferenceBehavior, CommandInterceptor);
40281
40282	// helpers //////////
40283
40284	function hasAnyEventDefinition(element, types) {
40285	  if (!isArray$2(types)) {
40286	    types = [ types ];
40287	  }
40288
40289	  return some(types, function(type) {
40290	    return hasEventDefinition$2(element, type);
40291	  });
40292	}
40293
40294	function CreateBehavior(injector) {
40295	  injector.invoke(CommandInterceptor, this);
40296
40297	  this.preExecute('shape.create', 1500, function(event) {
40298	    var context = event.context,
40299	        parent = context.parent,
40300	        shape = context.shape;
40301
40302	    if (is$1(parent, 'bpmn:Lane') && !is$1(shape, 'bpmn:Lane')) {
40303	      context.parent = getParent(parent, 'bpmn:Participant');
40304	    }
40305	  });
40306
40307	}
40308
40309
40310	CreateBehavior.$inject = [ 'injector' ];
40311
40312	inherits$1(CreateBehavior, CommandInterceptor);
40313
40314	var HIGH_PRIORITY$b = 1500;
40315	var HIGHEST_PRIORITY = 2000;
40316
40317
40318	/**
40319	 * Correct hover targets in certain situations to improve diagram interaction.
40320	 *
40321	 * @param {ElementRegistry} elementRegistry
40322	 * @param {EventBus} eventBus
40323	 * @param {Canvas} canvas
40324	 */
40325	function FixHoverBehavior(elementRegistry, eventBus, canvas) {
40326
40327	  eventBus.on([
40328	    'create.hover',
40329	    'create.move',
40330	    'create.out',
40331	    'create.end',
40332	    'shape.move.hover',
40333	    'shape.move.move',
40334	    'shape.move.out',
40335	    'shape.move.end'
40336	  ], HIGH_PRIORITY$b, function(event) {
40337	    var context = event.context,
40338	        shape = context.shape || event.shape,
40339	        hover = event.hover;
40340
40341	    // ensure elements are not dropped onto a bpmn:Lane but onto
40342	    // the underlying bpmn:Participant
40343	    if (is$1(hover, 'bpmn:Lane') && !isAny(shape, [ 'bpmn:Lane', 'bpmn:Participant' ])) {
40344	      event.hover = getLanesRoot(hover);
40345	      event.hoverGfx = elementRegistry.getGraphics(event.hover);
40346	    }
40347
40348	    var rootElement = canvas.getRootElement();
40349
40350	    // ensure bpmn:Group and label elements are dropped
40351	    // always onto the root
40352	    if (hover !== rootElement && (shape.labelTarget || is$1(shape, 'bpmn:Group'))) {
40353	      event.hover = rootElement;
40354	      event.hoverGfx = elementRegistry.getGraphics(event.hover);
40355	    }
40356	  });
40357
40358	  eventBus.on([
40359	    'connect.hover',
40360	    'connect.out',
40361	    'connect.end',
40362	    'connect.cleanup',
40363	    'global-connect.hover',
40364	    'global-connect.out',
40365	    'global-connect.end',
40366	    'global-connect.cleanup'
40367	  ], HIGH_PRIORITY$b, function(event) {
40368	    var hover = event.hover;
40369
40370	    // ensure connections start/end on bpmn:Participant,
40371	    // not the underlying bpmn:Lane
40372	    if (is$1(hover, 'bpmn:Lane')) {
40373	      event.hover = getLanesRoot(hover) || hover;
40374	      event.hoverGfx = elementRegistry.getGraphics(event.hover);
40375	    }
40376	  });
40377
40378
40379	  eventBus.on([
40380	    'bendpoint.move.hover'
40381	  ], HIGH_PRIORITY$b, function(event) {
40382	    var context = event.context,
40383	        hover = event.hover,
40384	        type = context.type;
40385
40386	    // ensure reconnect start/end on bpmn:Participant,
40387	    // not the underlying bpmn:Lane
40388	    if (is$1(hover, 'bpmn:Lane') && /reconnect/.test(type)) {
40389	      event.hover = getLanesRoot(hover) || hover;
40390	      event.hoverGfx = elementRegistry.getGraphics(event.hover);
40391	    }
40392	  });
40393
40394
40395	  eventBus.on([
40396	    'connect.start'
40397	  ], HIGH_PRIORITY$b, function(event) {
40398	    var context = event.context,
40399	        start = context.start;
40400
40401	    // ensure connect start on bpmn:Participant,
40402	    // not the underlying bpmn:Lane
40403	    if (is$1(start, 'bpmn:Lane')) {
40404	      context.start = getLanesRoot(start) || start;
40405	    }
40406	  });
40407
40408
40409	  // allow movement of participants from lanes
40410	  eventBus.on('shape.move.start', HIGHEST_PRIORITY, function(event) {
40411	    var shape = event.shape;
40412
40413	    if (is$1(shape, 'bpmn:Lane')) {
40414	      event.shape = getLanesRoot(shape) || shape;
40415	    }
40416	  });
40417
40418	}
40419
40420	FixHoverBehavior.$inject = [
40421	  'elementRegistry',
40422	  'eventBus',
40423	  'canvas'
40424	];
40425
40426	/**
40427	 * BPMN specific create data object behavior
40428	 */
40429	function CreateDataObjectBehavior(eventBus, bpmnFactory, moddle) {
40430
40431	  CommandInterceptor.call(this, eventBus);
40432
40433	  this.preExecute('shape.create', function(event) {
40434
40435	    var context = event.context,
40436	        shape = context.shape;
40437
40438	    if (is$1(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
40439
40440	      // create a DataObject every time a DataObjectReference is created
40441	      var dataObject = bpmnFactory.create('bpmn:DataObject');
40442
40443	      // set the reference to the DataObject
40444	      shape.businessObject.dataObjectRef = dataObject;
40445	    }
40446	  });
40447
40448	}
40449
40450	CreateDataObjectBehavior.$inject = [
40451	  'eventBus',
40452	  'bpmnFactory',
40453	  'moddle'
40454	];
40455
40456	inherits$1(CreateDataObjectBehavior, CommandInterceptor);
40457
40458	var HORIZONTAL_PARTICIPANT_PADDING = 20,
40459	    VERTICAL_PARTICIPANT_PADDING = 20;
40460
40461	var PARTICIPANT_BORDER_WIDTH = 30;
40462
40463	var HIGH_PRIORITY$a = 2000;
40464
40465
40466	/**
40467	 * BPMN-specific behavior for creating participants.
40468	 */
40469	function CreateParticipantBehavior(canvas, eventBus, modeling) {
40470	  CommandInterceptor.call(this, eventBus);
40471
40472	  // fit participant
40473	  eventBus.on([
40474	    'create.start',
40475	    'shape.move.start'
40476	  ], HIGH_PRIORITY$a, function(event) {
40477	    var context = event.context,
40478	        shape = context.shape,
40479	        rootElement = canvas.getRootElement();
40480
40481	    if (!is$1(shape, 'bpmn:Participant') ||
40482	      !is$1(rootElement, 'bpmn:Process') ||
40483	      !rootElement.children.length) {
40484	      return;
40485	    }
40486
40487	    // ignore connections, groups and labels
40488	    var children = rootElement.children.filter(function(element) {
40489	      return !is$1(element, 'bpmn:Group') &&
40490	        !isLabel$6(element) &&
40491	        !isConnection$9(element);
40492	    });
40493
40494	    // ensure for available children to calculate bounds
40495	    if (!children.length) {
40496	      return;
40497	    }
40498
40499	    var childrenBBox = getBBox(children);
40500
40501	    var participantBounds = getParticipantBounds(shape, childrenBBox);
40502
40503	    // assign width and height
40504	    assign(shape, participantBounds);
40505
40506	    // assign create constraints
40507	    context.createConstraints = getParticipantCreateConstraints(shape, childrenBBox);
40508	  });
40509
40510	  // force hovering process when creating first participant
40511	  eventBus.on('create.start', HIGH_PRIORITY$a, function(event) {
40512	    var context = event.context,
40513	        shape = context.shape,
40514	        rootElement = canvas.getRootElement(),
40515	        rootElementGfx = canvas.getGraphics(rootElement);
40516
40517	    function ensureHoveringProcess(event) {
40518	      event.element = rootElement;
40519	      event.gfx = rootElementGfx;
40520	    }
40521
40522	    if (is$1(shape, 'bpmn:Participant') && is$1(rootElement, 'bpmn:Process')) {
40523	      eventBus.on('element.hover', HIGH_PRIORITY$a, ensureHoveringProcess);
40524
40525	      eventBus.once('create.cleanup', function() {
40526	        eventBus.off('element.hover', ensureHoveringProcess);
40527	      });
40528	    }
40529	  });
40530
40531	  function ensureCollaboration(context) {
40532	    var parent = context.parent,
40533	        collaboration;
40534
40535	    var rootElement = canvas.getRootElement();
40536
40537	    if (is$1(rootElement, 'bpmn:Collaboration')) {
40538	      collaboration = rootElement;
40539	    } else {
40540
40541	      // update root element by making collaboration
40542	      collaboration = modeling.makeCollaboration();
40543
40544	      // re-use process when creating first participant
40545	      context.process = parent;
40546	    }
40547
40548	    context.parent = collaboration;
40549	  }
40550
40551	  // turn process into collaboration before adding participant
40552	  this.preExecute('shape.create', function(context) {
40553	    var parent = context.parent,
40554	        shape = context.shape;
40555
40556	    if (is$1(shape, 'bpmn:Participant') && is$1(parent, 'bpmn:Process')) {
40557	      ensureCollaboration(context);
40558	    }
40559	  }, true);
40560
40561	  this.execute('shape.create', function(context) {
40562	    var process = context.process,
40563	        shape = context.shape;
40564
40565	    if (process) {
40566	      context.oldProcessRef = shape.businessObject.processRef;
40567
40568	      // re-use process when creating first participant
40569	      shape.businessObject.processRef = process.businessObject;
40570	    }
40571	  }, true);
40572
40573	  this.revert('shape.create', function(context) {
40574	    var process = context.process,
40575	        shape = context.shape;
40576
40577	    if (process) {
40578
40579	      // re-use process when creating first participant
40580	      shape.businessObject.processRef = context.oldProcessRef;
40581	    }
40582	  }, true);
40583
40584	  this.postExecute('shape.create', function(context) {
40585	    var process = context.process,
40586	        shape = context.shape;
40587
40588	    if (process) {
40589
40590	      // move children from process to participant
40591	      var processChildren = process.children.slice();
40592
40593	      modeling.moveElements(processChildren, { x: 0, y: 0 }, shape);
40594	    }
40595
40596	  }, true);
40597
40598	  // turn process into collaboration when creating participants
40599	  this.preExecute('elements.create', HIGH_PRIORITY$a, function(context) {
40600	    var elements = context.elements,
40601	        parent = context.parent,
40602	        participant;
40603
40604	    var hasParticipants = findParticipant(elements);
40605
40606	    if (hasParticipants && is$1(parent, 'bpmn:Process')) {
40607	      ensureCollaboration(context);
40608
40609	      participant = findParticipant(elements);
40610
40611	      context.oldProcessRef = participant.businessObject.processRef;
40612
40613	      // re-use process when creating first participant
40614	      participant.businessObject.processRef = parent.businessObject;
40615	    }
40616	  }, true);
40617
40618	  this.revert('elements.create', function(context) {
40619	    var elements = context.elements,
40620	        process = context.process,
40621	        participant;
40622
40623	    if (process) {
40624	      participant = findParticipant(elements);
40625
40626	      // re-use process when creating first participant
40627	      participant.businessObject.processRef = context.oldProcessRef;
40628	    }
40629	  }, true);
40630
40631	  this.postExecute('elements.create', function(context) {
40632	    var elements = context.elements,
40633	        process = context.process,
40634	        participant;
40635
40636	    if (process) {
40637	      participant = findParticipant(elements);
40638
40639	      // move children from process to first participant
40640	      var processChildren = process.children.slice();
40641
40642	      modeling.moveElements(processChildren, { x: 0, y: 0 }, participant);
40643	    }
40644
40645	  }, true);
40646
40647	}
40648
40649	CreateParticipantBehavior.$inject = [
40650	  'canvas',
40651	  'eventBus',
40652	  'modeling'
40653	];
40654
40655	inherits$1(CreateParticipantBehavior, CommandInterceptor);
40656
40657	// helpers //////////
40658
40659	function getParticipantBounds(shape, childrenBBox) {
40660	  childrenBBox = {
40661	    width: childrenBBox.width + HORIZONTAL_PARTICIPANT_PADDING * 2 + PARTICIPANT_BORDER_WIDTH,
40662	    height: childrenBBox.height + VERTICAL_PARTICIPANT_PADDING * 2
40663	  };
40664
40665	  var width = Math.max(shape.width, childrenBBox.width),
40666	      height = Math.max(shape.height, childrenBBox.height);
40667
40668	  return {
40669	    x: -width / 2,
40670	    y: -height / 2,
40671	    width: width,
40672	    height: height
40673	  };
40674	}
40675
40676	function getParticipantCreateConstraints(shape, childrenBBox) {
40677	  childrenBBox = asTRBL(childrenBBox);
40678
40679	  return {
40680	    bottom: childrenBBox.top + shape.height / 2 - VERTICAL_PARTICIPANT_PADDING,
40681	    left: childrenBBox.right - shape.width / 2 + HORIZONTAL_PARTICIPANT_PADDING,
40682	    top: childrenBBox.bottom - shape.height / 2 + VERTICAL_PARTICIPANT_PADDING,
40683	    right: childrenBBox.left + shape.width / 2 - HORIZONTAL_PARTICIPANT_PADDING - PARTICIPANT_BORDER_WIDTH
40684	  };
40685	}
40686
40687	function isConnection$9(element) {
40688	  return !!element.waypoints;
40689	}
40690
40691	function findParticipant(elements) {
40692	  return find(elements, function(element) {
40693	    return is$1(element, 'bpmn:Participant');
40694	  });
40695	}
40696
40697	var TARGET_REF_PLACEHOLDER_NAME = '__targetRef_placeholder';
40698
40699
40700	/**
40701	 * This behavior makes sure we always set a fake
40702	 * DataInputAssociation#targetRef as demanded by the BPMN 2.0
40703	 * XSD schema.
40704	 *
40705	 * The reference is set to a bpmn:Property{ name: '__targetRef_placeholder' }
40706	 * which is created on the fly and cleaned up afterwards if not needed
40707	 * anymore.
40708	 *
40709	 * @param {EventBus} eventBus
40710	 * @param {BpmnFactory} bpmnFactory
40711	 */
40712	function DataInputAssociationBehavior(eventBus, bpmnFactory) {
40713
40714	  CommandInterceptor.call(this, eventBus);
40715
40716
40717	  this.executed([
40718	    'connection.create',
40719	    'connection.delete',
40720	    'connection.move',
40721	    'connection.reconnect'
40722	  ], ifDataInputAssociation(fixTargetRef));
40723
40724	  this.reverted([
40725	    'connection.create',
40726	    'connection.delete',
40727	    'connection.move',
40728	    'connection.reconnect'
40729	  ], ifDataInputAssociation(fixTargetRef));
40730
40731
40732	  function usesTargetRef(element, targetRef, removedConnection) {
40733
40734	    var inputAssociations = element.get('dataInputAssociations');
40735
40736	    return find(inputAssociations, function(association) {
40737	      return association !== removedConnection &&
40738	             association.targetRef === targetRef;
40739	    });
40740	  }
40741
40742	  function getTargetRef(element, create) {
40743
40744	    var properties = element.get('properties');
40745
40746	    var targetRefProp = find(properties, function(p) {
40747	      return p.name === TARGET_REF_PLACEHOLDER_NAME;
40748	    });
40749
40750	    if (!targetRefProp && create) {
40751	      targetRefProp = bpmnFactory.create('bpmn:Property', {
40752	        name: TARGET_REF_PLACEHOLDER_NAME
40753	      });
40754
40755	      add(properties, targetRefProp);
40756	    }
40757
40758	    return targetRefProp;
40759	  }
40760
40761	  function cleanupTargetRef(element, connection) {
40762
40763	    var targetRefProp = getTargetRef(element);
40764
40765	    if (!targetRefProp) {
40766	      return;
40767	    }
40768
40769	    if (!usesTargetRef(element, targetRefProp, connection)) {
40770	      remove(element.get('properties'), targetRefProp);
40771	    }
40772	  }
40773
40774	  /**
40775	   * Make sure targetRef is set to a valid property or
40776	   * `null` if the connection is detached.
40777	   *
40778	   * @param {Event} event
40779	   */
40780	  function fixTargetRef(event) {
40781
40782	    var context = event.context,
40783	        connection = context.connection,
40784	        connectionBo = connection.businessObject,
40785	        target = connection.target,
40786	        targetBo = target && target.businessObject,
40787	        newTarget = context.newTarget,
40788	        newTargetBo = newTarget && newTarget.businessObject,
40789	        oldTarget = context.oldTarget || context.target,
40790	        oldTargetBo = oldTarget && oldTarget.businessObject;
40791
40792	    var dataAssociation = connection.businessObject,
40793	        targetRefProp;
40794
40795	    if (oldTargetBo && oldTargetBo !== targetBo) {
40796	      cleanupTargetRef(oldTargetBo, connectionBo);
40797	    }
40798
40799	    if (newTargetBo && newTargetBo !== targetBo) {
40800	      cleanupTargetRef(newTargetBo, connectionBo);
40801	    }
40802
40803	    if (targetBo) {
40804	      targetRefProp = getTargetRef(targetBo, true);
40805	      dataAssociation.targetRef = targetRefProp;
40806	    } else {
40807	      dataAssociation.targetRef = null;
40808	    }
40809	  }
40810	}
40811
40812	DataInputAssociationBehavior.$inject = [
40813	  'eventBus',
40814	  'bpmnFactory'
40815	];
40816
40817	inherits$1(DataInputAssociationBehavior, CommandInterceptor);
40818
40819
40820	/**
40821	 * Only call the given function when the event
40822	 * touches a bpmn:DataInputAssociation.
40823	 *
40824	 * @param {Function} fn
40825	 * @return {Function}
40826	 */
40827	function ifDataInputAssociation(fn) {
40828
40829	  return function(event) {
40830	    var context = event.context,
40831	        connection = context.connection;
40832
40833	    if (is$1(connection, 'bpmn:DataInputAssociation')) {
40834	      return fn(event);
40835	    }
40836	  };
40837	}
40838
40839	function UpdateSemanticParentHandler(bpmnUpdater) {
40840	  this._bpmnUpdater = bpmnUpdater;
40841	}
40842
40843	UpdateSemanticParentHandler.$inject = [ 'bpmnUpdater' ];
40844
40845
40846	UpdateSemanticParentHandler.prototype.execute = function(context) {
40847	  var dataStoreBo = context.dataStoreBo,
40848	      newSemanticParent = context.newSemanticParent,
40849	      newDiParent = context.newDiParent;
40850
40851	  context.oldSemanticParent = dataStoreBo.$parent;
40852	  context.oldDiParent = dataStoreBo.di.$parent;
40853
40854	  // update semantic parent
40855	  this._bpmnUpdater.updateSemanticParent(dataStoreBo, newSemanticParent);
40856
40857	  // update DI parent
40858	  this._bpmnUpdater.updateDiParent(dataStoreBo.di, newDiParent);
40859	};
40860
40861	UpdateSemanticParentHandler.prototype.revert = function(context) {
40862	  var dataStoreBo = context.dataStoreBo,
40863	      oldSemanticParent = context.oldSemanticParent,
40864	      oldDiParent = context.oldDiParent;
40865
40866	  // update semantic parent
40867	  this._bpmnUpdater.updateSemanticParent(dataStoreBo, oldSemanticParent);
40868
40869	  // update DI parent
40870	  this._bpmnUpdater.updateDiParent(dataStoreBo.di, oldDiParent);
40871	};
40872
40873	/**
40874	 * BPMN specific data store behavior
40875	 */
40876	function DataStoreBehavior(
40877	    canvas, commandStack, elementRegistry,
40878	    eventBus) {
40879
40880	  CommandInterceptor.call(this, eventBus);
40881
40882	  commandStack.registerHandler('dataStore.updateContainment', UpdateSemanticParentHandler);
40883
40884	  function getFirstParticipantWithProcessRef() {
40885	    return elementRegistry.filter(function(element) {
40886	      return is$1(element, 'bpmn:Participant') && getBusinessObject(element).processRef;
40887	    })[0];
40888	  }
40889
40890	  function getDataStores(element) {
40891	    return element.children.filter(function(child) {
40892	      return is$1(child, 'bpmn:DataStoreReference') && !child.labelTarget;
40893	    });
40894	  }
40895
40896	  function updateDataStoreParent(dataStore, newDataStoreParent) {
40897	    var dataStoreBo = dataStore.businessObject || dataStore;
40898
40899	    newDataStoreParent = newDataStoreParent || getFirstParticipantWithProcessRef();
40900
40901	    if (newDataStoreParent) {
40902	      var newDataStoreParentBo = newDataStoreParent.businessObject || newDataStoreParent;
40903
40904	      commandStack.execute('dataStore.updateContainment', {
40905	        dataStoreBo: dataStoreBo,
40906	        newSemanticParent: newDataStoreParentBo.processRef || newDataStoreParentBo,
40907	        newDiParent: newDataStoreParentBo.di
40908	      });
40909	    }
40910	  }
40911
40912
40913	  // disable auto-resize for data stores
40914	  this.preExecute('shape.create', function(event) {
40915
40916	    var context = event.context,
40917	        shape = context.shape;
40918
40919	    if (is$1(shape, 'bpmn:DataStoreReference') &&
40920	        shape.type !== 'label') {
40921
40922	      if (!context.hints) {
40923	        context.hints = {};
40924	      }
40925
40926	      // prevent auto resizing
40927	      context.hints.autoResize = false;
40928	    }
40929	  });
40930
40931
40932	  // disable auto-resize for data stores
40933	  this.preExecute('elements.move', function(event) {
40934	    var context = event.context,
40935	        shapes = context.shapes;
40936
40937	    var dataStoreReferences = shapes.filter(function(shape) {
40938	      return is$1(shape, 'bpmn:DataStoreReference');
40939	    });
40940
40941	    if (dataStoreReferences.length) {
40942	      if (!context.hints) {
40943	        context.hints = {};
40944	      }
40945
40946	      // prevent auto resizing for data store references
40947	      context.hints.autoResize = shapes.filter(function(shape) {
40948	        return !is$1(shape, 'bpmn:DataStoreReference');
40949	      });
40950	    }
40951	  });
40952
40953
40954	  // update parent on data store created
40955	  this.postExecute('shape.create', function(event) {
40956	    var context = event.context,
40957	        shape = context.shape,
40958	        parent = shape.parent;
40959
40960
40961	    if (is$1(shape, 'bpmn:DataStoreReference') &&
40962	        shape.type !== 'label' &&
40963	        is$1(parent, 'bpmn:Collaboration')) {
40964
40965	      updateDataStoreParent(shape);
40966	    }
40967	  });
40968
40969
40970	  // update parent on data store moved
40971	  this.postExecute('shape.move', function(event) {
40972	    var context = event.context,
40973	        shape = context.shape,
40974	        oldParent = context.oldParent,
40975	        parent = shape.parent;
40976
40977	    if (is$1(oldParent, 'bpmn:Collaboration')) {
40978
40979	      // do nothing if not necessary
40980	      return;
40981	    }
40982
40983	    if (is$1(shape, 'bpmn:DataStoreReference') &&
40984	        shape.type !== 'label' &&
40985	        is$1(parent, 'bpmn:Collaboration')) {
40986
40987	      var participant = is$1(oldParent, 'bpmn:Participant') ?
40988	        oldParent :
40989	        getAncestor(oldParent, 'bpmn:Participant');
40990
40991	      updateDataStoreParent(shape, participant);
40992	    }
40993	  });
40994
40995
40996	  // update data store parents on participant or subprocess deleted
40997	  this.postExecute('shape.delete', function(event) {
40998	    var context = event.context,
40999	        shape = context.shape,
41000	        rootElement = canvas.getRootElement();
41001
41002	    if (isAny(shape, [ 'bpmn:Participant', 'bpmn:SubProcess' ])
41003	        && is$1(rootElement, 'bpmn:Collaboration')) {
41004	      getDataStores(rootElement)
41005	        .filter(function(dataStore) {
41006	          return isDescendant(dataStore, shape);
41007	        })
41008	        .forEach(function(dataStore) {
41009	          updateDataStoreParent(dataStore);
41010	        });
41011	    }
41012	  });
41013
41014	  // update data store parents on collaboration -> process
41015	  this.postExecute('canvas.updateRoot', function(event) {
41016	    var context = event.context,
41017	        oldRoot = context.oldRoot,
41018	        newRoot = context.newRoot;
41019
41020	    var dataStores = getDataStores(oldRoot);
41021
41022	    dataStores.forEach(function(dataStore) {
41023
41024	      if (is$1(newRoot, 'bpmn:Process')) {
41025	        updateDataStoreParent(dataStore, newRoot);
41026	      }
41027
41028	    });
41029	  });
41030	}
41031
41032	DataStoreBehavior.$inject = [
41033	  'canvas',
41034	  'commandStack',
41035	  'elementRegistry',
41036	  'eventBus',
41037	];
41038
41039	inherits$1(DataStoreBehavior, CommandInterceptor);
41040
41041
41042	// helpers //////////
41043
41044	function isDescendant(descendant, ancestor) {
41045	  var descendantBo = descendant.businessObject || descendant,
41046	      ancestorBo = ancestor.businessObject || ancestor;
41047
41048	  while (descendantBo.$parent) {
41049	    if (descendantBo.$parent === ancestorBo.processRef || ancestorBo) {
41050	      return true;
41051	    }
41052
41053	    descendantBo = descendantBo.$parent;
41054	  }
41055
41056	  return false;
41057	}
41058
41059	function getAncestor(element, type) {
41060
41061	  while (element.parent) {
41062	    if (is$1(element.parent, type)) {
41063	      return element.parent;
41064	    }
41065
41066	    element = element.parent;
41067	  }
41068	}
41069
41070	var LOW_PRIORITY$a = 500;
41071
41072
41073	/**
41074	 * BPMN specific delete lane behavior
41075	 */
41076	function DeleteLaneBehavior(eventBus, modeling, spaceTool) {
41077
41078	  CommandInterceptor.call(this, eventBus);
41079
41080
41081	  function compensateLaneDelete(shape, oldParent) {
41082
41083	    var siblings = getChildLanes(oldParent);
41084
41085	    var topAffected = [];
41086	    var bottomAffected = [];
41087
41088	    eachElement(siblings, function(element) {
41089
41090	      if (element.y > shape.y) {
41091	        bottomAffected.push(element);
41092	      } else {
41093	        topAffected.push(element);
41094	      }
41095
41096	      return element.children;
41097	    });
41098
41099	    if (!siblings.length) {
41100	      return;
41101	    }
41102
41103	    var offset;
41104
41105	    if (bottomAffected.length && topAffected.length) {
41106	      offset = shape.height / 2;
41107	    } else {
41108	      offset = shape.height;
41109	    }
41110
41111	    var topAdjustments,
41112	        bottomAdjustments;
41113
41114	    if (topAffected.length) {
41115	      topAdjustments = spaceTool.calculateAdjustments(
41116	        topAffected, 'y', offset, shape.y - 10);
41117
41118	      spaceTool.makeSpace(
41119	        topAdjustments.movingShapes,
41120	        topAdjustments.resizingShapes,
41121	        { x: 0, y: offset }, 's');
41122	    }
41123
41124	    if (bottomAffected.length) {
41125	      bottomAdjustments = spaceTool.calculateAdjustments(
41126	        bottomAffected, 'y', -offset, shape.y + shape.height + 10);
41127
41128	      spaceTool.makeSpace(
41129	        bottomAdjustments.movingShapes,
41130	        bottomAdjustments.resizingShapes,
41131	        { x: 0, y: -offset }, 'n');
41132	    }
41133	  }
41134
41135
41136	  /**
41137	   * Adjust sizes of other lanes after lane deletion
41138	   */
41139	  this.postExecuted('shape.delete', LOW_PRIORITY$a, function(event) {
41140
41141	    var context = event.context,
41142	        hints = context.hints,
41143	        shape = context.shape,
41144	        oldParent = context.oldParent;
41145
41146	    // only compensate lane deletes
41147	    if (!is$1(shape, 'bpmn:Lane')) {
41148	      return;
41149	    }
41150
41151	    // compensate root deletes only
41152	    if (hints && hints.nested) {
41153	      return;
41154	    }
41155
41156	    compensateLaneDelete(shape, oldParent);
41157	  });
41158	}
41159
41160	DeleteLaneBehavior.$inject = [
41161	  'eventBus',
41162	  'modeling',
41163	  'spaceTool'
41164	];
41165
41166	inherits$1(DeleteLaneBehavior, CommandInterceptor);
41167
41168	var LOW_PRIORITY$9 = 500;
41169
41170
41171	/**
41172	 * Replace boundary event with intermediate event when creating or moving results in detached event.
41173	 */
41174	function DetachEventBehavior(bpmnReplace, injector) {
41175	  injector.invoke(CommandInterceptor, this);
41176
41177	  this._bpmnReplace = bpmnReplace;
41178
41179	  var self = this;
41180
41181	  this.postExecuted('elements.create', LOW_PRIORITY$9, function(context) {
41182	    var elements = context.elements;
41183
41184	    elements.filter(function(shape) {
41185	      var host = shape.host;
41186
41187	      return shouldReplace(shape, host);
41188	    }).map(function(shape) {
41189	      return elements.indexOf(shape);
41190	    }).forEach(function(index) {
41191	      context.elements[ index ] = self.replaceShape(elements[ index ]);
41192	    });
41193	  }, true);
41194
41195	  this.preExecute('elements.move', LOW_PRIORITY$9, function(context) {
41196	    var shapes = context.shapes,
41197	        newHost = context.newHost;
41198
41199	    shapes.forEach(function(shape, index) {
41200	      var host = shape.host;
41201
41202	      if (shouldReplace(shape, includes$6(shapes, host) ? host : newHost)) {
41203	        shapes[ index ] = self.replaceShape(shape);
41204	      }
41205	    });
41206	  }, true);
41207	}
41208
41209	DetachEventBehavior.$inject = [
41210	  'bpmnReplace',
41211	  'injector'
41212	];
41213
41214	inherits$1(DetachEventBehavior, CommandInterceptor);
41215
41216	DetachEventBehavior.prototype.replaceShape = function(shape) {
41217	  var eventDefinition = getEventDefinition(shape),
41218	      intermediateEvent;
41219
41220	  if (eventDefinition) {
41221	    intermediateEvent = {
41222	      type: 'bpmn:IntermediateCatchEvent',
41223	      eventDefinitionType: eventDefinition.$type
41224	    };
41225	  } else {
41226	    intermediateEvent = {
41227	      type: 'bpmn:IntermediateThrowEvent'
41228	    };
41229	  }
41230
41231	  return this._bpmnReplace.replaceElement(shape, intermediateEvent, { layoutConnection: false });
41232	};
41233
41234
41235	// helpers //////////
41236
41237	function getEventDefinition(element) {
41238	  var businessObject = getBusinessObject(element),
41239	      eventDefinitions = businessObject.eventDefinitions;
41240
41241	  return eventDefinitions && eventDefinitions[0];
41242	}
41243
41244	function shouldReplace(shape, host) {
41245	  return !isLabel$6(shape) && is$1(shape, 'bpmn:BoundaryEvent') && !host;
41246	}
41247
41248	function includes$6(array, item) {
41249	  return array.indexOf(item) !== -1;
41250	}
41251
41252	function DropOnFlowBehavior(eventBus, bpmnRules, modeling) {
41253
41254	  CommandInterceptor.call(this, eventBus);
41255
41256	  /**
41257	   * Reconnect start / end of a connection after
41258	   * dropping an element on a flow.
41259	   */
41260
41261	  function insertShape(shape, targetFlow, positionOrBounds) {
41262	    var waypoints = targetFlow.waypoints,
41263	        waypointsBefore,
41264	        waypointsAfter,
41265	        dockingPoint,
41266	        source,
41267	        target,
41268	        incomingConnection,
41269	        outgoingConnection,
41270	        oldOutgoing = shape.outgoing.slice(),
41271	        oldIncoming = shape.incoming.slice();
41272
41273	    var mid;
41274
41275	    if (isNumber(positionOrBounds.width)) {
41276	      mid = getMid(positionOrBounds);
41277	    } else {
41278	      mid = positionOrBounds;
41279	    }
41280
41281	    var intersection = getApproxIntersection(waypoints, mid);
41282
41283	    if (intersection) {
41284	      waypointsBefore = waypoints.slice(0, intersection.index);
41285	      waypointsAfter = waypoints.slice(intersection.index + (intersection.bendpoint ? 1 : 0));
41286
41287	      // due to inaccuracy intersection might have been found
41288	      if (!waypointsBefore.length || !waypointsAfter.length) {
41289	        return;
41290	      }
41291
41292	      dockingPoint = intersection.bendpoint ? waypoints[intersection.index] : mid;
41293
41294	      // if last waypointBefore is inside shape's bounds, ignore docking point
41295	      if (!isPointInsideBBox(shape, waypointsBefore[waypointsBefore.length-1])) {
41296	        waypointsBefore.push(copy(dockingPoint));
41297	      }
41298
41299	      // if first waypointAfter is inside shape's bounds, ignore docking point
41300	      if (!isPointInsideBBox(shape, waypointsAfter[0])) {
41301	        waypointsAfter.unshift(copy(dockingPoint));
41302	      }
41303	    }
41304
41305	    source = targetFlow.source;
41306	    target = targetFlow.target;
41307
41308	    if (bpmnRules.canConnect(source, shape, targetFlow)) {
41309
41310	      // reconnect source -> inserted shape
41311	      modeling.reconnectEnd(targetFlow, shape, waypointsBefore || mid);
41312
41313	      incomingConnection = targetFlow;
41314	    }
41315
41316	    if (bpmnRules.canConnect(shape, target, targetFlow)) {
41317
41318	      if (!incomingConnection) {
41319
41320	        // reconnect inserted shape -> end
41321	        modeling.reconnectStart(targetFlow, shape, waypointsAfter || mid);
41322
41323	        outgoingConnection = targetFlow;
41324	      } else {
41325	        outgoingConnection = modeling.connect(
41326	          shape, target, { type: targetFlow.type, waypoints: waypointsAfter }
41327	        );
41328	      }
41329	    }
41330
41331	    var duplicateConnections = [].concat(
41332
41333	      incomingConnection && filter(oldIncoming, function(connection) {
41334	        return connection.source === incomingConnection.source;
41335	      }) || [],
41336
41337	      outgoingConnection && filter(oldOutgoing, function(connection) {
41338	        return connection.target === outgoingConnection.target;
41339	      }) || []
41340	    );
41341
41342	    if (duplicateConnections.length) {
41343	      modeling.removeElements(duplicateConnections);
41344	    }
41345	  }
41346
41347	  this.preExecute('elements.move', function(context) {
41348
41349	    var newParent = context.newParent,
41350	        shapes = context.shapes,
41351	        delta = context.delta,
41352	        shape = shapes[0];
41353
41354	    if (!shape || !newParent) {
41355	      return;
41356	    }
41357
41358	    // if the new parent is a connection,
41359	    // change it to the new parent's parent
41360	    if (newParent && newParent.waypoints) {
41361	      context.newParent = newParent = newParent.parent;
41362	    }
41363
41364	    var shapeMid = getMid(shape);
41365	    var newShapeMid = {
41366	      x: shapeMid.x + delta.x,
41367	      y: shapeMid.y + delta.y
41368	    };
41369
41370	    // find a connection which intersects with the
41371	    // element's mid point
41372	    var connection = find(newParent.children, function(element) {
41373	      var canInsert = bpmnRules.canInsert(shapes, element);
41374
41375	      return canInsert && getApproxIntersection(element.waypoints, newShapeMid);
41376	    });
41377
41378	    if (connection) {
41379	      context.targetFlow = connection;
41380	      context.position = newShapeMid;
41381	    }
41382
41383	  }, true);
41384
41385	  this.postExecuted('elements.move', function(context) {
41386
41387	    var shapes = context.shapes,
41388	        targetFlow = context.targetFlow,
41389	        position = context.position;
41390
41391	    if (targetFlow) {
41392	      insertShape(shapes[0], targetFlow, position);
41393	    }
41394
41395	  }, true);
41396
41397	  this.preExecute('shape.create', function(context) {
41398
41399	    var parent = context.parent,
41400	        shape = context.shape;
41401
41402	    if (bpmnRules.canInsert(shape, parent)) {
41403	      context.targetFlow = parent;
41404	      context.parent = parent.parent;
41405	    }
41406	  }, true);
41407
41408	  this.postExecuted('shape.create', function(context) {
41409
41410	    var shape = context.shape,
41411	        targetFlow = context.targetFlow,
41412	        positionOrBounds = context.position;
41413
41414	    if (targetFlow) {
41415	      insertShape(shape, targetFlow, positionOrBounds);
41416	    }
41417	  }, true);
41418	}
41419
41420	inherits$1(DropOnFlowBehavior, CommandInterceptor);
41421
41422	DropOnFlowBehavior.$inject = [
41423	  'eventBus',
41424	  'bpmnRules',
41425	  'modeling'
41426	];
41427
41428
41429	// helpers /////////////////////
41430
41431	function isPointInsideBBox(bbox, point) {
41432	  var x = point.x,
41433	      y = point.y;
41434
41435	  return x >= bbox.x &&
41436	    x <= bbox.x + bbox.width &&
41437	    y >= bbox.y &&
41438	    y <= bbox.y + bbox.height;
41439	}
41440
41441	function copy(obj) {
41442	  return assign({}, obj);
41443	}
41444
41445	function EventBasedGatewayBehavior(eventBus, modeling) {
41446
41447	  CommandInterceptor.call(this, eventBus);
41448
41449	  /**
41450	   * Remove existing sequence flows of event-based target before connecting
41451	   * from event-based gateway.
41452	   */
41453	  this.preExecuted('connection.create', function(event) {
41454
41455	    var context = event.context,
41456	        source = context.source,
41457	        target = context.target,
41458	        existingIncomingConnections = target.incoming.slice();
41459
41460	    if (context.hints && context.hints.createElementsBehavior === false) {
41461	      return;
41462	    }
41463
41464	    if (
41465	      is$1(source, 'bpmn:EventBasedGateway') &&
41466	      target.incoming.length
41467	    ) {
41468
41469	      existingIncomingConnections.filter(isSequenceFlow)
41470	        .forEach(function(sequenceFlow) {
41471	          modeling.removeConnection(sequenceFlow);
41472	        });
41473	    }
41474	  });
41475
41476	  /**
41477	   *  After replacing shape with event-based gateway, remove incoming sequence
41478	   *  flows of event-based targets which do not belong to event-based gateway
41479	   *  source.
41480	   */
41481	  this.preExecuted('shape.replace', function(event) {
41482
41483	    var newShape = event.context.newShape,
41484	        newShapeTargets,
41485	        newShapeTargetsIncomingSequenceFlows;
41486
41487	    if (!is$1(newShape, 'bpmn:EventBasedGateway')) {
41488	      return;
41489	    }
41490
41491	    newShapeTargets = newShape.outgoing.filter(isSequenceFlow)
41492	      .map(function(sequenceFlow) {
41493	        return sequenceFlow.target;
41494	      });
41495
41496	    newShapeTargetsIncomingSequenceFlows = newShapeTargets.reduce(function(sequenceFlows, target) {
41497	      var incomingSequenceFlows = target.incoming.filter(isSequenceFlow);
41498
41499	      return sequenceFlows.concat(incomingSequenceFlows);
41500	    }, []);
41501
41502	    newShapeTargetsIncomingSequenceFlows.forEach(function(sequenceFlow) {
41503	      if (sequenceFlow.source !== newShape) {
41504	        modeling.removeConnection(sequenceFlow);
41505	      }
41506	    });
41507	  });
41508	}
41509
41510	EventBasedGatewayBehavior.$inject = [
41511	  'eventBus',
41512	  'modeling'
41513	];
41514
41515	inherits$1(EventBasedGatewayBehavior, CommandInterceptor);
41516
41517
41518
41519	// helpers //////////////////////
41520
41521	function isSequenceFlow(connection) {
41522	  return is$1(connection, 'bpmn:SequenceFlow');
41523	}
41524
41525	var HIGH_PRIORITY$9 = 2000;
41526
41527
41528	/**
41529	 * BPMN specific Group behavior
41530	 */
41531	function GroupBehavior(
41532	    bpmnFactory,
41533	    canvas,
41534	    elementRegistry,
41535	    eventBus,
41536	    injector,
41537	    moddleCopy
41538	) {
41539	  injector.invoke(CommandInterceptor, this);
41540
41541	  /**
41542	   * Gets process definitions
41543	   *
41544	   * @return {ModdleElement} definitions
41545	   */
41546	  function getDefinitions() {
41547	    var rootElement = canvas.getRootElement(),
41548	        businessObject = getBusinessObject(rootElement);
41549
41550	    return businessObject.$parent;
41551	  }
41552
41553	  /**
41554	   * Removes a referenced category value for a given group shape
41555	   *
41556	   * @param {djs.model.Shape} shape
41557	   */
41558	  function removeReferencedCategoryValue(shape) {
41559
41560	    var businessObject = getBusinessObject(shape),
41561	        categoryValue = businessObject.categoryValueRef;
41562
41563	    if (!categoryValue) {
41564	      return;
41565	    }
41566
41567	    var category = categoryValue.$parent;
41568
41569	    if (!categoryValue) {
41570	      return;
41571	    }
41572
41573	    remove(category.categoryValue, categoryValue);
41574
41575	    // cleanup category if it is empty
41576	    if (category && !category.categoryValue.length) {
41577	      removeCategory(category);
41578	    }
41579	  }
41580
41581	  /**
41582	   * Removes a given category from the definitions
41583	   *
41584	   * @param {ModdleElement} category
41585	   */
41586	  function removeCategory(category) {
41587
41588	    var definitions = getDefinitions();
41589
41590	    remove(definitions.get('rootElements'), category);
41591	  }
41592
41593	  /**
41594	   * Returns all group element in the current registry
41595	   *
41596	   * @return {Array<djs.model.shape>} a list of group shapes
41597	   */
41598	  function getGroupElements() {
41599	    return elementRegistry.filter(function(e) {
41600	      return is$1(e, 'bpmn:Group');
41601	    });
41602	  }
41603
41604	  /**
41605	   * Returns true if given categoryValue is referenced in one of the given elements
41606	   *
41607	   * @param {Array<djs.model.shape>} elements
41608	   * @param {ModdleElement} categoryValue
41609	   * @return {boolean}
41610	   */
41611	  function isReferenced(elements, categoryValue) {
41612	    return elements.some(function(e) {
41613
41614	      var businessObject = getBusinessObject(e);
41615
41616	      return businessObject.categoryValueRef
41617	        && businessObject.categoryValueRef === categoryValue;
41618	    });
41619	  }
41620
41621	  /**
41622	   * remove referenced category + value when group was deleted
41623	   */
41624	  this.executed('shape.delete', function(event) {
41625
41626	    var context = event.context,
41627	        shape = context.shape;
41628
41629	    if (is$1(shape, 'bpmn:Group')) {
41630
41631	      var businessObject = getBusinessObject(shape),
41632	          categoryValueRef = businessObject.categoryValueRef,
41633	          groupElements = getGroupElements();
41634
41635	      if (!isReferenced(groupElements, categoryValueRef)) {
41636	        removeReferencedCategoryValue(shape);
41637	      }
41638	    }
41639	  });
41640
41641	  /**
41642	   * re-attach removed category
41643	   */
41644	  this.reverted('shape.delete', function(event) {
41645
41646	    var context = event.context,
41647	        shape = context.shape;
41648
41649	    if (is$1(shape, 'bpmn:Group')) {
41650
41651	      var businessObject = getBusinessObject(shape),
41652	          categoryValueRef = businessObject.categoryValueRef,
41653	          definitions = getDefinitions(),
41654	          category = categoryValueRef ? categoryValueRef.$parent : null;
41655
41656	      add(category.get('categoryValue'), categoryValueRef);
41657	      add(definitions.get('rootElements'), category);
41658	    }
41659	  });
41660
41661	  /**
41662	   * create new category + value when group was created
41663	   */
41664	  this.execute('shape.create', function(event) {
41665	    var context = event.context,
41666	        shape = context.shape,
41667	        businessObject = getBusinessObject(shape);
41668
41669	    if (is$1(businessObject, 'bpmn:Group') && !businessObject.categoryValueRef) {
41670
41671	      var definitions = getDefinitions(),
41672	          categoryValue = createCategoryValue(definitions, bpmnFactory);
41673
41674	      // link the reference to the Group
41675	      businessObject.categoryValueRef = categoryValue;
41676	    }
41677	  });
41678
41679
41680	  this.revert('shape.create', function(event) {
41681
41682	    var context = event.context,
41683	        shape = context.shape;
41684
41685	    if (is$1(shape, 'bpmn:Group')) {
41686	      removeReferencedCategoryValue(shape);
41687
41688	      delete getBusinessObject(shape).categoryValueRef;
41689
41690	    }
41691	  });
41692
41693	  // copy bpmn:CategoryValue when copying element
41694	  eventBus.on('moddleCopy.canCopyProperty', HIGH_PRIORITY$9, function(context) {
41695	    var property = context.property,
41696	        categoryValue;
41697
41698	    if (is$1(property, 'bpmn:CategoryValue')) {
41699	      categoryValue = createCategoryValue(getDefinitions(), bpmnFactory);
41700
41701	      // return copy of category
41702	      return moddleCopy.copyElement(property, categoryValue);
41703	    }
41704	  });
41705
41706	}
41707
41708	GroupBehavior.$inject = [
41709	  'bpmnFactory',
41710	  'canvas',
41711	  'elementRegistry',
41712	  'eventBus',
41713	  'injector',
41714	  'moddleCopy'
41715	];
41716
41717	inherits$1(GroupBehavior, CommandInterceptor);
41718
41719	/**
41720	 * Returns the intersection between two line segments a and b.
41721	 *
41722	 * @param {Point} l1s
41723	 * @param {Point} l1e
41724	 * @param {Point} l2s
41725	 * @param {Point} l2e
41726	 *
41727	 * @return {Point}
41728	 */
41729	function lineIntersect(l1s, l1e, l2s, l2e) {
41730
41731	  // if the lines intersect, the result contains the x and y of the
41732	  // intersection (treating the lines as infinite) and booleans for
41733	  // whether line segment 1 or line segment 2 contain the point
41734	  var denominator, a, b, c, numerator;
41735
41736	  denominator = ((l2e.y - l2s.y) * (l1e.x - l1s.x)) - ((l2e.x - l2s.x) * (l1e.y - l1s.y));
41737
41738	  if (denominator == 0) {
41739	    return null;
41740	  }
41741
41742	  a = l1s.y - l2s.y;
41743	  b = l1s.x - l2s.x;
41744	  numerator = ((l2e.x - l2s.x) * a) - ((l2e.y - l2s.y) * b);
41745
41746	  c = numerator / denominator;
41747
41748	  // if we cast these lines infinitely in
41749	  // both directions, they intersect here
41750	  return {
41751	    x: Math.round(l1s.x + (c * (l1e.x - l1s.x))),
41752	    y: Math.round(l1s.y + (c * (l1e.y - l1s.y)))
41753	  };
41754	}
41755
41756	/**
41757	 * Fix broken dockings after DI imports.
41758	 *
41759	 * @param {EventBus} eventBus
41760	 */
41761	function ImportDockingFix(eventBus) {
41762
41763	  function adjustDocking(startPoint, nextPoint, elementMid) {
41764
41765	    var elementTop = {
41766	      x: elementMid.x,
41767	      y: elementMid.y - 50
41768	    };
41769
41770	    var elementLeft = {
41771	      x: elementMid.x - 50,
41772	      y: elementMid.y
41773	    };
41774
41775	    var verticalIntersect = lineIntersect(startPoint, nextPoint, elementMid, elementTop),
41776	        horizontalIntersect = lineIntersect(startPoint, nextPoint, elementMid, elementLeft);
41777
41778	    // original is horizontal or vertical center cross intersection
41779	    var centerIntersect;
41780
41781	    if (verticalIntersect && horizontalIntersect) {
41782	      if (getDistance$1(verticalIntersect, elementMid) > getDistance$1(horizontalIntersect, elementMid)) {
41783	        centerIntersect = horizontalIntersect;
41784	      } else {
41785	        centerIntersect = verticalIntersect;
41786	      }
41787	    } else {
41788	      centerIntersect = verticalIntersect || horizontalIntersect;
41789	    }
41790
41791	    startPoint.original = centerIntersect;
41792	  }
41793
41794	  function fixDockings(connection) {
41795	    var waypoints = connection.waypoints;
41796
41797	    adjustDocking(
41798	      waypoints[0],
41799	      waypoints[1],
41800	      getMid(connection.source)
41801	    );
41802
41803	    adjustDocking(
41804	      waypoints[waypoints.length - 1],
41805	      waypoints[waypoints.length - 2],
41806	      getMid(connection.target)
41807	    );
41808	  }
41809
41810	  eventBus.on('bpmnElement.added', function(e) {
41811
41812	    var element = e.element;
41813
41814	    if (element.waypoints) {
41815	      fixDockings(element);
41816	    }
41817	  });
41818	}
41819
41820	ImportDockingFix.$inject = [
41821	  'eventBus'
41822	];
41823
41824
41825	// helpers //////////////////////
41826
41827	function getDistance$1(p1, p2) {
41828	  return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
41829	}
41830
41831	/**
41832	 * A component that makes sure that each created or updated
41833	 * Pool and Lane is assigned an isHorizontal property set to true.
41834	 *
41835	 * @param {EventBus} eventBus
41836	 */
41837	function IsHorizontalFix(eventBus) {
41838
41839	  CommandInterceptor.call(this, eventBus);
41840
41841	  var elementTypesToUpdate = [
41842	    'bpmn:Participant',
41843	    'bpmn:Lane'
41844	  ];
41845
41846	  this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], function(event) {
41847	    var bo = getBusinessObject(event.context.shape);
41848
41849	    if (isAny(bo, elementTypesToUpdate) && !bo.di.get('isHorizontal')) {
41850
41851	      // set attribute directly to avoid modeling#updateProperty side effects
41852	      bo.di.set('isHorizontal', true);
41853	    }
41854	  });
41855
41856	}
41857
41858	IsHorizontalFix.$inject = [ 'eventBus' ];
41859
41860	inherits$1(IsHorizontalFix, CommandInterceptor);
41861
41862	/**
41863	 * Returns the length of a vector
41864	 *
41865	 * @param {Vector}
41866	 * @return {Float}
41867	 */
41868	function vectorLength(v) {
41869	  return Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
41870	}
41871
41872
41873	/**
41874	 * Calculates the angle between a line a the yAxis
41875	 *
41876	 * @param {Array}
41877	 * @return {Float}
41878	 */
41879	function getAngle(line) {
41880
41881	  // return value is between 0, 180 and -180, -0
41882	  // @janstuemmel: maybe replace return a/b with b/a
41883	  return Math.atan((line[1].y - line[0].y) / (line[1].x - line[0].x));
41884	}
41885
41886
41887	/**
41888	 * Rotates a vector by a given angle
41889	 *
41890	 * @param {Vector}
41891	 * @param {Float} Angle in radians
41892	 * @return {Vector}
41893	 */
41894	function rotateVector(vector, angle) {
41895	  return (!angle) ? vector : {
41896	    x: Math.cos(angle) * vector.x - Math.sin(angle) * vector.y,
41897	    y: Math.sin(angle) * vector.x + Math.cos(angle) * vector.y
41898	  };
41899	}
41900
41901
41902	/**
41903	 * Solves a 2D equation system
41904	 * a + r*b = c, where a,b,c are 2D vectors
41905	 *
41906	 * @param {Vector}
41907	 * @param {Vector}
41908	 * @param {Vector}
41909	 * @return {Float}
41910	 */
41911	function solveLambaSystem(a, b, c) {
41912
41913	  // the 2d system
41914	  var system = [
41915	    { n: a[0] - c[0], lambda: b[0] },
41916	    { n: a[1] - c[1], lambda: b[1] }
41917	  ];
41918
41919	  // solve
41920	  var n = system[0].n * b[0] + system[1].n * b[1],
41921	      l = system[0].lambda * b[0] + system[1].lambda * b[1];
41922
41923	  return -n/l;
41924	}
41925
41926
41927	/**
41928	 * Position of perpendicular foot
41929	 *
41930	 * @param {Point}
41931	 * @param [ {Point}, {Point} ] line defined through two points
41932	 * @return {Point} the perpendicular foot position
41933	 */
41934	function perpendicularFoot(point, line) {
41935
41936	  var a = line[0], b = line[1];
41937
41938	  // relative position of b from a
41939	  var bd = { x: b.x - a.x, y: b.y - a.y };
41940
41941	  // solve equation system to the parametrized vectors param real value
41942	  var r = solveLambaSystem([ a.x, a.y ], [ bd.x, bd.y ], [ point.x, point.y ]);
41943
41944	  return { x: a.x + r*bd.x, y: a.y + r*bd.y };
41945	}
41946
41947
41948	/**
41949	 * Calculates the distance between a point and a line
41950	 *
41951	 * @param {Point}
41952	 * @param [ {Point}, {Point} ] line defined through two points
41953	 * @return {Float} distance
41954	 */
41955	function getDistancePointLine(point, line) {
41956
41957	  var pfPoint = perpendicularFoot(point, line);
41958
41959	  // distance vector
41960	  var connectionVector = {
41961	    x: pfPoint.x - point.x,
41962	    y: pfPoint.y - point.y
41963	  };
41964
41965	  return vectorLength(connectionVector);
41966	}
41967
41968
41969	/**
41970	 * Calculates the distance between two points
41971	 *
41972	 * @param {Point}
41973	 * @param {Point}
41974	 * @return {Float} distance
41975	 */
41976	function getDistancePointPoint(point1, point2) {
41977
41978	  return vectorLength({
41979	    x: point1.x - point2.x,
41980	    y: point1.y - point2.y
41981	  });
41982	}
41983
41984	var sqrt = Math.sqrt,
41985	    min$1 = Math.min,
41986	    max$3 = Math.max,
41987	    abs$3 = Math.abs;
41988
41989	/**
41990	 * Calculate the square (power to two) of a number.
41991	 *
41992	 * @param {number} n
41993	 *
41994	 * @return {number}
41995	 */
41996	function sq(n) {
41997	  return Math.pow(n, 2);
41998	}
41999
42000	/**
42001	 * Get distance between two points.
42002	 *
42003	 * @param {Point} p1
42004	 * @param {Point} p2
42005	 *
42006	 * @return {number}
42007	 */
42008	function getDistance(p1, p2) {
42009	  return sqrt(sq(p1.x - p2.x) + sq(p1.y - p2.y));
42010	}
42011
42012	/**
42013	 * Return the attachment of the given point on the specified line.
42014	 *
42015	 * The attachment is either a bendpoint (attached to the given point)
42016	 * or segment (attached to a location on a line segment) attachment:
42017	 *
42018	 * ```javascript
42019	 * var pointAttachment = {
42020	 *   type: 'bendpoint',
42021	 *   bendpointIndex: 3,
42022	 *   position: { x: 10, y: 10 } // the attach point on the line
42023	 * };
42024	 *
42025	 * var segmentAttachment = {
42026	 *   type: 'segment',
42027	 *   segmentIndex: 2,
42028	 *   relativeLocation: 0.31, // attach point location between 0 (at start) and 1 (at end)
42029	 *   position: { x: 10, y: 10 } // the attach point on the line
42030	 * };
42031	 * ```
42032	 *
42033	 * @param {Point} point
42034	 * @param {Array<Point>} line
42035	 *
42036	 * @return {Object} attachment
42037	 */
42038	function getAttachment(point, line) {
42039
42040	  var idx = 0,
42041	      segmentStart,
42042	      segmentEnd,
42043	      segmentStartDistance,
42044	      segmentEndDistance,
42045	      attachmentPosition,
42046	      minDistance,
42047	      intersections,
42048	      attachment,
42049	      attachmentDistance,
42050	      closestAttachmentDistance,
42051	      closestAttachment;
42052
42053	  for (idx = 0; idx < line.length - 1; idx++) {
42054
42055	    segmentStart = line[idx];
42056	    segmentEnd = line[idx + 1];
42057
42058	    if (pointsEqual(segmentStart, segmentEnd)) {
42059	      intersections = [ segmentStart ];
42060	    } else {
42061	      segmentStartDistance = getDistance(point, segmentStart);
42062	      segmentEndDistance = getDistance(point, segmentEnd);
42063
42064	      minDistance = min$1(segmentStartDistance, segmentEndDistance);
42065
42066	      intersections = getCircleSegmentIntersections(segmentStart, segmentEnd, point, minDistance);
42067	    }
42068
42069	    if (intersections.length < 1) {
42070	      throw new Error('expected between [1, 2] circle -> line intersections');
42071	    }
42072
42073	    // one intersection -> bendpoint attachment
42074	    if (intersections.length === 1) {
42075	      attachment = {
42076	        type: 'bendpoint',
42077	        position: intersections[0],
42078	        segmentIndex: idx,
42079	        bendpointIndex: pointsEqual(segmentStart, intersections[0]) ? idx : idx + 1
42080	      };
42081	    }
42082
42083	    // two intersections -> segment attachment
42084	    if (intersections.length === 2) {
42085
42086	      attachmentPosition = mid$1(intersections[0], intersections[1]);
42087
42088	      attachment = {
42089	        type: 'segment',
42090	        position: attachmentPosition,
42091	        segmentIndex: idx,
42092	        relativeLocation: getDistance(segmentStart, attachmentPosition) / getDistance(segmentStart, segmentEnd)
42093	      };
42094	    }
42095
42096	    attachmentDistance = getDistance(attachment.position, point);
42097
42098	    if (!closestAttachment || closestAttachmentDistance > attachmentDistance) {
42099	      closestAttachment = attachment;
42100	      closestAttachmentDistance = attachmentDistance;
42101	    }
42102	  }
42103
42104	  return closestAttachment;
42105	}
42106
42107	/**
42108	 * Gets the intersection between a circle and a line segment.
42109	 *
42110	 * @param {Point} s1 segment start
42111	 * @param {Point} s2 segment end
42112	 * @param {Point} cc circle center
42113	 * @param {number} cr circle radius
42114	 *
42115	 * @return {Array<Point>} intersections
42116	 */
42117	function getCircleSegmentIntersections(s1, s2, cc, cr) {
42118
42119	  var baX = s2.x - s1.x;
42120	  var baY = s2.y - s1.y;
42121	  var caX = cc.x - s1.x;
42122	  var caY = cc.y - s1.y;
42123
42124	  var a = baX * baX + baY * baY;
42125	  var bBy2 = baX * caX + baY * caY;
42126	  var c = caX * caX + caY * caY - cr * cr;
42127
42128	  var pBy2 = bBy2 / a;
42129	  var q = c / a;
42130
42131	  var disc = pBy2 * pBy2 - q;
42132
42133	  // check against negative value to work around
42134	  // negative, very close to zero results (-4e-15)
42135	  // being produced in some environments
42136	  if (disc < 0 && disc > -0.000001) {
42137	    disc = 0;
42138	  }
42139
42140	  if (disc < 0) {
42141	    return [];
42142	  }
42143
42144	  // if disc == 0 ... dealt with later
42145	  var tmpSqrt = sqrt(disc);
42146	  var abScalingFactor1 = -pBy2 + tmpSqrt;
42147	  var abScalingFactor2 = -pBy2 - tmpSqrt;
42148
42149	  var i1 = {
42150	    x: s1.x - baX * abScalingFactor1,
42151	    y: s1.y - baY * abScalingFactor1
42152	  };
42153
42154	  if (disc === 0) { // abScalingFactor1 == abScalingFactor2
42155	    return [ i1 ];
42156	  }
42157
42158	  var i2 = {
42159	    x: s1.x - baX * abScalingFactor2,
42160	    y: s1.y - baY * abScalingFactor2
42161	  };
42162
42163	  // return only points on line segment
42164	  return [ i1, i2 ].filter(function(p) {
42165	    return isPointInSegment(p, s1, s2);
42166	  });
42167	}
42168
42169
42170	function isPointInSegment(p, segmentStart, segmentEnd) {
42171	  return (
42172	    fenced(p.x, segmentStart.x, segmentEnd.x) &&
42173	    fenced(p.y, segmentStart.y, segmentEnd.y)
42174	  );
42175	}
42176
42177	function fenced(n, rangeStart, rangeEnd) {
42178
42179	  // use matching threshold to work around
42180	  // precision errors in intersection computation
42181
42182	  return (
42183	    n >= min$1(rangeStart, rangeEnd) - EQUAL_THRESHOLD &&
42184	    n <= max$3(rangeStart, rangeEnd) + EQUAL_THRESHOLD
42185	  );
42186	}
42187
42188	/**
42189	 * Calculate mid of two points.
42190	 *
42191	 * @param {Point} p1
42192	 * @param {Point} p2
42193	 *
42194	 * @return {Point}
42195	 */
42196	function mid$1(p1, p2) {
42197
42198	  return {
42199	    x: (p1.x + p2.x) / 2,
42200	    y: (p1.y + p2.y) / 2
42201	  };
42202	}
42203
42204	var EQUAL_THRESHOLD = 0.1;
42205
42206	function pointsEqual(p1, p2) {
42207
42208	  return (
42209	    abs$3(p1.x - p2.x) <= EQUAL_THRESHOLD &&
42210	    abs$3(p1.y - p2.y) <= EQUAL_THRESHOLD
42211	  );
42212	}
42213
42214	function findNewLabelLineStartIndex(oldWaypoints, newWaypoints, attachment, hints) {
42215
42216	  var index = attachment.segmentIndex;
42217
42218	  var offset = newWaypoints.length - oldWaypoints.length;
42219
42220	  // segmentMove happened
42221	  if (hints.segmentMove) {
42222
42223	    var oldSegmentStartIndex = hints.segmentMove.segmentStartIndex,
42224	        newSegmentStartIndex = hints.segmentMove.newSegmentStartIndex;
42225
42226	    // if label was on moved segment return new segment index
42227	    if (index === oldSegmentStartIndex) {
42228	      return newSegmentStartIndex;
42229	    }
42230
42231	    // label is after new segment index
42232	    if (index >= newSegmentStartIndex) {
42233	      return (index+offset < newSegmentStartIndex) ? newSegmentStartIndex : index+offset;
42234	    }
42235
42236	    // if label is before new segment index
42237	    return index;
42238	  }
42239
42240	  // bendpointMove happened
42241	  if (hints.bendpointMove) {
42242
42243	    var insert = hints.bendpointMove.insert,
42244	        bendpointIndex = hints.bendpointMove.bendpointIndex,
42245	        newIndex;
42246
42247	    // waypoints length didnt change
42248	    if (offset === 0) {
42249	      return index;
42250	    }
42251
42252	    // label behind new/removed bendpoint
42253	    if (index >= bendpointIndex) {
42254	      newIndex = insert ? index + 1 : index - 1;
42255	    }
42256
42257	    // label before new/removed bendpoint
42258	    if (index < bendpointIndex) {
42259
42260	      newIndex = index;
42261
42262	      // decide label should take right or left segment
42263	      if (insert && attachment.type !== 'bendpoint' && bendpointIndex-1 === index) {
42264
42265	        var rel = relativePositionMidWaypoint(newWaypoints, bendpointIndex);
42266
42267	        if (rel < attachment.relativeLocation) {
42268	          newIndex++;
42269	        }
42270	      }
42271	    }
42272
42273	    return newIndex;
42274	  }
42275
42276	  // start/end changed
42277	  if (offset === 0) {
42278	    return index;
42279	  }
42280
42281	  if (hints.connectionStart) {
42282	    return (index === 0) ? 0 : null;
42283	  }
42284
42285	  if (hints.connectionEnd) {
42286	    return (index === oldWaypoints.length - 2) ? newWaypoints.length - 2 : null;
42287	  }
42288
42289	  // if nothing fits, return null
42290	  return null;
42291	}
42292
42293
42294	/**
42295	 * Calculate the required adjustment (move delta) for the given label
42296	 * after the connection waypoints got updated.
42297	 *
42298	 * @param {djs.model.Label} label
42299	 * @param {Array<Point>} newWaypoints
42300	 * @param {Array<Point>} oldWaypoints
42301	 * @param {Object} hints
42302	 *
42303	 * @return {Point} delta
42304	 */
42305	function getLabelAdjustment(label, newWaypoints, oldWaypoints, hints) {
42306
42307	  var x = 0,
42308	      y = 0;
42309
42310	  var labelPosition = getLabelMid(label);
42311
42312	  // get closest attachment
42313	  var attachment = getAttachment(labelPosition, oldWaypoints),
42314	      oldLabelLineIndex = attachment.segmentIndex,
42315	      newLabelLineIndex = findNewLabelLineStartIndex(oldWaypoints, newWaypoints, attachment, hints);
42316
42317	  if (newLabelLineIndex === null) {
42318	    return { x: x, y: y };
42319	  }
42320
42321	  // should never happen
42322	  // TODO(@janstuemmel): throw an error here when connectionSegmentMove is refactored
42323	  if (newLabelLineIndex < 0 ||
42324	      newLabelLineIndex > newWaypoints.length - 2) {
42325	    return { x: x, y: y };
42326	  }
42327
42328	  var oldLabelLine = getLine(oldWaypoints, oldLabelLineIndex),
42329	      newLabelLine = getLine(newWaypoints, newLabelLineIndex),
42330	      oldFoot = attachment.position;
42331
42332	  var relativeFootPosition = getRelativeFootPosition(oldLabelLine, oldFoot),
42333	      angleDelta = getAngleDelta(oldLabelLine, newLabelLine);
42334
42335	  // special rule if label on bendpoint
42336	  if (attachment.type === 'bendpoint') {
42337
42338	    var offset = newWaypoints.length - oldWaypoints.length,
42339	        oldBendpointIndex = attachment.bendpointIndex,
42340	        oldBendpoint = oldWaypoints[oldBendpointIndex];
42341
42342	    // bendpoint position hasn't changed, return same position
42343	    if (newWaypoints.indexOf(oldBendpoint) !== -1) {
42344	      return { x: x, y: y };
42345	    }
42346
42347	    // new bendpoint and old bendpoint have same index, then just return the offset
42348	    if (offset === 0) {
42349	      var newBendpoint = newWaypoints[oldBendpointIndex];
42350
42351	      return {
42352	        x: newBendpoint.x - attachment.position.x,
42353	        y: newBendpoint.y - attachment.position.y
42354	      };
42355	    }
42356
42357	    // if bendpoints get removed
42358	    if (offset < 0 && oldBendpointIndex !== 0 && oldBendpointIndex < oldWaypoints.length - 1) {
42359	      relativeFootPosition = relativePositionMidWaypoint(oldWaypoints, oldBendpointIndex);
42360	    }
42361	  }
42362
42363	  var newFoot = {
42364	    x: (newLabelLine[1].x - newLabelLine[0].x) * relativeFootPosition + newLabelLine[0].x,
42365	    y: (newLabelLine[1].y - newLabelLine[0].y) * relativeFootPosition + newLabelLine[0].y
42366	  };
42367
42368	  // the rotated vector to label
42369	  var newLabelVector = rotateVector({
42370	    x: labelPosition.x - oldFoot.x,
42371	    y: labelPosition.y - oldFoot.y
42372	  }, angleDelta);
42373
42374	  // the new relative position
42375	  x = newFoot.x + newLabelVector.x - labelPosition.x;
42376	  y = newFoot.y + newLabelVector.y - labelPosition.y;
42377
42378	  return roundPoint({
42379	    x: x,
42380	    y: y
42381	  });
42382	}
42383
42384
42385	// HELPERS //////////////////////
42386
42387	function relativePositionMidWaypoint(waypoints, idx) {
42388
42389	  var distanceSegment1 = getDistancePointPoint(waypoints[idx-1], waypoints[idx]),
42390	      distanceSegment2 = getDistancePointPoint(waypoints[idx], waypoints[idx+1]);
42391
42392	  var relativePosition = distanceSegment1 / (distanceSegment1 + distanceSegment2);
42393
42394	  return relativePosition;
42395	}
42396
42397	function getLabelMid(label) {
42398	  return {
42399	    x: label.x + label.width / 2,
42400	    y: label.y + label.height / 2
42401	  };
42402	}
42403
42404	function getAngleDelta(l1, l2) {
42405	  var a1 = getAngle(l1),
42406	      a2 = getAngle(l2);
42407	  return a2 - a1;
42408	}
42409
42410	function getLine(waypoints, idx) {
42411	  return [ waypoints[idx], waypoints[idx+1] ];
42412	}
42413
42414	function getRelativeFootPosition(line, foot) {
42415
42416	  var length = getDistancePointPoint(line[0], line[1]),
42417	      lengthToFoot = getDistancePointPoint(line[0], foot);
42418
42419	  return length === 0 ? 0 : lengthToFoot / length;
42420	}
42421
42422	/**
42423	 * Calculates the absolute point relative to the new element's position
42424	 *
42425	 * @param {point} point [absolute]
42426	 * @param {bounds} oldBounds
42427	 * @param {bounds} newBounds
42428	 *
42429	 * @return {point} point [absolute]
42430	 */
42431	function getNewAttachPoint(point, oldBounds, newBounds) {
42432	  var oldCenter = center(oldBounds),
42433	      newCenter = center(newBounds),
42434	      oldDelta = delta(point, oldCenter);
42435
42436	  var newDelta = {
42437	    x: oldDelta.x * (newBounds.width / oldBounds.width),
42438	    y: oldDelta.y * (newBounds.height / oldBounds.height)
42439	  };
42440
42441	  return roundPoint({
42442	    x: newCenter.x + newDelta.x,
42443	    y: newCenter.y + newDelta.y
42444	  });
42445	}
42446
42447
42448	/**
42449	 * Calculates the shape's delta relative to a new position
42450	 * of a certain element's bounds
42451	 *
42452	 * @param {djs.model.Shape} point [absolute]
42453	 * @param {bounds} oldBounds
42454	 * @param {bounds} newBounds
42455	 *
42456	 * @return {delta} delta
42457	 */
42458	function getNewAttachShapeDelta(shape, oldBounds, newBounds) {
42459	  var shapeCenter = center(shape),
42460	      oldCenter = center(oldBounds),
42461	      newCenter = center(newBounds),
42462	      shapeDelta = delta(shape, shapeCenter),
42463	      oldCenterDelta = delta(shapeCenter, oldCenter),
42464	      stickyPositionDelta = getStickyPositionDelta(shapeCenter, oldBounds, newBounds);
42465
42466	  if (stickyPositionDelta) {
42467	    return stickyPositionDelta;
42468	  }
42469
42470	  var newCenterDelta = {
42471	    x: oldCenterDelta.x * (newBounds.width / oldBounds.width),
42472	    y: oldCenterDelta.y * (newBounds.height / oldBounds.height)
42473	  };
42474
42475	  var newShapeCenter = {
42476	    x: newCenter.x + newCenterDelta.x,
42477	    y: newCenter.y + newCenterDelta.y
42478	  };
42479
42480	  return roundPoint({
42481	    x: newShapeCenter.x + shapeDelta.x - shape.x,
42482	    y: newShapeCenter.y + shapeDelta.y - shape.y
42483	  });
42484	}
42485
42486	function getStickyPositionDelta(oldShapeCenter, oldBounds, newBounds) {
42487	  var oldTRBL = asTRBL(oldBounds),
42488	      newTRBL = asTRBL(newBounds);
42489
42490	  if (isMoved(oldTRBL, newTRBL)) {
42491	    return null;
42492	  }
42493
42494	  var oldOrientation = getOrientation(oldBounds, oldShapeCenter),
42495	      stickyPositionDelta,
42496	      newShapeCenter,
42497	      newOrientation;
42498
42499	  if (oldOrientation === 'top') {
42500	    stickyPositionDelta = {
42501	      x: 0,
42502	      y: newTRBL.bottom - oldTRBL.bottom
42503	    };
42504	  } else if (oldOrientation === 'bottom') {
42505	    stickyPositionDelta = {
42506	      x: 0,
42507	      y: newTRBL.top - oldTRBL.top
42508	    };
42509	  } else if (oldOrientation === 'right') {
42510	    stickyPositionDelta = {
42511	      x: newTRBL.left - oldTRBL.left,
42512	      y: 0
42513	    };
42514	  } else if (oldOrientation === 'left') {
42515	    stickyPositionDelta = {
42516	      x: newTRBL.right - oldTRBL.right,
42517	      y: 0
42518	    };
42519	  } else {
42520
42521	    // fallback to proportional movement for corner-placed attachments
42522	    return null;
42523	  }
42524
42525	  newShapeCenter = {
42526	    x: oldShapeCenter.x + stickyPositionDelta.x,
42527	    y: oldShapeCenter.y + stickyPositionDelta.y
42528	  };
42529
42530	  newOrientation = getOrientation(newBounds, newShapeCenter);
42531
42532	  if (newOrientation !== oldOrientation) {
42533
42534	    // fallback to proportional movement if orientation would otherwise change
42535	    return null;
42536	  }
42537
42538	  return stickyPositionDelta;
42539	}
42540
42541	function isMoved(oldTRBL, newTRBL) {
42542	  return isHorizontallyMoved(oldTRBL, newTRBL) || isVerticallyMoved(oldTRBL, newTRBL);
42543	}
42544
42545	function isHorizontallyMoved(oldTRBL, newTRBL) {
42546	  return oldTRBL.right !== newTRBL.right && oldTRBL.left !== newTRBL.left;
42547	}
42548
42549	function isVerticallyMoved(oldTRBL, newTRBL) {
42550	  return oldTRBL.top !== newTRBL.top && oldTRBL.bottom !== newTRBL.bottom;
42551	}
42552
42553	var DEFAULT_LABEL_DIMENSIONS = {
42554	  width: 90,
42555	  height: 20
42556	};
42557
42558	var NAME_PROPERTY = 'name';
42559	var TEXT_PROPERTY = 'text';
42560
42561	/**
42562	 * A component that makes sure that external labels are added
42563	 * together with respective elements and properly updated (DI wise)
42564	 * during move.
42565	 *
42566	 * @param {EventBus} eventBus
42567	 * @param {Modeling} modeling
42568	 * @param {BpmnFactory} bpmnFactory
42569	 * @param {TextRenderer} textRenderer
42570	 */
42571	function LabelBehavior(
42572	    eventBus, modeling, bpmnFactory,
42573	    textRenderer) {
42574
42575	  CommandInterceptor.call(this, eventBus);
42576
42577	  // update label if name property was updated
42578	  this.postExecute('element.updateProperties', function(e) {
42579	    var context = e.context,
42580	        element = context.element,
42581	        properties = context.properties;
42582
42583	    if (NAME_PROPERTY in properties) {
42584	      modeling.updateLabel(element, properties[NAME_PROPERTY]);
42585	    }
42586
42587	    if (TEXT_PROPERTY in properties
42588	        && is$1(element, 'bpmn:TextAnnotation')) {
42589
42590	      var newBounds = textRenderer.getTextAnnotationBounds(
42591	        {
42592	          x: element.x,
42593	          y: element.y,
42594	          width: element.width,
42595	          height: element.height
42596	        },
42597	        properties[TEXT_PROPERTY] || ''
42598	      );
42599
42600	      modeling.updateLabel(element, properties.text, newBounds);
42601	    }
42602	  });
42603
42604	  // create label shape after shape/connection was created
42605	  this.postExecute([ 'shape.create', 'connection.create' ], function(e) {
42606	    var context = e.context,
42607	        hints = context.hints || {};
42608
42609	    if (hints.createElementsBehavior === false) {
42610	      return;
42611	    }
42612
42613	    var element = context.shape || context.connection,
42614	        businessObject = element.businessObject;
42615
42616	    if (isLabel$6(element) || !isLabelExternal(element)) {
42617	      return;
42618	    }
42619
42620	    // only create label if attribute available
42621	    if (!getLabel(element)) {
42622	      return;
42623	    }
42624
42625	    var labelCenter = getExternalLabelMid(element);
42626
42627	    // we don't care about x and y
42628	    var labelDimensions = textRenderer.getExternalLabelBounds(
42629	      DEFAULT_LABEL_DIMENSIONS,
42630	      getLabel(element)
42631	    );
42632
42633	    modeling.createLabel(element, labelCenter, {
42634	      id: businessObject.id + '_label',
42635	      businessObject: businessObject,
42636	      width: labelDimensions.width,
42637	      height: labelDimensions.height
42638	    });
42639	  });
42640
42641	  // update label after label shape was deleted
42642	  this.postExecute('shape.delete', function(event) {
42643	    var context = event.context,
42644	        labelTarget = context.labelTarget,
42645	        hints = context.hints || {};
42646
42647	    // check if label
42648	    if (labelTarget && hints.unsetLabel !== false) {
42649	      modeling.updateLabel(labelTarget, null, null, { removeShape: false });
42650	    }
42651	  });
42652
42653	  // update di information on label creation
42654	  this.postExecute([ 'label.create' ], function(event) {
42655
42656	    var context = event.context,
42657	        element = context.shape,
42658	        businessObject,
42659	        di;
42660
42661	    // we want to trigger on real labels only
42662	    if (!element.labelTarget) {
42663	      return;
42664	    }
42665
42666	    // we want to trigger on BPMN elements only
42667	    if (!is$1(element.labelTarget || element, 'bpmn:BaseElement')) {
42668	      return;
42669	    }
42670
42671	    businessObject = element.businessObject,
42672	    di = businessObject.di;
42673
42674
42675	    if (!di.label) {
42676	      di.label = bpmnFactory.create('bpmndi:BPMNLabel', {
42677	        bounds: bpmnFactory.create('dc:Bounds')
42678	      });
42679	    }
42680
42681	    assign(di.label.bounds, {
42682	      x: element.x,
42683	      y: element.y,
42684	      width: element.width,
42685	      height: element.height
42686	    });
42687	  });
42688
42689	  function getVisibleLabelAdjustment(event) {
42690
42691	    var context = event.context,
42692	        connection = context.connection,
42693	        label = connection.label,
42694	        hints = assign({}, context.hints),
42695	        newWaypoints = context.newWaypoints || connection.waypoints,
42696	        oldWaypoints = context.oldWaypoints;
42697
42698
42699	    if (typeof hints.startChanged === 'undefined') {
42700	      hints.startChanged = !!hints.connectionStart;
42701	    }
42702
42703	    if (typeof hints.endChanged === 'undefined') {
42704	      hints.endChanged = !!hints.connectionEnd;
42705	    }
42706
42707	    return getLabelAdjustment(label, newWaypoints, oldWaypoints, hints);
42708	  }
42709
42710	  this.postExecute([
42711	    'connection.layout',
42712	    'connection.updateWaypoints'
42713	  ], function(event) {
42714	    var context = event.context,
42715	        hints = context.hints || {};
42716
42717	    if (hints.labelBehavior === false) {
42718	      return;
42719	    }
42720
42721	    var connection = context.connection,
42722	        label = connection.label,
42723	        labelAdjustment;
42724
42725	    // handle missing label as well as the case
42726	    // that the label parent does not exist (yet),
42727	    // because it is being pasted / created via multi element create
42728	    //
42729	    // Cf. https://github.com/bpmn-io/bpmn-js/pull/1227
42730	    if (!label || !label.parent) {
42731	      return;
42732	    }
42733
42734	    labelAdjustment = getVisibleLabelAdjustment(event);
42735
42736	    modeling.moveShape(label, labelAdjustment);
42737	  });
42738
42739
42740	  // keep label position on shape replace
42741	  this.postExecute([ 'shape.replace' ], function(event) {
42742	    var context = event.context,
42743	        newShape = context.newShape,
42744	        oldShape = context.oldShape;
42745
42746	    var businessObject = getBusinessObject(newShape);
42747
42748	    if (businessObject
42749	      && isLabelExternal(businessObject)
42750	      && oldShape.label
42751	      && newShape.label) {
42752	      newShape.label.x = oldShape.label.x;
42753	      newShape.label.y = oldShape.label.y;
42754	    }
42755	  });
42756
42757
42758	  // move external label after resizing
42759	  this.postExecute('shape.resize', function(event) {
42760
42761	    var context = event.context,
42762	        shape = context.shape,
42763	        newBounds = context.newBounds,
42764	        oldBounds = context.oldBounds;
42765
42766	    if (hasExternalLabel(shape)) {
42767
42768	      var label = shape.label,
42769	          labelMid = getMid(label),
42770	          edges = asEdges(oldBounds);
42771
42772	      // get nearest border point to label as reference point
42773	      var referencePoint = getReferencePoint(labelMid, edges);
42774
42775	      var delta = getReferencePointDelta(referencePoint, oldBounds, newBounds);
42776
42777	      modeling.moveShape(label, delta);
42778
42779	    }
42780
42781	  });
42782
42783	}
42784
42785	inherits$1(LabelBehavior, CommandInterceptor);
42786
42787	LabelBehavior.$inject = [
42788	  'eventBus',
42789	  'modeling',
42790	  'bpmnFactory',
42791	  'textRenderer'
42792	];
42793
42794	// helpers //////////////////////
42795
42796	/**
42797	 * Calculates a reference point delta relative to a new position
42798	 * of a certain element's bounds
42799	 *
42800	 * @param {Point} point
42801	 * @param {Bounds} oldBounds
42802	 * @param {Bounds} newBounds
42803	 *
42804	 * @return {Delta} delta
42805	 */
42806	function getReferencePointDelta(referencePoint, oldBounds, newBounds) {
42807
42808	  var newReferencePoint = getNewAttachPoint(referencePoint, oldBounds, newBounds);
42809
42810	  return roundPoint(delta(newReferencePoint, referencePoint));
42811	}
42812
42813	/**
42814	 * Generates the nearest point (reference point) for a given point
42815	 * onto given set of lines
42816	 *
42817	 * @param {Array<Point, Point>} lines
42818	 * @param {Point} point
42819	 *
42820	 * @param {Point}
42821	 */
42822	function getReferencePoint(point, lines) {
42823
42824	  if (!lines.length) {
42825	    return;
42826	  }
42827
42828	  var nearestLine = getNearestLine(point, lines);
42829
42830	  return perpendicularFoot(point, nearestLine);
42831	}
42832
42833	/**
42834	 * Convert the given bounds to a lines array containing all edges
42835	 *
42836	 * @param {Bounds|Point} bounds
42837	 *
42838	 * @return Array<Point>
42839	 */
42840	function asEdges(bounds) {
42841	  return [
42842	    [ // top
42843	      {
42844	        x: bounds.x,
42845	        y: bounds.y
42846	      },
42847	      {
42848	        x: bounds.x + (bounds.width || 0),
42849	        y: bounds.y
42850	      }
42851	    ],
42852	    [ // right
42853	      {
42854	        x: bounds.x + (bounds.width || 0),
42855	        y: bounds.y
42856	      },
42857	      {
42858	        x: bounds.x + (bounds.width || 0),
42859	        y: bounds.y + (bounds.height || 0)
42860	      }
42861	    ],
42862	    [ // bottom
42863	      {
42864	        x: bounds.x,
42865	        y: bounds.y + (bounds.height || 0)
42866	      },
42867	      {
42868	        x: bounds.x + (bounds.width || 0),
42869	        y: bounds.y + (bounds.height || 0)
42870	      }
42871	    ],
42872	    [ // left
42873	      {
42874	        x: bounds.x,
42875	        y: bounds.y
42876	      },
42877	      {
42878	        x: bounds.x,
42879	        y: bounds.y + (bounds.height || 0)
42880	      }
42881	    ]
42882	  ];
42883	}
42884
42885	/**
42886	 * Returns the nearest line for a given point by distance
42887	 * @param {Point} point
42888	 * @param Array<Point> lines
42889	 *
42890	 * @return Array<Point>
42891	 */
42892	function getNearestLine(point, lines) {
42893
42894	  var distances = lines.map(function(l) {
42895	    return {
42896	      line: l,
42897	      distance: getDistancePointLine(point, l)
42898	    };
42899	  });
42900
42901	  var sorted = sortBy(distances, 'distance');
42902
42903	  return sorted[0].line;
42904	}
42905
42906	function getResizedSourceAnchor(connection, shape, oldBounds) {
42907
42908	  var waypoints = safeGetWaypoints(connection),
42909	      waypointsInsideNewBounds = getWaypointsInsideBounds(waypoints, shape),
42910	      oldAnchor = waypoints[0];
42911
42912	  // new anchor is the last waypoint enclosed be resized source
42913	  if (waypointsInsideNewBounds.length) {
42914	    return waypointsInsideNewBounds[ waypointsInsideNewBounds.length - 1 ];
42915	  }
42916
42917	  return getNewAttachPoint(oldAnchor.original || oldAnchor, oldBounds, shape);
42918	}
42919
42920
42921	function getResizedTargetAnchor(connection, shape, oldBounds) {
42922
42923	  var waypoints = safeGetWaypoints(connection),
42924	      waypointsInsideNewBounds = getWaypointsInsideBounds(waypoints, shape),
42925	      oldAnchor = waypoints[waypoints.length - 1];
42926
42927	  // new anchor is the first waypoint enclosed be resized target
42928	  if (waypointsInsideNewBounds.length) {
42929	    return waypointsInsideNewBounds[ 0 ];
42930	  }
42931
42932	  return getNewAttachPoint(oldAnchor.original || oldAnchor, oldBounds, shape);
42933	}
42934
42935
42936	function getMovedSourceAnchor(connection, source, moveDelta) {
42937
42938	  var waypoints = safeGetWaypoints(connection),
42939	      oldBounds = subtract(source, moveDelta),
42940	      oldAnchor = waypoints[ 0 ];
42941
42942	  return getNewAttachPoint(oldAnchor.original || oldAnchor, oldBounds, source);
42943	}
42944
42945
42946	function getMovedTargetAnchor(connection, target, moveDelta) {
42947
42948	  var waypoints = safeGetWaypoints(connection),
42949	      oldBounds = subtract(target, moveDelta),
42950	      oldAnchor = waypoints[ waypoints.length - 1 ];
42951
42952	  return getNewAttachPoint(oldAnchor.original || oldAnchor, oldBounds, target);
42953	}
42954
42955
42956	// helpers //////////////////////
42957
42958	function subtract(bounds, delta) {
42959	  return {
42960	    x: bounds.x - delta.x,
42961	    y: bounds.y - delta.y,
42962	    width: bounds.width,
42963	    height: bounds.height
42964	  };
42965	}
42966
42967
42968	/**
42969	 * Return waypoints of given connection; throw if non exists (should not happen!!).
42970	 *
42971	 * @param {Connection} connection
42972	 *
42973	 * @return {Array<Point>}
42974	 */
42975	function safeGetWaypoints(connection) {
42976
42977	  var waypoints = connection.waypoints;
42978
42979	  if (!waypoints.length) {
42980	    throw new Error('connection#' + connection.id + ': no waypoints');
42981	  }
42982
42983	  return waypoints;
42984	}
42985
42986	function getWaypointsInsideBounds(waypoints, bounds) {
42987	  var originalWaypoints = map$1(waypoints, getOriginal);
42988
42989	  return filter(originalWaypoints, function(waypoint) {
42990	    return isInsideBounds(waypoint, bounds);
42991	  });
42992	}
42993
42994	/**
42995	 * Checks if point is inside bounds, incl. edges.
42996	 *
42997	 * @param {Point} point
42998	 * @param {Bounds} bounds
42999	 */
43000	function isInsideBounds(point, bounds) {
43001	  return getOrientation(bounds, point, 1) === 'intersect';
43002	}
43003
43004	function getOriginal(point) {
43005	  return point.original || point;
43006	}
43007
43008	/**
43009	 * BPMN-specific message flow behavior.
43010	 */
43011	function MessageFlowBehavior(eventBus, modeling) {
43012
43013	  CommandInterceptor.call(this, eventBus);
43014
43015	  this.postExecute('shape.replace', function(context) {
43016	    var oldShape = context.oldShape,
43017	        newShape = context.newShape;
43018
43019	    if (!isParticipantCollapse(oldShape, newShape)) {
43020	      return;
43021	    }
43022
43023	    var messageFlows = getMessageFlows(oldShape);
43024
43025	    messageFlows.incoming.forEach(function(incoming) {
43026	      var anchor = getResizedTargetAnchor(incoming, newShape, oldShape);
43027
43028	      modeling.reconnectEnd(incoming, newShape, anchor);
43029	    });
43030
43031	    messageFlows.outgoing.forEach(function(outgoing) {
43032	      var anchor = getResizedSourceAnchor(outgoing, newShape, oldShape);
43033
43034	      modeling.reconnectStart(outgoing, newShape, anchor);
43035	    });
43036	  }, true);
43037
43038	}
43039
43040	MessageFlowBehavior.$inject = [ 'eventBus', 'modeling' ];
43041
43042	inherits$1(MessageFlowBehavior, CommandInterceptor);
43043
43044	// helpers //////////
43045
43046	function isParticipantCollapse(oldShape, newShape) {
43047	  return is$1(oldShape, 'bpmn:Participant')
43048	    && isExpanded(oldShape)
43049	    && is$1(newShape, 'bpmn:Participant')
43050	    && !isExpanded(newShape);
43051	}
43052
43053	function getMessageFlows(parent) {
43054	  var elements = selfAndAllChildren([ parent ], false);
43055
43056	  var incoming = [],
43057	      outgoing = [];
43058
43059	  elements.forEach(function(element) {
43060	    if (element === parent) {
43061	      return;
43062	    }
43063
43064	    element.incoming.forEach(function(connection) {
43065	      if (is$1(connection, 'bpmn:MessageFlow')) {
43066	        incoming.push(connection);
43067	      }
43068	    });
43069
43070	    element.outgoing.forEach(function(connection) {
43071	      if (is$1(connection, 'bpmn:MessageFlow')) {
43072	        outgoing.push(connection);
43073	      }
43074	    });
43075	  }, []);
43076
43077	  return {
43078	    incoming: incoming,
43079	    outgoing: outgoing
43080	  };
43081	}
43082
43083	var COLLAB_ERR_MSG = 'flow elements must be children of pools/participants';
43084
43085	function ModelingFeedback(eventBus, tooltips, translate) {
43086
43087	  function showError(position, message, timeout) {
43088	    tooltips.add({
43089	      position: {
43090	        x: position.x + 5,
43091	        y: position.y + 5
43092	      },
43093	      type: 'error',
43094	      timeout: timeout || 2000,
43095	      html: '<div>' + message + '</div>'
43096	    });
43097	  }
43098
43099	  eventBus.on([ 'shape.move.rejected', 'create.rejected' ], function(event) {
43100	    var context = event.context,
43101	        shape = context.shape,
43102	        target = context.target;
43103
43104	    if (is$1(target, 'bpmn:Collaboration') && is$1(shape, 'bpmn:FlowNode')) {
43105	      showError(event, translate(COLLAB_ERR_MSG));
43106	    }
43107	  });
43108
43109	}
43110
43111	ModelingFeedback.$inject = [
43112	  'eventBus',
43113	  'tooltips',
43114	  'translate'
43115	];
43116
43117	function ReplaceConnectionBehavior(eventBus, modeling, bpmnRules, injector) {
43118
43119	  CommandInterceptor.call(this, eventBus);
43120
43121	  var dragging = injector.get('dragging', false);
43122
43123	  function fixConnection(connection) {
43124
43125	    var source = connection.source,
43126	        target = connection.target,
43127	        parent = connection.parent;
43128
43129	    // do not do anything if connection
43130	    // is already deleted (may happen due to other
43131	    // behaviors plugged-in before)
43132	    if (!parent) {
43133	      return;
43134	    }
43135
43136	    var replacementType,
43137	        remove;
43138
43139	    /**
43140	     * Check if incoming or outgoing connections
43141	     * can stay or could be substituted with an
43142	     * appropriate replacement.
43143	     *
43144	     * This holds true for SequenceFlow <> MessageFlow.
43145	     */
43146
43147	    if (is$1(connection, 'bpmn:SequenceFlow')) {
43148	      if (!bpmnRules.canConnectSequenceFlow(source, target)) {
43149	        remove = true;
43150	      }
43151
43152	      if (bpmnRules.canConnectMessageFlow(source, target)) {
43153	        replacementType = 'bpmn:MessageFlow';
43154	      }
43155	    }
43156
43157	    // transform message flows into sequence flows, if possible
43158
43159	    if (is$1(connection, 'bpmn:MessageFlow')) {
43160
43161	      if (!bpmnRules.canConnectMessageFlow(source, target)) {
43162	        remove = true;
43163	      }
43164
43165	      if (bpmnRules.canConnectSequenceFlow(source, target)) {
43166	        replacementType = 'bpmn:SequenceFlow';
43167	      }
43168	    }
43169
43170	    if (is$1(connection, 'bpmn:Association') && !bpmnRules.canConnectAssociation(source, target)) {
43171	      remove = true;
43172	    }
43173
43174
43175	    // remove invalid connection,
43176	    // unless it has been removed already
43177	    if (remove) {
43178	      modeling.removeConnection(connection);
43179	    }
43180
43181	    // replace SequenceFlow <> MessageFlow
43182
43183	    if (replacementType) {
43184	      modeling.connect(source, target, {
43185	        type: replacementType,
43186	        waypoints: connection.waypoints.slice()
43187	      });
43188	    }
43189	  }
43190
43191	  function replaceReconnectedConnection(event) {
43192
43193	    var context = event.context,
43194	        connection = context.connection,
43195	        source = context.newSource || connection.source,
43196	        target = context.newTarget || connection.target,
43197	        allowed,
43198	        replacement;
43199
43200	    allowed = bpmnRules.canConnect(source, target);
43201
43202	    if (!allowed || allowed.type === connection.type) {
43203	      return;
43204	    }
43205
43206	    replacement = modeling.connect(source, target, {
43207	      type: allowed.type,
43208	      waypoints: connection.waypoints.slice()
43209	    });
43210
43211	    // remove old connection
43212	    modeling.removeConnection(connection);
43213
43214	    // replace connection in context to reconnect end/start
43215	    context.connection = replacement;
43216
43217	    if (dragging) {
43218	      cleanDraggingSelection(connection, replacement);
43219	    }
43220	  }
43221
43222	  // monkey-patch selection saved in dragging in order to re-select it when operation is finished
43223	  function cleanDraggingSelection(oldConnection, newConnection) {
43224	    var context = dragging.context(),
43225	        previousSelection = context && context.payload.previousSelection,
43226	        index;
43227
43228	    // do nothing if not dragging or no selection was present
43229	    if (!previousSelection || !previousSelection.length) {
43230	      return;
43231	    }
43232
43233	    index = previousSelection.indexOf(oldConnection);
43234
43235	    if (index === -1) {
43236	      return;
43237	    }
43238
43239	    previousSelection.splice(index, 1, newConnection);
43240	  }
43241
43242	  // lifecycle hooks
43243
43244	  this.postExecuted('elements.move', function(context) {
43245
43246	    var closure = context.closure,
43247	        allConnections = closure.allConnections;
43248
43249	    forEach(allConnections, fixConnection);
43250	  }, true);
43251
43252	  this.preExecute('connection.reconnect', replaceReconnectedConnection);
43253
43254	  this.postExecuted('element.updateProperties', function(event) {
43255	    var context = event.context,
43256	        properties = context.properties,
43257	        element = context.element,
43258	        businessObject = element.businessObject,
43259	        connection;
43260
43261	    // remove condition on change to default
43262	    if (properties.default) {
43263	      connection = find(
43264	        element.outgoing,
43265	        matchPattern({ id: element.businessObject.default.id })
43266	      );
43267
43268	      if (connection) {
43269	        modeling.updateProperties(connection, { conditionExpression: undefined });
43270	      }
43271	    }
43272
43273	    // remove default from source on change to conditional
43274	    if (properties.conditionExpression && businessObject.sourceRef.default === businessObject) {
43275	      modeling.updateProperties(element.source, { default: undefined });
43276	    }
43277	  });
43278	}
43279
43280	inherits$1(ReplaceConnectionBehavior, CommandInterceptor);
43281
43282	ReplaceConnectionBehavior.$inject = [
43283	  'eventBus',
43284	  'modeling',
43285	  'bpmnRules',
43286	  'injector'
43287	];
43288
43289	/**
43290	 * BPMN specific remove behavior
43291	 */
43292	function RemoveParticipantBehavior(eventBus, modeling) {
43293
43294	  CommandInterceptor.call(this, eventBus);
43295
43296
43297	  /**
43298	   * morph collaboration diagram into process diagram
43299	   * after the last participant has been removed
43300	   */
43301
43302	  this.preExecute('shape.delete', function(context) {
43303
43304	    var shape = context.shape,
43305	        parent = shape.parent;
43306
43307	    // activate the behavior if the shape to be removed
43308	    // is a participant
43309	    if (is$1(shape, 'bpmn:Participant')) {
43310	      context.collaborationRoot = parent;
43311	    }
43312	  }, true);
43313
43314	  this.postExecute('shape.delete', function(context) {
43315
43316	    var collaborationRoot = context.collaborationRoot;
43317
43318	    if (collaborationRoot && !collaborationRoot.businessObject.participants.length) {
43319
43320	      // replace empty collaboration with process diagram
43321	      modeling.makeProcess();
43322	    }
43323	  }, true);
43324
43325	}
43326
43327	RemoveParticipantBehavior.$inject = [ 'eventBus', 'modeling' ];
43328
43329	inherits$1(RemoveParticipantBehavior, CommandInterceptor);
43330
43331	/**
43332	 * BPMN-specific replace behavior.
43333	 */
43334	function ReplaceElementBehaviour(
43335	    bpmnReplace,
43336	    bpmnRules,
43337	    elementRegistry,
43338	    injector,
43339	    modeling,
43340	    selection
43341	) {
43342	  injector.invoke(CommandInterceptor, this);
43343
43344	  this._bpmnReplace = bpmnReplace;
43345	  this._elementRegistry = elementRegistry;
43346	  this._selection = selection;
43347
43348	  // replace elements on create, e.g. during copy-paste
43349	  this.postExecuted([ 'elements.create' ], 500, function(event) {
43350	    var context = event.context,
43351	        target = context.parent,
43352	        elements = context.elements;
43353
43354	    var canReplace = bpmnRules.canReplace(elements, target);
43355
43356	    if (canReplace) {
43357	      this.replaceElements(elements, canReplace.replacements);
43358	    }
43359	  }, this);
43360
43361	  // replace elements on move
43362	  this.postExecuted([ 'elements.move' ], 500, function(event) {
43363	    var context = event.context,
43364	        target = context.newParent,
43365	        newHost = context.newHost,
43366	        elements = [];
43367
43368	    forEach(context.closure.topLevel, function(topLevelElements) {
43369	      if (isEventSubProcess(topLevelElements)) {
43370	        elements = elements.concat(topLevelElements.children);
43371	      } else {
43372	        elements = elements.concat(topLevelElements);
43373	      }
43374	    });
43375
43376	    // set target to host if attaching
43377	    if (elements.length === 1 && newHost) {
43378	      target = newHost;
43379	    }
43380
43381	    var canReplace = bpmnRules.canReplace(elements, target);
43382
43383	    if (canReplace) {
43384	      this.replaceElements(elements, canReplace.replacements, newHost);
43385	    }
43386	  }, this);
43387
43388	  // update attachments on host replace
43389	  this.postExecute([ 'shape.replace' ], 1500, function(e) {
43390	    var context = e.context,
43391	        oldShape = context.oldShape,
43392	        newShape = context.newShape,
43393	        attachers = oldShape.attachers,
43394	        canReplace;
43395
43396	    if (attachers && attachers.length) {
43397	      canReplace = bpmnRules.canReplace(attachers, newShape);
43398
43399	      this.replaceElements(attachers, canReplace.replacements);
43400	    }
43401
43402	  }, this);
43403
43404	  // keep ID on shape replace
43405	  this.postExecuted([ 'shape.replace' ], 1500, function(e) {
43406	    var context = e.context,
43407	        oldShape = context.oldShape,
43408	        newShape = context.newShape;
43409
43410	    modeling.unclaimId(oldShape.businessObject.id, oldShape.businessObject);
43411	    modeling.updateProperties(newShape, { id: oldShape.id });
43412	  });
43413	}
43414
43415	inherits$1(ReplaceElementBehaviour, CommandInterceptor);
43416
43417	ReplaceElementBehaviour.prototype.replaceElements = function(elements, newElements) {
43418	  var elementRegistry = this._elementRegistry,
43419	      bpmnReplace = this._bpmnReplace,
43420	      selection = this._selection;
43421
43422	  forEach(newElements, function(replacement) {
43423	    var newElement = {
43424	      type: replacement.newElementType
43425	    };
43426
43427	    var oldElement = elementRegistry.get(replacement.oldElementId);
43428
43429	    var idx = elements.indexOf(oldElement);
43430
43431	    elements[idx] = bpmnReplace.replaceElement(oldElement, newElement, { select: false });
43432	  });
43433
43434	  if (newElements) {
43435	    selection.select(elements);
43436	  }
43437	};
43438
43439	ReplaceElementBehaviour.$inject = [
43440	  'bpmnReplace',
43441	  'bpmnRules',
43442	  'elementRegistry',
43443	  'injector',
43444	  'modeling',
43445	  'selection'
43446	];
43447
43448	var HIGH_PRIORITY$8 = 1500;
43449
43450	var LANE_MIN_DIMENSIONS = { width: 300, height: 60 };
43451
43452	var PARTICIPANT_MIN_DIMENSIONS = { width: 300, height: 150 };
43453
43454	var SUB_PROCESS_MIN_DIMENSIONS = { width: 140, height: 120 };
43455
43456	var TEXT_ANNOTATION_MIN_DIMENSIONS = { width: 50, height: 30 };
43457
43458	/**
43459	 * Set minimum bounds/resize constraints on resize.
43460	 *
43461	 * @param {EventBus} eventBus
43462	 */
43463	function ResizeBehavior(eventBus) {
43464	  eventBus.on('resize.start', HIGH_PRIORITY$8, function(event) {
43465	    var context = event.context,
43466	        shape = context.shape,
43467	        direction = context.direction,
43468	        balanced = context.balanced;
43469
43470	    if (is$1(shape, 'bpmn:Lane') || is$1(shape, 'bpmn:Participant')) {
43471	      context.resizeConstraints = getParticipantResizeConstraints(shape, direction, balanced);
43472	    }
43473
43474	    if (is$1(shape, 'bpmn:Participant')) {
43475	      context.minDimensions = PARTICIPANT_MIN_DIMENSIONS;
43476	    }
43477
43478	    if (is$1(shape, 'bpmn:SubProcess') && isExpanded(shape)) {
43479	      context.minDimensions = SUB_PROCESS_MIN_DIMENSIONS;
43480	    }
43481
43482	    if (is$1(shape, 'bpmn:TextAnnotation')) {
43483	      context.minDimensions = TEXT_ANNOTATION_MIN_DIMENSIONS;
43484	    }
43485	  });
43486	}
43487
43488	ResizeBehavior.$inject = [ 'eventBus' ];
43489
43490
43491	var abs$2 = Math.abs,
43492	    min = Math.min,
43493	    max$2 = Math.max;
43494
43495
43496	function addToTrbl(trbl, attr, value, choice) {
43497	  var current = trbl[attr];
43498
43499	  // make sure to set the value if it does not exist
43500	  // or apply the correct value by comparing against
43501	  // choice(value, currentValue)
43502	  trbl[attr] = current === undefined ? value : choice(value, current);
43503	}
43504
43505	function addMin(trbl, attr, value) {
43506	  return addToTrbl(trbl, attr, value, min);
43507	}
43508
43509	function addMax(trbl, attr, value) {
43510	  return addToTrbl(trbl, attr, value, max$2);
43511	}
43512
43513	var LANE_RIGHT_PADDING = 20,
43514	    LANE_LEFT_PADDING = 50,
43515	    LANE_TOP_PADDING = 20,
43516	    LANE_BOTTOM_PADDING = 20;
43517
43518	function getParticipantResizeConstraints(laneShape, resizeDirection, balanced) {
43519	  var lanesRoot = getLanesRoot(laneShape);
43520
43521	  var isFirst = true,
43522	      isLast = true;
43523
43524	  // max top/bottom size for lanes
43525	  var allLanes = collectLanes(lanesRoot, [ lanesRoot ]);
43526
43527	  var laneTrbl = asTRBL(laneShape);
43528
43529	  var maxTrbl = {},
43530	      minTrbl = {};
43531
43532	  if (/e/.test(resizeDirection)) {
43533	    minTrbl.right = laneTrbl.left + LANE_MIN_DIMENSIONS.width;
43534	  } else
43535	  if (/w/.test(resizeDirection)) {
43536	    minTrbl.left = laneTrbl.right - LANE_MIN_DIMENSIONS.width;
43537	  }
43538
43539	  allLanes.forEach(function(other) {
43540
43541	    var otherTrbl = asTRBL(other);
43542
43543	    if (/n/.test(resizeDirection)) {
43544
43545	      if (otherTrbl.top < (laneTrbl.top - 10)) {
43546	        isFirst = false;
43547	      }
43548
43549	      // max top size (based on next element)
43550	      if (balanced && abs$2(laneTrbl.top - otherTrbl.bottom) < 10) {
43551	        addMax(maxTrbl, 'top', otherTrbl.top + LANE_MIN_DIMENSIONS.height);
43552	      }
43553
43554	      // min top size (based on self or nested element)
43555	      if (abs$2(laneTrbl.top - otherTrbl.top) < 5) {
43556	        addMin(minTrbl, 'top', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height);
43557	      }
43558	    }
43559
43560	    if (/s/.test(resizeDirection)) {
43561
43562	      if (otherTrbl.bottom > (laneTrbl.bottom + 10)) {
43563	        isLast = false;
43564	      }
43565
43566	      // max bottom size (based on previous element)
43567	      if (balanced && abs$2(laneTrbl.bottom - otherTrbl.top) < 10) {
43568	        addMin(maxTrbl, 'bottom', otherTrbl.bottom - LANE_MIN_DIMENSIONS.height);
43569	      }
43570
43571	      // min bottom size (based on self or nested element)
43572	      if (abs$2(laneTrbl.bottom - otherTrbl.bottom) < 5) {
43573	        addMax(minTrbl, 'bottom', otherTrbl.top + LANE_MIN_DIMENSIONS.height);
43574	      }
43575	    }
43576	  });
43577
43578	  // max top/bottom/left/right size based on flow nodes
43579	  var flowElements = lanesRoot.children.filter(function(s) {
43580	    return !s.hidden && !s.waypoints && (is$1(s, 'bpmn:FlowElement') || is$1(s, 'bpmn:Artifact'));
43581	  });
43582
43583	  flowElements.forEach(function(flowElement) {
43584
43585	    var flowElementTrbl = asTRBL(flowElement);
43586
43587	    if (isFirst && /n/.test(resizeDirection)) {
43588	      addMin(minTrbl, 'top', flowElementTrbl.top - LANE_TOP_PADDING);
43589	    }
43590
43591	    if (/e/.test(resizeDirection)) {
43592	      addMax(minTrbl, 'right', flowElementTrbl.right + LANE_RIGHT_PADDING);
43593	    }
43594
43595	    if (isLast && /s/.test(resizeDirection)) {
43596	      addMax(minTrbl, 'bottom', flowElementTrbl.bottom + LANE_BOTTOM_PADDING);
43597	    }
43598
43599	    if (/w/.test(resizeDirection)) {
43600	      addMin(minTrbl, 'left', flowElementTrbl.left - LANE_LEFT_PADDING);
43601	    }
43602	  });
43603
43604	  return {
43605	    min: minTrbl,
43606	    max: maxTrbl
43607	  };
43608	}
43609
43610	var SLIGHTLY_HIGHER_PRIORITY = 1001;
43611
43612
43613	/**
43614	 * Invoke {@link Modeling#resizeLane} instead of
43615	 * {@link Modeling#resizeShape} when resizing a Lane
43616	 * or Participant shape.
43617	 */
43618	function ResizeLaneBehavior(eventBus, modeling) {
43619
43620	  eventBus.on('resize.start', SLIGHTLY_HIGHER_PRIORITY + 500, function(event) {
43621	    var context = event.context,
43622	        shape = context.shape;
43623
43624	    if (is$1(shape, 'bpmn:Lane') || is$1(shape, 'bpmn:Participant')) {
43625
43626	      // should we resize the opposite lane(s) in
43627	      // order to compensate for the resize operation?
43628	      context.balanced = !hasPrimaryModifier(event);
43629	    }
43630	  });
43631
43632	  /**
43633	   * Intercept resize end and call resize lane function instead.
43634	   */
43635	  eventBus.on('resize.end', SLIGHTLY_HIGHER_PRIORITY, function(event) {
43636	    var context = event.context,
43637	        shape = context.shape,
43638	        canExecute = context.canExecute,
43639	        newBounds = context.newBounds;
43640
43641	    if (is$1(shape, 'bpmn:Lane') || is$1(shape, 'bpmn:Participant')) {
43642
43643	      if (canExecute) {
43644
43645	        // ensure we have actual pixel values for new bounds
43646	        // (important when zoom level was > 1 during move)
43647	        newBounds = roundBounds(newBounds);
43648
43649	        // perform the actual resize
43650	        modeling.resizeLane(shape, newBounds, context.balanced);
43651	      }
43652
43653	      // stop propagation
43654	      return false;
43655	    }
43656	  });
43657	}
43658
43659	ResizeLaneBehavior.$inject = [
43660	  'eventBus',
43661	  'modeling'
43662	];
43663
43664	function RemoveElementBehavior(eventBus, bpmnRules, modeling) {
43665
43666	  CommandInterceptor.call(this, eventBus);
43667
43668	  /**
43669	   * Combine sequence flows when deleting an element
43670	   * if there is one incoming and one outgoing
43671	   * sequence flow
43672	   */
43673	  this.preExecute('shape.delete', function(e) {
43674
43675	    var shape = e.context.shape;
43676
43677	    // only handle [a] -> [shape] -> [b] patterns
43678	    if (shape.incoming.length !== 1 || shape.outgoing.length !== 1) {
43679	      return;
43680	    }
43681
43682	    var inConnection = shape.incoming[0],
43683	        outConnection = shape.outgoing[0];
43684
43685	    // only handle sequence flows
43686	    if (!is$1(inConnection, 'bpmn:SequenceFlow') || !is$1(outConnection, 'bpmn:SequenceFlow')) {
43687	      return;
43688	    }
43689
43690	    if (bpmnRules.canConnect(inConnection.source, outConnection.target, inConnection)) {
43691
43692	      // compute new, combined waypoints
43693	      var newWaypoints = getNewWaypoints(inConnection.waypoints, outConnection.waypoints);
43694
43695	      modeling.reconnectEnd(inConnection, outConnection.target, newWaypoints);
43696	    }
43697	  });
43698
43699	}
43700
43701	inherits$1(RemoveElementBehavior, CommandInterceptor);
43702
43703	RemoveElementBehavior.$inject = [
43704	  'eventBus',
43705	  'bpmnRules',
43706	  'modeling'
43707	];
43708
43709
43710	// helpers //////////////////////
43711
43712	function getDocking$1(point) {
43713	  return point.original || point;
43714	}
43715
43716
43717	function getNewWaypoints(inWaypoints, outWaypoints) {
43718
43719	  var intersection = lineIntersect(
43720	    getDocking$1(inWaypoints[inWaypoints.length - 2]),
43721	    getDocking$1(inWaypoints[inWaypoints.length - 1]),
43722	    getDocking$1(outWaypoints[1]),
43723	    getDocking$1(outWaypoints[0]));
43724
43725	  if (intersection) {
43726	    return [].concat(
43727	      inWaypoints.slice(0, inWaypoints.length - 1),
43728	      [ intersection ],
43729	      outWaypoints.slice(1));
43730	  } else {
43731	    return [
43732	      getDocking$1(inWaypoints[0]),
43733	      getDocking$1(outWaypoints[outWaypoints.length - 1])
43734	    ];
43735	  }
43736	}
43737
43738	var max$1 = Math.max;
43739
43740
43741	function SpaceToolBehavior(eventBus) {
43742	  eventBus.on('spaceTool.getMinDimensions', function(context) {
43743	    var shapes = context.shapes,
43744	        axis = context.axis,
43745	        start = context.start,
43746	        minDimensions = {};
43747
43748	    forEach(shapes, function(shape) {
43749	      var id = shape.id;
43750
43751	      if (is$1(shape, 'bpmn:Participant')) {
43752
43753	        if (isHorizontal$1(axis)) {
43754	          minDimensions[ id ] = PARTICIPANT_MIN_DIMENSIONS;
43755	        } else {
43756	          minDimensions[ id ] = {
43757	            width: PARTICIPANT_MIN_DIMENSIONS.width,
43758	            height: getParticipantMinHeight(shape, start)
43759	          };
43760	        }
43761
43762	      }
43763
43764	      if (is$1(shape, 'bpmn:SubProcess') && isExpanded(shape)) {
43765	        minDimensions[ id ] = SUB_PROCESS_MIN_DIMENSIONS;
43766	      }
43767
43768	      if (is$1(shape, 'bpmn:TextAnnotation')) {
43769	        minDimensions[ id ] = TEXT_ANNOTATION_MIN_DIMENSIONS;
43770	      }
43771	    });
43772
43773	    return minDimensions;
43774	  });
43775	}
43776
43777	SpaceToolBehavior.$inject = [ 'eventBus' ];
43778
43779
43780	// helpers //////////
43781	function isHorizontal$1(axis) {
43782	  return axis === 'x';
43783	}
43784
43785	/**
43786	 * Get minimum height for participant taking lanes into account.
43787	 *
43788	 * @param {<djs.model.Shape>} participant
43789	 * @param {number} start
43790	 *
43791	 * @returns {Object}
43792	 */
43793	function getParticipantMinHeight(participant, start) {
43794	  var lanesMinHeight;
43795
43796	  if (!hasChildLanes(participant)) {
43797	    return PARTICIPANT_MIN_DIMENSIONS.height;
43798	  }
43799
43800	  lanesMinHeight = getLanesMinHeight(participant, start);
43801
43802	  return max$1(PARTICIPANT_MIN_DIMENSIONS.height, lanesMinHeight);
43803	}
43804
43805	function hasChildLanes(element) {
43806	  return !!getChildLanes(element).length;
43807	}
43808
43809	function getLanesMinHeight(participant, resizeStart) {
43810	  var lanes = getChildLanes(participant),
43811	      resizedLane;
43812
43813	  // find the nested lane which is currently resized
43814	  resizedLane = findResizedLane(lanes, resizeStart);
43815
43816	  // resized lane cannot shrink below the minimum height
43817	  // but remaining lanes' dimensions are kept intact
43818	  return participant.height - resizedLane.height + LANE_MIN_DIMENSIONS.height;
43819	}
43820
43821	/**
43822	 * Find nested lane which is currently resized.
43823	 *
43824	 * @param {Array<djs.model.Shape>} lanes
43825	 * @param {number} resizeStart
43826	 */
43827	function findResizedLane(lanes, resizeStart) {
43828	  var i, lane, childLanes;
43829
43830	  for (i = 0; i < lanes.length; i++) {
43831	    lane = lanes[i];
43832
43833	    // resizing current lane or a lane nested
43834	    if (resizeStart >= lane.y && resizeStart <= lane.y + lane.height) {
43835	      childLanes = getChildLanes(lane);
43836
43837	      // a nested lane is resized
43838	      if (childLanes.length) {
43839	        return findResizedLane(childLanes, resizeStart);
43840	      }
43841
43842	      // current lane is the resized one
43843	      return lane;
43844	    }
43845	  }
43846	}
43847
43848	/**
43849	 * Add start event replacing element with expanded sub process.
43850	 *
43851	 * @param {Injector} injector
43852	 * @param {Modeling} modeling
43853	 */
43854	function SubProcessStartEventBehavior(injector, modeling) {
43855	  injector.invoke(CommandInterceptor, this);
43856
43857	  this.postExecuted('shape.replace', function(event) {
43858	    var oldShape = event.context.oldShape,
43859	        newShape = event.context.newShape;
43860
43861	    if (
43862	      !is$1(newShape, 'bpmn:SubProcess') ||
43863	      !is$1(oldShape, 'bpmn:Task') ||
43864	      !isExpanded(newShape)
43865	    ) {
43866	      return;
43867	    }
43868
43869	    var position = getStartEventPosition(newShape);
43870
43871	    modeling.createShape({ type: 'bpmn:StartEvent' }, position, newShape);
43872	  });
43873	}
43874
43875	SubProcessStartEventBehavior.$inject = [
43876	  'injector',
43877	  'modeling'
43878	];
43879
43880	inherits$1(SubProcessStartEventBehavior, CommandInterceptor);
43881
43882	// helpers //////////
43883
43884	function getStartEventPosition(shape) {
43885	  return {
43886	    x: shape.x + shape.width / 6,
43887	    y: shape.y + shape.height / 2
43888	  };
43889	}
43890
43891	var LOW_PRIORITY$8 = 500;
43892
43893
43894	function ToggleElementCollapseBehaviour(
43895	    eventBus, elementFactory, modeling,
43896	    resize) {
43897
43898	  CommandInterceptor.call(this, eventBus);
43899
43900
43901	  function hideEmptyLabels(children) {
43902	    if (children.length) {
43903	      children.forEach(function(child) {
43904	        if (child.type === 'label' && !child.businessObject.name) {
43905	          child.hidden = true;
43906	        }
43907	      });
43908	    }
43909	  }
43910
43911	  function expandedBounds(shape, defaultSize) {
43912	    var children = shape.children,
43913	        newBounds = defaultSize,
43914	        visibleElements,
43915	        visibleBBox;
43916
43917	    visibleElements = filterVisible(children).concat([ shape ]);
43918
43919	    visibleBBox = computeChildrenBBox(visibleElements);
43920
43921	    if (visibleBBox) {
43922
43923	      // center to visibleBBox with max(defaultSize, childrenBounds)
43924	      newBounds.width = Math.max(visibleBBox.width, newBounds.width);
43925	      newBounds.height = Math.max(visibleBBox.height, newBounds.height);
43926
43927	      newBounds.x = visibleBBox.x + (visibleBBox.width - newBounds.width) / 2;
43928	      newBounds.y = visibleBBox.y + (visibleBBox.height - newBounds.height) / 2;
43929	    } else {
43930
43931	      // center to collapsed shape with defaultSize
43932	      newBounds.x = shape.x + (shape.width - newBounds.width) / 2;
43933	      newBounds.y = shape.y + (shape.height - newBounds.height) / 2;
43934	    }
43935
43936	    return newBounds;
43937	  }
43938
43939	  function collapsedBounds(shape, defaultSize) {
43940
43941	    return {
43942	      x: shape.x + (shape.width - defaultSize.width) / 2,
43943	      y: shape.y + (shape.height - defaultSize.height) / 2,
43944	      width: defaultSize.width,
43945	      height: defaultSize.height
43946	    };
43947	  }
43948
43949	  this.executed([ 'shape.toggleCollapse' ], LOW_PRIORITY$8, function(e) {
43950
43951	    var context = e.context,
43952	        shape = context.shape;
43953
43954	    if (!is$1(shape, 'bpmn:SubProcess')) {
43955	      return;
43956	    }
43957
43958	    if (!shape.collapsed) {
43959
43960	      // all children got made visible through djs, hide empty labels
43961	      hideEmptyLabels(shape.children);
43962
43963	      // remove collapsed marker
43964	      getBusinessObject(shape).di.isExpanded = true;
43965	    } else {
43966
43967	      // place collapsed marker
43968	      getBusinessObject(shape).di.isExpanded = false;
43969	    }
43970	  });
43971
43972	  this.reverted([ 'shape.toggleCollapse' ], LOW_PRIORITY$8, function(e) {
43973
43974	    var context = e.context;
43975	    var shape = context.shape;
43976
43977
43978	    // revert removing/placing collapsed marker
43979	    if (!shape.collapsed) {
43980	      getBusinessObject(shape).di.isExpanded = true;
43981
43982	    } else {
43983	      getBusinessObject(shape).di.isExpanded = false;
43984	    }
43985	  });
43986
43987	  this.postExecuted([ 'shape.toggleCollapse' ], LOW_PRIORITY$8, function(e) {
43988	    var shape = e.context.shape,
43989	        defaultSize = elementFactory._getDefaultSize(shape),
43990	        newBounds;
43991
43992	    if (shape.collapsed) {
43993
43994	      // resize to default size of collapsed shapes
43995	      newBounds = collapsedBounds(shape, defaultSize);
43996	    } else {
43997
43998	      // resize to bounds of max(visible children, defaultSize)
43999	      newBounds = expandedBounds(shape, defaultSize);
44000	    }
44001
44002	    modeling.resizeShape(shape, newBounds, null, {
44003	      autoResize: shape.collapsed ? false : 'nwse'
44004	    });
44005	  });
44006
44007	}
44008
44009
44010	inherits$1(ToggleElementCollapseBehaviour, CommandInterceptor);
44011
44012	ToggleElementCollapseBehaviour.$inject = [
44013	  'eventBus',
44014	  'elementFactory',
44015	  'modeling'
44016	];
44017
44018
44019	// helpers //////////////////////
44020
44021	function filterVisible(elements) {
44022	  return elements.filter(function(e) {
44023	    return !e.hidden;
44024	  });
44025	}
44026
44027	/**
44028	 * Unclaims model IDs on element deletion.
44029	 *
44030	 * @param {Canvas} canvas
44031	 * @param {Injector} injector
44032	 * @param {Moddle} moddle
44033	 * @param {Modeling} modeling
44034	 */
44035	function UnclaimIdBehavior(canvas, injector, moddle, modeling) {
44036	  injector.invoke(CommandInterceptor, this);
44037
44038	  this.preExecute('shape.delete', function(event) {
44039	    var context = event.context,
44040	        shape = context.shape,
44041	        shapeBo = shape.businessObject;
44042
44043	    if (isLabel$6(shape)) {
44044	      return;
44045	    }
44046
44047	    if (is$1(shape, 'bpmn:Participant') && isExpanded(shape)) {
44048	      moddle.ids.unclaim(shapeBo.processRef.id);
44049	    }
44050
44051	    modeling.unclaimId(shapeBo.id, shapeBo);
44052	  });
44053
44054
44055	  this.preExecute('connection.delete', function(event) {
44056	    var context = event.context,
44057	        connection = context.connection,
44058	        connectionBo = connection.businessObject;
44059
44060	    modeling.unclaimId(connectionBo.id, connectionBo);
44061	  });
44062
44063	  this.preExecute('canvas.updateRoot', function() {
44064	    var rootElement = canvas.getRootElement(),
44065	        rootElementBo = rootElement.businessObject;
44066
44067	    moddle.ids.unclaim(rootElementBo.id);
44068	  });
44069	}
44070
44071	inherits$1(UnclaimIdBehavior, CommandInterceptor);
44072
44073	UnclaimIdBehavior.$inject = [ 'canvas', 'injector', 'moddle', 'modeling' ];
44074
44075	var LOW_PRIORITY$7 = 500,
44076	    HIGH_PRIORITY$7 = 5000;
44077
44078
44079	/**
44080	 * BPMN specific delete lane behavior
44081	 */
44082	function UpdateFlowNodeRefsBehavior(eventBus, modeling, translate) {
44083
44084	  CommandInterceptor.call(this, eventBus);
44085
44086	  /**
44087	   * Ok, this is it:
44088	   *
44089	   * We have to update the Lane#flowNodeRefs _and_
44090	   * FlowNode#lanes with every FlowNode move/resize and
44091	   * Lane move/resize.
44092	   *
44093	   * We want to group that stuff to recompute containments
44094	   * as efficient as possible.
44095	   *
44096	   * Yea!
44097	   */
44098
44099	  // the update context
44100	  var context;
44101
44102
44103	  function initContext() {
44104	    context = context || new UpdateContext();
44105	    context.enter();
44106
44107	    return context;
44108	  }
44109
44110	  function getContext() {
44111	    if (!context) {
44112	      throw new Error(translate('out of bounds release'));
44113	    }
44114
44115	    return context;
44116	  }
44117
44118	  function releaseContext() {
44119
44120	    if (!context) {
44121	      throw new Error(translate('out of bounds release'));
44122	    }
44123
44124	    var triggerUpdate = context.leave();
44125
44126	    if (triggerUpdate) {
44127	      modeling.updateLaneRefs(context.flowNodes, context.lanes);
44128
44129	      context = null;
44130	    }
44131
44132	    return triggerUpdate;
44133	  }
44134
44135
44136	  var laneRefUpdateEvents = [
44137	    'spaceTool',
44138	    'lane.add',
44139	    'lane.resize',
44140	    'lane.split',
44141	    'elements.create',
44142	    'elements.delete',
44143	    'elements.move',
44144	    'shape.create',
44145	    'shape.delete',
44146	    'shape.move',
44147	    'shape.resize'
44148	  ];
44149
44150
44151	  // listen to a lot of stuff to group lane updates
44152
44153	  this.preExecute(laneRefUpdateEvents, HIGH_PRIORITY$7, function(event) {
44154	    initContext();
44155	  });
44156
44157	  this.postExecuted(laneRefUpdateEvents, LOW_PRIORITY$7, function(event) {
44158	    releaseContext();
44159	  });
44160
44161
44162	  // Mark flow nodes + lanes that need an update
44163
44164	  this.preExecute([
44165	    'shape.create',
44166	    'shape.move',
44167	    'shape.delete',
44168	    'shape.resize'
44169	  ], function(event) {
44170
44171	    var context = event.context,
44172	        shape = context.shape;
44173
44174	    var updateContext = getContext();
44175
44176	    // no need to update labels
44177	    if (shape.labelTarget) {
44178	      return;
44179	    }
44180
44181	    if (is$1(shape, 'bpmn:Lane')) {
44182	      updateContext.addLane(shape);
44183	    }
44184
44185	    if (is$1(shape, 'bpmn:FlowNode')) {
44186	      updateContext.addFlowNode(shape);
44187	    }
44188	  });
44189	}
44190
44191	UpdateFlowNodeRefsBehavior.$inject = [
44192	  'eventBus',
44193	  'modeling' ,
44194	  'translate'
44195	];
44196
44197	inherits$1(UpdateFlowNodeRefsBehavior, CommandInterceptor);
44198
44199
44200	function UpdateContext() {
44201
44202	  this.flowNodes = [];
44203	  this.lanes = [];
44204
44205	  this.counter = 0;
44206
44207	  this.addLane = function(lane) {
44208	    this.lanes.push(lane);
44209	  };
44210
44211	  this.addFlowNode = function(flowNode) {
44212	    this.flowNodes.push(flowNode);
44213	  };
44214
44215	  this.enter = function() {
44216	    this.counter++;
44217	  };
44218
44219	  this.leave = function() {
44220	    this.counter--;
44221
44222	    return !this.counter;
44223	  };
44224	}
44225
44226	/**
44227	 * A behavior that unsets the Default property of
44228	 * sequence flow source on element delete, if the
44229	 * removed element is the Gateway or Task's default flow.
44230	 *
44231	 * @param {EventBus} eventBus
44232	 * @param {Modeling} modeling
44233	 */
44234	function DeleteSequenceFlowBehavior(eventBus, modeling) {
44235
44236	  CommandInterceptor.call(this, eventBus);
44237
44238
44239	  this.preExecute('connection.delete', function(event) {
44240	    var context = event.context,
44241	        connection = context.connection,
44242	        source = connection.source;
44243
44244	    if (isDefaultFlow(connection, source)) {
44245	      modeling.updateProperties(source, {
44246	        'default': null
44247	      });
44248	    }
44249	  });
44250	}
44251
44252	inherits$1(DeleteSequenceFlowBehavior, CommandInterceptor);
44253
44254	DeleteSequenceFlowBehavior.$inject = [
44255	  'eventBus',
44256	  'modeling'
44257	];
44258
44259
44260	// helpers //////////////////////
44261
44262	function isDefaultFlow(connection, source) {
44263
44264	  if (!is$1(connection, 'bpmn:SequenceFlow')) {
44265	    return false;
44266	  }
44267
44268	  var sourceBo = getBusinessObject(source),
44269	      sequenceFlow = getBusinessObject(connection);
44270
44271	  return sourceBo.get('default') === sequenceFlow;
44272	}
44273
44274	var BehaviorModule = {
44275	  __init__: [
44276	    'adaptiveLabelPositioningBehavior',
44277	    'appendBehavior',
44278	    'associationBehavior',
44279	    'attachEventBehavior',
44280	    'boundaryEventBehavior',
44281	    'rootElementReferenceBehavior',
44282	    'createBehavior',
44283	    'fixHoverBehavior',
44284	    'createDataObjectBehavior',
44285	    'createParticipantBehavior',
44286	    'dataStoreBehavior',
44287	    'dataInputAssociationBehavior',
44288	    'deleteLaneBehavior',
44289	    'detachEventBehavior',
44290	    'dropOnFlowBehavior',
44291	    'eventBasedGatewayBehavior',
44292	    'groupBehavior',
44293	    'importDockingFix',
44294	    'isHorizontalFix',
44295	    'labelBehavior',
44296	    'messageFlowBehavior',
44297	    'modelingFeedback',
44298	    'removeElementBehavior',
44299	    'removeParticipantBehavior',
44300	    'replaceConnectionBehavior',
44301	    'replaceElementBehaviour',
44302	    'resizeBehavior',
44303	    'resizeLaneBehavior',
44304	    'toggleElementCollapseBehaviour',
44305	    'spaceToolBehavior',
44306	    'subProcessStartEventBehavior',
44307	    'unclaimIdBehavior',
44308	    'unsetDefaultFlowBehavior',
44309	    'updateFlowNodeRefsBehavior'
44310	  ],
44311	  adaptiveLabelPositioningBehavior: [ 'type', AdaptiveLabelPositioningBehavior ],
44312	  appendBehavior: [ 'type', AppendBehavior ],
44313	  associationBehavior: [ 'type', AssociationBehavior ],
44314	  attachEventBehavior: [ 'type', AttachEventBehavior ],
44315	  boundaryEventBehavior: [ 'type', BoundaryEventBehavior ],
44316	  rootElementReferenceBehavior: [ 'type', RootElementReferenceBehavior ],
44317	  createBehavior: [ 'type', CreateBehavior ],
44318	  fixHoverBehavior: [ 'type', FixHoverBehavior ],
44319	  createDataObjectBehavior: [ 'type', CreateDataObjectBehavior ],
44320	  createParticipantBehavior: [ 'type', CreateParticipantBehavior ],
44321	  dataInputAssociationBehavior: [ 'type', DataInputAssociationBehavior ],
44322	  dataStoreBehavior: [ 'type', DataStoreBehavior ],
44323	  deleteLaneBehavior: [ 'type', DeleteLaneBehavior ],
44324	  detachEventBehavior: [ 'type', DetachEventBehavior ],
44325	  dropOnFlowBehavior: [ 'type', DropOnFlowBehavior ],
44326	  eventBasedGatewayBehavior: [ 'type', EventBasedGatewayBehavior ],
44327	  groupBehavior: [ 'type', GroupBehavior ],
44328	  importDockingFix: [ 'type', ImportDockingFix ],
44329	  isHorizontalFix: [ 'type', IsHorizontalFix ],
44330	  labelBehavior: [ 'type', LabelBehavior ],
44331	  messageFlowBehavior: [ 'type', MessageFlowBehavior ],
44332	  modelingFeedback: [ 'type', ModelingFeedback ],
44333	  replaceConnectionBehavior: [ 'type', ReplaceConnectionBehavior ],
44334	  removeParticipantBehavior: [ 'type', RemoveParticipantBehavior ],
44335	  replaceElementBehaviour: [ 'type', ReplaceElementBehaviour ],
44336	  resizeBehavior: [ 'type', ResizeBehavior ],
44337	  resizeLaneBehavior: [ 'type', ResizeLaneBehavior ],
44338	  removeElementBehavior: [ 'type', RemoveElementBehavior ],
44339	  toggleElementCollapseBehaviour : [ 'type', ToggleElementCollapseBehaviour ],
44340	  spaceToolBehavior: [ 'type', SpaceToolBehavior ],
44341	  subProcessStartEventBehavior: [ 'type', SubProcessStartEventBehavior ],
44342	  unclaimIdBehavior: [ 'type', UnclaimIdBehavior ],
44343	  updateFlowNodeRefsBehavior: [ 'type', UpdateFlowNodeRefsBehavior ],
44344	  unsetDefaultFlowBehavior: [ 'type', DeleteSequenceFlowBehavior ]
44345	};
44346
44347	function getBoundaryAttachment(position, targetBounds) {
44348
44349	  var orientation = getOrientation(position, targetBounds, -15);
44350
44351	  if (orientation !== 'intersect') {
44352	    return orientation;
44353	  } else {
44354	    return null;
44355	  }
44356	}
44357
44358	/**
44359	 * BPMN specific modeling rule
44360	 */
44361	function BpmnRules(eventBus) {
44362	  RuleProvider.call(this, eventBus);
44363	}
44364
44365	inherits$1(BpmnRules, RuleProvider);
44366
44367	BpmnRules.$inject = [ 'eventBus' ];
44368
44369	BpmnRules.prototype.init = function() {
44370
44371	  this.addRule('connection.start', function(context) {
44372	    var source = context.source;
44373
44374	    return canStartConnection(source);
44375	  });
44376
44377	  this.addRule('connection.create', function(context) {
44378	    var source = context.source,
44379	        target = context.target,
44380	        hints = context.hints || {},
44381	        targetParent = hints.targetParent,
44382	        targetAttach = hints.targetAttach;
44383
44384	    // don't allow incoming connections on
44385	    // newly created boundary events
44386	    // to boundary events
44387	    if (targetAttach) {
44388	      return false;
44389	    }
44390
44391	    // temporarily set target parent for scoping
44392	    // checks to work
44393	    if (targetParent) {
44394	      target.parent = targetParent;
44395	    }
44396
44397	    try {
44398	      return canConnect(source, target);
44399	    } finally {
44400
44401	      // unset temporary target parent
44402	      if (targetParent) {
44403	        target.parent = null;
44404	      }
44405	    }
44406	  });
44407
44408	  this.addRule('connection.reconnect', function(context) {
44409
44410	    var connection = context.connection,
44411	        source = context.source,
44412	        target = context.target;
44413
44414	    return canConnect(source, target, connection);
44415	  });
44416
44417	  this.addRule('connection.updateWaypoints', function(context) {
44418	    return {
44419	      type: context.connection.type
44420	    };
44421	  });
44422
44423	  this.addRule('shape.resize', function(context) {
44424
44425	    var shape = context.shape,
44426	        newBounds = context.newBounds;
44427
44428	    return canResize(shape, newBounds);
44429	  });
44430
44431	  this.addRule('elements.create', function(context) {
44432	    var elements = context.elements,
44433	        position = context.position,
44434	        target = context.target;
44435
44436	    if (isConnection$8(target) && !canInsert(elements, target)) {
44437	      return false;
44438	    }
44439
44440	    return every(elements, function(element) {
44441	      if (isConnection$8(element)) {
44442	        return canConnect(element.source, element.target, element);
44443	      }
44444
44445	      if (element.host) {
44446	        return canAttach(element, element.host, null, position);
44447	      }
44448
44449	      return canCreate(element, target, null);
44450	    });
44451	  });
44452
44453	  this.addRule('elements.move', function(context) {
44454
44455	    var target = context.target,
44456	        shapes = context.shapes,
44457	        position = context.position;
44458
44459	    return canAttach(shapes, target, null, position) ||
44460	           canReplace(shapes, target, position) ||
44461	           canMove(shapes, target) ||
44462	           canInsert(shapes, target);
44463	  });
44464
44465	  this.addRule('shape.create', function(context) {
44466	    return canCreate(
44467	      context.shape,
44468	      context.target,
44469	      context.source,
44470	      context.position
44471	    );
44472	  });
44473
44474	  this.addRule('shape.attach', function(context) {
44475
44476	    return canAttach(
44477	      context.shape,
44478	      context.target,
44479	      null,
44480	      context.position
44481	    );
44482	  });
44483
44484	  this.addRule('element.copy', function(context) {
44485	    var element = context.element,
44486	        elements = context.elements;
44487
44488	    return canCopy(elements, element);
44489	  });
44490	};
44491
44492	BpmnRules.prototype.canConnectMessageFlow = canConnectMessageFlow;
44493
44494	BpmnRules.prototype.canConnectSequenceFlow = canConnectSequenceFlow;
44495
44496	BpmnRules.prototype.canConnectDataAssociation = canConnectDataAssociation;
44497
44498	BpmnRules.prototype.canConnectAssociation = canConnectAssociation;
44499
44500	BpmnRules.prototype.canMove = canMove;
44501
44502	BpmnRules.prototype.canAttach = canAttach;
44503
44504	BpmnRules.prototype.canReplace = canReplace;
44505
44506	BpmnRules.prototype.canDrop = canDrop;
44507
44508	BpmnRules.prototype.canInsert = canInsert;
44509
44510	BpmnRules.prototype.canCreate = canCreate;
44511
44512	BpmnRules.prototype.canConnect = canConnect;
44513
44514	BpmnRules.prototype.canResize = canResize;
44515
44516	BpmnRules.prototype.canCopy = canCopy;
44517
44518	/**
44519	 * Utility functions for rule checking
44520	 */
44521
44522	/**
44523	 * Checks if given element can be used for starting connection.
44524	 *
44525	 * @param  {Element} source
44526	 * @return {boolean}
44527	 */
44528	function canStartConnection(element) {
44529	  if (nonExistingOrLabel(element)) {
44530	    return null;
44531	  }
44532
44533	  return isAny(element, [
44534	    'bpmn:FlowNode',
44535	    'bpmn:InteractionNode',
44536	    'bpmn:DataObjectReference',
44537	    'bpmn:DataStoreReference',
44538	    'bpmn:Group',
44539	    'bpmn:TextAnnotation'
44540	  ]);
44541	}
44542
44543	function nonExistingOrLabel(element) {
44544	  return !element || isLabel$6(element);
44545	}
44546
44547	function isSame$1(a, b) {
44548	  return a === b;
44549	}
44550
44551	function getOrganizationalParent(element) {
44552
44553	  do {
44554	    if (is$1(element, 'bpmn:Process')) {
44555	      return getBusinessObject(element);
44556	    }
44557
44558	    if (is$1(element, 'bpmn:Participant')) {
44559	      return (
44560	        getBusinessObject(element).processRef ||
44561	        getBusinessObject(element)
44562	      );
44563	    }
44564	  } while ((element = element.parent));
44565
44566	}
44567
44568	function isTextAnnotation(element) {
44569	  return is$1(element, 'bpmn:TextAnnotation');
44570	}
44571
44572	function isGroup(element) {
44573	  return is$1(element, 'bpmn:Group') && !element.labelTarget;
44574	}
44575
44576	function isCompensationBoundary(element) {
44577	  return is$1(element, 'bpmn:BoundaryEvent') &&
44578	         hasEventDefinition(element, 'bpmn:CompensateEventDefinition');
44579	}
44580
44581	function isForCompensation(e) {
44582	  return getBusinessObject(e).isForCompensation;
44583	}
44584
44585	function isSameOrganization(a, b) {
44586	  var parentA = getOrganizationalParent(a),
44587	      parentB = getOrganizationalParent(b);
44588
44589	  return parentA === parentB;
44590	}
44591
44592	function isMessageFlowSource(element) {
44593	  return (
44594	    is$1(element, 'bpmn:InteractionNode') &&
44595	    !is$1(element, 'bpmn:BoundaryEvent') && (
44596	      !is$1(element, 'bpmn:Event') || (
44597	        is$1(element, 'bpmn:ThrowEvent') &&
44598	        hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition')
44599	      )
44600	    )
44601	  );
44602	}
44603
44604	function isMessageFlowTarget(element) {
44605	  return (
44606	    is$1(element, 'bpmn:InteractionNode') &&
44607	    !isForCompensation(element) && (
44608	      !is$1(element, 'bpmn:Event') || (
44609	        is$1(element, 'bpmn:CatchEvent') &&
44610	        hasEventDefinitionOrNone(element, 'bpmn:MessageEventDefinition')
44611	      )
44612	    ) && !(
44613	      is$1(element, 'bpmn:BoundaryEvent') &&
44614	      !hasEventDefinition(element, 'bpmn:MessageEventDefinition')
44615	    )
44616	  );
44617	}
44618
44619	function getScopeParent(element) {
44620
44621	  var parent = element;
44622
44623	  while ((parent = parent.parent)) {
44624
44625	    if (is$1(parent, 'bpmn:FlowElementsContainer')) {
44626	      return getBusinessObject(parent);
44627	    }
44628
44629	    if (is$1(parent, 'bpmn:Participant')) {
44630	      return getBusinessObject(parent).processRef;
44631	    }
44632	  }
44633
44634	  return null;
44635	}
44636
44637	function isSameScope(a, b) {
44638	  var scopeParentA = getScopeParent(a),
44639	      scopeParentB = getScopeParent(b);
44640
44641	  return scopeParentA === scopeParentB;
44642	}
44643
44644	function hasEventDefinition(element, eventDefinition) {
44645	  var bo = getBusinessObject(element);
44646
44647	  return !!find(bo.eventDefinitions || [], function(definition) {
44648	    return is$1(definition, eventDefinition);
44649	  });
44650	}
44651
44652	function hasEventDefinitionOrNone(element, eventDefinition) {
44653	  var bo = getBusinessObject(element);
44654
44655	  return (bo.eventDefinitions || []).every(function(definition) {
44656	    return is$1(definition, eventDefinition);
44657	  });
44658	}
44659
44660	function isSequenceFlowSource(element) {
44661	  return (
44662	    is$1(element, 'bpmn:FlowNode') &&
44663	    !is$1(element, 'bpmn:EndEvent') &&
44664	    !isEventSubProcess(element) &&
44665	    !(is$1(element, 'bpmn:IntermediateThrowEvent') &&
44666	      hasEventDefinition(element, 'bpmn:LinkEventDefinition')
44667	    ) &&
44668	    !isCompensationBoundary(element) &&
44669	    !isForCompensation(element)
44670	  );
44671	}
44672
44673	function isSequenceFlowTarget(element) {
44674	  return (
44675	    is$1(element, 'bpmn:FlowNode') &&
44676	    !is$1(element, 'bpmn:StartEvent') &&
44677	    !is$1(element, 'bpmn:BoundaryEvent') &&
44678	    !isEventSubProcess(element) &&
44679	    !(is$1(element, 'bpmn:IntermediateCatchEvent') &&
44680	      hasEventDefinition(element, 'bpmn:LinkEventDefinition')
44681	    ) &&
44682	    !isForCompensation(element)
44683	  );
44684	}
44685
44686	function isEventBasedTarget(element) {
44687	  return (
44688	    is$1(element, 'bpmn:ReceiveTask') || (
44689	      is$1(element, 'bpmn:IntermediateCatchEvent') && (
44690	        hasEventDefinition(element, 'bpmn:MessageEventDefinition') ||
44691	        hasEventDefinition(element, 'bpmn:TimerEventDefinition') ||
44692	        hasEventDefinition(element, 'bpmn:ConditionalEventDefinition') ||
44693	        hasEventDefinition(element, 'bpmn:SignalEventDefinition')
44694	      )
44695	    )
44696	  );
44697	}
44698
44699	function isConnection$8(element) {
44700	  return element.waypoints;
44701	}
44702
44703	function getParents(element) {
44704
44705	  var parents = [];
44706
44707	  while (element) {
44708	    element = element.parent;
44709
44710	    if (element) {
44711	      parents.push(element);
44712	    }
44713	  }
44714
44715	  return parents;
44716	}
44717
44718	function isParent(possibleParent, element) {
44719	  var allParents = getParents(element);
44720	  return allParents.indexOf(possibleParent) !== -1;
44721	}
44722
44723	function canConnect(source, target, connection) {
44724
44725	  if (nonExistingOrLabel(source) || nonExistingOrLabel(target)) {
44726	    return null;
44727	  }
44728
44729	  if (!is$1(connection, 'bpmn:DataAssociation')) {
44730
44731	    if (canConnectMessageFlow(source, target)) {
44732	      return { type: 'bpmn:MessageFlow' };
44733	    }
44734
44735	    if (canConnectSequenceFlow(source, target)) {
44736	      return { type: 'bpmn:SequenceFlow' };
44737	    }
44738	  }
44739
44740	  var connectDataAssociation = canConnectDataAssociation(source, target);
44741
44742	  if (connectDataAssociation) {
44743	    return connectDataAssociation;
44744	  }
44745
44746	  if (isCompensationBoundary(source) && isForCompensation(target)) {
44747	    return {
44748	      type: 'bpmn:Association',
44749	      associationDirection: 'One'
44750	    };
44751	  }
44752
44753	  if (canConnectAssociation(source, target)) {
44754
44755	    return {
44756	      type: 'bpmn:Association'
44757	    };
44758	  }
44759
44760	  return false;
44761	}
44762
44763	/**
44764	 * Can an element be dropped into the target element
44765	 *
44766	 * @return {boolean}
44767	 */
44768	function canDrop(element, target, position) {
44769
44770	  // can move labels and groups everywhere
44771	  if (isLabel$6(element) || isGroup(element)) {
44772	    return true;
44773	  }
44774
44775
44776	  // disallow to create elements on collapsed pools
44777	  if (is$1(target, 'bpmn:Participant') && !isExpanded(target)) {
44778	    return false;
44779	  }
44780
44781	  // allow to create new participants on
44782	  // existing collaboration and process diagrams
44783	  if (is$1(element, 'bpmn:Participant')) {
44784	    return is$1(target, 'bpmn:Process') || is$1(target, 'bpmn:Collaboration');
44785	  }
44786
44787	  // allow moving DataInput / DataOutput within its original container only
44788	  if (isAny(element, [ 'bpmn:DataInput', 'bpmn:DataOutput' ])) {
44789
44790	    if (element.parent) {
44791	      return target === element.parent;
44792	    }
44793	  }
44794
44795	  // allow creating lanes on participants and other lanes only
44796	  if (is$1(element, 'bpmn:Lane')) {
44797	    return is$1(target, 'bpmn:Participant') || is$1(target, 'bpmn:Lane');
44798	  }
44799
44800	  // disallow dropping boundary events which cannot replace with intermediate event
44801	  if (is$1(element, 'bpmn:BoundaryEvent') && !isDroppableBoundaryEvent(element)) {
44802	    return false;
44803	  }
44804
44805	  // drop flow elements onto flow element containers
44806	  // and participants
44807	  if (is$1(element, 'bpmn:FlowElement') && !is$1(element, 'bpmn:DataStoreReference')) {
44808	    if (is$1(target, 'bpmn:FlowElementsContainer')) {
44809	      return isExpanded(target);
44810	    }
44811
44812	    return isAny(target, [ 'bpmn:Participant', 'bpmn:Lane' ]);
44813	  }
44814
44815	  // disallow dropping data store reference if there is no process to append to
44816	  if (is$1(element, 'bpmn:DataStoreReference') && is$1(target, 'bpmn:Collaboration')) {
44817	    return some(getBusinessObject(target).get('participants'), function(participant) {
44818	      return !!participant.get('processRef');
44819	    });
44820	  }
44821
44822	  // account for the fact that data associations are always
44823	  // rendered and moved to top (Process or Collaboration level)
44824	  //
44825	  // artifacts may be placed wherever, too
44826	  if (isAny(element, [ 'bpmn:Artifact', 'bpmn:DataAssociation', 'bpmn:DataStoreReference' ])) {
44827	    return isAny(target, [
44828	      'bpmn:Collaboration',
44829	      'bpmn:Lane',
44830	      'bpmn:Participant',
44831	      'bpmn:Process',
44832	      'bpmn:SubProcess' ]);
44833	  }
44834
44835	  if (is$1(element, 'bpmn:MessageFlow')) {
44836	    return is$1(target, 'bpmn:Collaboration')
44837	      || element.source.parent == target
44838	      || element.target.parent == target;
44839	  }
44840
44841	  return false;
44842	}
44843
44844	function isDroppableBoundaryEvent(event) {
44845	  return getBusinessObject(event).cancelActivity && (
44846	    hasNoEventDefinition(event) || hasCommonBoundaryIntermediateEventDefinition(event)
44847	  );
44848	}
44849
44850	function isBoundaryEvent(element) {
44851	  return !isLabel$6(element) && is$1(element, 'bpmn:BoundaryEvent');
44852	}
44853
44854	function isLane(element) {
44855	  return is$1(element, 'bpmn:Lane');
44856	}
44857
44858	/**
44859	 * We treat IntermediateThrowEvents as boundary events during create,
44860	 * this must be reflected in the rules.
44861	 */
44862	function isBoundaryCandidate(element) {
44863	  if (isBoundaryEvent(element)) {
44864	    return true;
44865	  }
44866
44867	  if (is$1(element, 'bpmn:IntermediateThrowEvent') && hasNoEventDefinition(element)) {
44868	    return true;
44869	  }
44870
44871	  return (
44872	    is$1(element, 'bpmn:IntermediateCatchEvent') &&
44873	    hasCommonBoundaryIntermediateEventDefinition(element)
44874	  );
44875	}
44876
44877	function hasNoEventDefinition(element) {
44878	  var bo = getBusinessObject(element);
44879
44880	  return bo && !(bo.eventDefinitions && bo.eventDefinitions.length);
44881	}
44882
44883	function hasCommonBoundaryIntermediateEventDefinition(element) {
44884	  return hasOneOfEventDefinitions(element, [
44885	    'bpmn:MessageEventDefinition',
44886	    'bpmn:TimerEventDefinition',
44887	    'bpmn:SignalEventDefinition',
44888	    'bpmn:ConditionalEventDefinition'
44889	  ]);
44890	}
44891
44892	function hasOneOfEventDefinitions(element, eventDefinitions) {
44893	  return eventDefinitions.some(function(definition) {
44894	    return hasEventDefinition(element, definition);
44895	  });
44896	}
44897
44898	function isReceiveTaskAfterEventBasedGateway(element) {
44899	  return (
44900	    is$1(element, 'bpmn:ReceiveTask') &&
44901	    find(element.incoming, function(incoming) {
44902	      return is$1(incoming.source, 'bpmn:EventBasedGateway');
44903	    })
44904	  );
44905	}
44906
44907
44908	function canAttach(elements, target, source, position) {
44909
44910	  if (!Array.isArray(elements)) {
44911	    elements = [ elements ];
44912	  }
44913
44914	  // only (re-)attach one element at a time
44915	  if (elements.length !== 1) {
44916	    return false;
44917	  }
44918
44919	  var element = elements[0];
44920
44921	  // do not attach labels
44922	  if (isLabel$6(element)) {
44923	    return false;
44924	  }
44925
44926	  // only handle boundary events
44927	  if (!isBoundaryCandidate(element)) {
44928	    return false;
44929	  }
44930
44931	  // disallow drop on event sub processes
44932	  if (isEventSubProcess(target)) {
44933	    return false;
44934	  }
44935
44936	  // only allow drop on non compensation activities
44937	  if (!is$1(target, 'bpmn:Activity') || isForCompensation(target)) {
44938	    return false;
44939	  }
44940
44941	  // only attach to subprocess border
44942	  if (position && !getBoundaryAttachment(position, target)) {
44943	    return false;
44944	  }
44945
44946	  // do not attach on receive tasks after event based gateways
44947	  if (isReceiveTaskAfterEventBasedGateway(target)) {
44948	    return false;
44949	  }
44950
44951	  return 'attach';
44952	}
44953
44954
44955	/**
44956	 * Defines how to replace elements for a given target.
44957	 *
44958	 * Returns an array containing all elements which will be replaced.
44959	 *
44960	 * @example
44961	 *
44962	 *  [{ id: 'IntermediateEvent_2',
44963	 *     type: 'bpmn:StartEvent'
44964	 *   },
44965	 *   { id: 'IntermediateEvent_5',
44966	 *     type: 'bpmn:EndEvent'
44967	 *   }]
44968	 *
44969	 * @param  {Array} elements
44970	 * @param  {Object} target
44971	 *
44972	 * @return {Object} an object containing all elements which have to be replaced
44973	 */
44974	function canReplace(elements, target, position) {
44975
44976	  if (!target) {
44977	    return false;
44978	  }
44979
44980	  var canExecute = {
44981	    replacements: []
44982	  };
44983
44984	  forEach(elements, function(element) {
44985
44986	    if (!isEventSubProcess(target)) {
44987
44988	      if (is$1(element, 'bpmn:StartEvent') &&
44989	          element.type !== 'label' &&
44990	          canDrop(element, target)) {
44991
44992	        // replace a non-interrupting start event by a blank interrupting start event
44993	        // when the target is not an event sub process
44994	        if (!isInterrupting(element)) {
44995	          canExecute.replacements.push({
44996	            oldElementId: element.id,
44997	            newElementType: 'bpmn:StartEvent'
44998	          });
44999	        }
45000
45001	        // replace an error/escalation/compensate start event by a blank interrupting start event
45002	        // when the target is not an event sub process
45003	        if (hasErrorEventDefinition(element) ||
45004	            hasEscalationEventDefinition(element) ||
45005	            hasCompensateEventDefinition(element)) {
45006	          canExecute.replacements.push({
45007	            oldElementId: element.id,
45008	            newElementType: 'bpmn:StartEvent'
45009	          });
45010	        }
45011
45012	        // replace a typed start event by a blank interrupting start event
45013	        // when the target is a sub process but not an event sub process
45014	        if (hasOneOfEventDefinitions(element,
45015	          [
45016	            'bpmn:MessageEventDefinition',
45017	            'bpmn:TimerEventDefinition',
45018	            'bpmn:SignalEventDefinition',
45019	            'bpmn:ConditionalEventDefinition'
45020	          ]) &&
45021	            is$1(target, 'bpmn:SubProcess')) {
45022	          canExecute.replacements.push({
45023	            oldElementId: element.id,
45024	            newElementType: 'bpmn:StartEvent'
45025	          });
45026	        }
45027	      }
45028	    }
45029
45030	    if (!is$1(target, 'bpmn:Transaction')) {
45031	      if (hasEventDefinition(element, 'bpmn:CancelEventDefinition') &&
45032	          element.type !== 'label') {
45033
45034	        if (is$1(element, 'bpmn:EndEvent') && canDrop(element, target)) {
45035	          canExecute.replacements.push({
45036	            oldElementId: element.id,
45037	            newElementType: 'bpmn:EndEvent'
45038	          });
45039	        }
45040
45041	        if (is$1(element, 'bpmn:BoundaryEvent') && canAttach(element, target, null, position)) {
45042	          canExecute.replacements.push({
45043	            oldElementId: element.id,
45044	            newElementType: 'bpmn:BoundaryEvent'
45045	          });
45046	        }
45047	      }
45048	    }
45049	  });
45050
45051	  return canExecute.replacements.length ? canExecute : false;
45052	}
45053
45054	function canMove(elements, target) {
45055
45056	  // do not move selection containing lanes
45057	  if (some(elements, isLane)) {
45058	    return false;
45059	  }
45060
45061	  // allow default move check to start move operation
45062	  if (!target) {
45063	    return true;
45064	  }
45065
45066	  return elements.every(function(element) {
45067	    return canDrop(element, target);
45068	  });
45069	}
45070
45071	function canCreate(shape, target, source, position) {
45072
45073	  if (!target) {
45074	    return false;
45075	  }
45076
45077	  if (isLabel$6(shape) || isGroup(shape)) {
45078	    return true;
45079	  }
45080
45081	  if (isSame$1(source, target)) {
45082	    return false;
45083	  }
45084
45085	  // ensure we do not drop the element
45086	  // into source
45087	  if (source && isParent(source, target)) {
45088	    return false;
45089	  }
45090
45091	  return canDrop(shape, target) || canInsert(shape, target);
45092	}
45093
45094	function canResize(shape, newBounds) {
45095	  if (is$1(shape, 'bpmn:SubProcess')) {
45096	    return (
45097	      isExpanded(shape) && (
45098	        !newBounds || (newBounds.width >= 100 && newBounds.height >= 80)
45099	      )
45100	    );
45101	  }
45102
45103	  if (is$1(shape, 'bpmn:Lane')) {
45104	    return !newBounds || (newBounds.width >= 130 && newBounds.height >= 60);
45105	  }
45106
45107	  if (is$1(shape, 'bpmn:Participant')) {
45108	    return !newBounds || (newBounds.width >= 250 && newBounds.height >= 50);
45109	  }
45110
45111	  if (isTextAnnotation(shape)) {
45112	    return true;
45113	  }
45114
45115	  if (isGroup(shape)) {
45116	    return true;
45117	  }
45118
45119	  return false;
45120	}
45121
45122	/**
45123	 * Check, whether one side of the relationship
45124	 * is a text annotation.
45125	 */
45126	function isOneTextAnnotation(source, target) {
45127
45128	  var sourceTextAnnotation = isTextAnnotation(source),
45129	      targetTextAnnotation = isTextAnnotation(target);
45130
45131	  return (
45132	    (sourceTextAnnotation || targetTextAnnotation) &&
45133	    (sourceTextAnnotation !== targetTextAnnotation)
45134	  );
45135	}
45136
45137
45138	function canConnectAssociation(source, target) {
45139
45140	  // do not connect connections
45141	  if (isConnection$8(source) || isConnection$8(target)) {
45142	    return false;
45143	  }
45144
45145	  // compensation boundary events are exception
45146	  if (isCompensationBoundary(source) && isForCompensation(target)) {
45147	    return true;
45148	  }
45149
45150	  // don't connect parent <-> child
45151	  if (isParent(target, source) || isParent(source, target)) {
45152	    return false;
45153	  }
45154
45155	  // allow connection of associations between <!TextAnnotation> and <TextAnnotation>
45156	  if (isOneTextAnnotation(source, target)) {
45157	    return true;
45158	  }
45159
45160	  // can connect associations where we can connect
45161	  // data associations, too (!)
45162	  return !!canConnectDataAssociation(source, target);
45163	}
45164
45165	function canConnectMessageFlow(source, target) {
45166
45167	  // during connect user might move mouse out of canvas
45168	  // https://github.com/bpmn-io/bpmn-js/issues/1033
45169	  if (getRootElement(source) && !getRootElement(target)) {
45170	    return false;
45171	  }
45172
45173	  return (
45174	    isMessageFlowSource(source) &&
45175	    isMessageFlowTarget(target) &&
45176	    !isSameOrganization(source, target)
45177	  );
45178	}
45179
45180	function canConnectSequenceFlow(source, target) {
45181
45182	  if (
45183	    isEventBasedTarget(target) &&
45184	    target.incoming.length > 0 &&
45185	    areOutgoingEventBasedGatewayConnections(target.incoming) &&
45186	    !is$1(source, 'bpmn:EventBasedGateway')
45187	  ) {
45188	    return false;
45189	  }
45190
45191	  return isSequenceFlowSource(source) &&
45192	         isSequenceFlowTarget(target) &&
45193	         isSameScope(source, target) &&
45194	         !(is$1(source, 'bpmn:EventBasedGateway') && !isEventBasedTarget(target));
45195	}
45196
45197
45198	function canConnectDataAssociation(source, target) {
45199
45200	  if (isAny(source, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ]) &&
45201	      isAny(target, [ 'bpmn:Activity', 'bpmn:ThrowEvent' ])) {
45202	    return { type: 'bpmn:DataInputAssociation' };
45203	  }
45204
45205	  if (isAny(target, [ 'bpmn:DataObjectReference', 'bpmn:DataStoreReference' ]) &&
45206	      isAny(source, [ 'bpmn:Activity', 'bpmn:CatchEvent' ])) {
45207	    return { type: 'bpmn:DataOutputAssociation' };
45208	  }
45209
45210	  return false;
45211	}
45212
45213	function canInsert(shape, flow, position) {
45214
45215	  if (!flow) {
45216	    return false;
45217	  }
45218
45219	  if (Array.isArray(shape)) {
45220	    if (shape.length !== 1) {
45221	      return false;
45222	    }
45223
45224	    shape = shape[0];
45225	  }
45226
45227	  if (flow.source === shape ||
45228	      flow.target === shape) {
45229	    return false;
45230	  }
45231
45232	  // return true if we can drop on the
45233	  // underlying flow parent
45234	  //
45235	  // at this point we are not really able to talk
45236	  // about connection rules (yet)
45237
45238	  return (
45239	    isAny(flow, [ 'bpmn:SequenceFlow', 'bpmn:MessageFlow' ]) &&
45240	    !isLabel$6(flow) &&
45241	    is$1(shape, 'bpmn:FlowNode') &&
45242	    !is$1(shape, 'bpmn:BoundaryEvent') &&
45243	    canDrop(shape, flow.parent));
45244	}
45245
45246	function includes$5(elements, element) {
45247	  return (elements && element) && elements.indexOf(element) !== -1;
45248	}
45249
45250	function canCopy(elements, element) {
45251	  if (isLabel$6(element)) {
45252	    return true;
45253	  }
45254
45255	  if (is$1(element, 'bpmn:Lane') && !includes$5(elements, element.parent)) {
45256	    return false;
45257	  }
45258
45259	  return true;
45260	}
45261
45262	function isOutgoingEventBasedGatewayConnection(connection) {
45263
45264	  if (connection && connection.source) {
45265	    return is$1(connection.source, 'bpmn:EventBasedGateway');
45266	  }
45267	}
45268
45269	function areOutgoingEventBasedGatewayConnections(connections) {
45270	  connections = connections || [];
45271
45272	  return connections.some(isOutgoingEventBasedGatewayConnection);
45273	}
45274
45275	function getRootElement(element) {
45276	  return getParent(element, 'bpmn:Process') || getParent(element, 'bpmn:Collaboration');
45277	}
45278
45279	var RulesModule = {
45280	  __depends__: [
45281	    RulesModule$1
45282	  ],
45283	  __init__: [ 'bpmnRules' ],
45284	  bpmnRules: [ 'type', BpmnRules ]
45285	};
45286
45287	var HIGH_PRIORITY$6 = 2000;
45288
45289	function BpmnDiOrdering(eventBus, canvas) {
45290
45291	  eventBus.on('saveXML.start', HIGH_PRIORITY$6, orderDi);
45292
45293	  function orderDi() {
45294	    var root = canvas.getRootElement(),
45295	        rootDi = getBusinessObject(root).di,
45296	        elements,
45297	        diElements;
45298
45299	    elements = selfAndAllChildren([ root ], false);
45300
45301	    // only bpmndi:Shape and bpmndi:Edge can be direct children of bpmndi:Plane
45302	    elements = filter(elements, function(element) {
45303	      return element !== root && !element.labelTarget;
45304	    });
45305
45306	    diElements = map$1(elements, getDi);
45307
45308	    rootDi.set('planeElement', diElements);
45309	  }
45310	}
45311
45312	BpmnDiOrdering.$inject = [ 'eventBus', 'canvas' ];
45313
45314	var DiOrderingModule = {
45315	  __init__: [
45316	    'bpmnDiOrdering'
45317	  ],
45318	  bpmnDiOrdering: [ 'type', BpmnDiOrdering ]
45319	};
45320
45321	/**
45322	 * An abstract provider that allows modelers to implement a custom
45323	 * ordering of diagram elements on the canvas.
45324	 *
45325	 * It makes sure that the order is always preserved during element
45326	 * creation and move operations.
45327	 *
45328	 * In order to use this behavior, inherit from it and override
45329	 * the method {@link OrderingProvider#getOrdering}.
45330	 *
45331	 * @example
45332	 *
45333	 * ```javascript
45334	 * function CustomOrderingProvider(eventBus) {
45335	 *   OrderingProvider.call(this, eventBus);
45336	 *
45337	 *   this.getOrdering = function(element, newParent) {
45338	 *     // always insert elements at the front
45339	 *     // when moving
45340	 *     return {
45341	 *       index: 0,
45342	 *       parent: newParent
45343	 *     };
45344	 *   };
45345	 * }
45346	 * ```
45347	 *
45348	 * @param {EventBus} eventBus
45349	 */
45350	function OrderingProvider(eventBus) {
45351
45352	  CommandInterceptor.call(this, eventBus);
45353
45354
45355	  var self = this;
45356
45357	  this.preExecute([ 'shape.create', 'connection.create' ], function(event) {
45358
45359	    var context = event.context,
45360	        element = context.shape || context.connection,
45361	        parent = context.parent;
45362
45363	    var ordering = self.getOrdering(element, parent);
45364
45365	    if (ordering) {
45366
45367	      if (ordering.parent !== undefined) {
45368	        context.parent = ordering.parent;
45369	      }
45370
45371	      context.parentIndex = ordering.index;
45372	    }
45373	  });
45374
45375	  this.preExecute([ 'shape.move', 'connection.move' ], function(event) {
45376
45377	    var context = event.context,
45378	        element = context.shape || context.connection,
45379	        parent = context.newParent || element.parent;
45380
45381	    var ordering = self.getOrdering(element, parent);
45382
45383	    if (ordering) {
45384
45385	      if (ordering.parent !== undefined) {
45386	        context.newParent = ordering.parent;
45387	      }
45388
45389	      context.newParentIndex = ordering.index;
45390	    }
45391	  });
45392	}
45393
45394	/**
45395	 * Return a custom ordering of the element, both in terms
45396	 * of parent element and index in the new parent.
45397	 *
45398	 * Implementors of this method must return an object with
45399	 * `parent` _and_ `index` in it.
45400	 *
45401	 * @param {djs.model.Base} element
45402	 * @param {djs.model.Shape} newParent
45403	 *
45404	 * @return {Object} ordering descriptor
45405	 */
45406	OrderingProvider.prototype.getOrdering = function(element, newParent) {
45407	  return null;
45408	};
45409
45410	inherits$1(OrderingProvider, CommandInterceptor);
45411
45412	/**
45413	 * a simple ordering provider that makes sure:
45414	 *
45415	 * (0) labels and groups are rendered always on top
45416	 * (1) elements are ordered by a {level} property
45417	 */
45418	function BpmnOrderingProvider(eventBus, canvas, translate) {
45419
45420	  OrderingProvider.call(this, eventBus);
45421
45422	  var orders = [
45423	    { type: 'bpmn:SubProcess', order: { level: 6 } },
45424	    {
45425	      type: 'bpmn:SequenceFlow',
45426	      order: {
45427	        level: 3,
45428	        containers: [
45429	          'bpmn:Participant',
45430	          'bpmn:FlowElementsContainer'
45431	        ]
45432	      }
45433	    },
45434
45435	    // handle DataAssociation(s) like message flows and render them always on top
45436	    {
45437	      type: 'bpmn:DataAssociation',
45438	      order: {
45439	        level: 9,
45440	        containers: [
45441	          'bpmn:Collaboration',
45442	          'bpmn:Process'
45443	        ]
45444	      }
45445	    },
45446	    {
45447	      type: 'bpmn:MessageFlow', order: {
45448	        level: 9,
45449	        containers: [ 'bpmn:Collaboration' ]
45450	      }
45451	    },
45452	    {
45453	      type: 'bpmn:Association',
45454	      order: {
45455	        level: 6,
45456	        containers: [
45457	          'bpmn:Participant',
45458	          'bpmn:FlowElementsContainer',
45459	          'bpmn:Collaboration'
45460	        ]
45461	      }
45462	    },
45463	    { type: 'bpmn:BoundaryEvent', order: { level: 8 } },
45464	    {
45465	      type: 'bpmn:Group',
45466	      order: {
45467	        level: 10,
45468	        containers: [
45469	          'bpmn:Collaboration',
45470	          'bpmn:Process'
45471	        ]
45472	      }
45473	    },
45474	    { type: 'bpmn:FlowElement', order: { level: 5 } },
45475	    { type: 'bpmn:Participant', order: { level: -2 } },
45476	    { type: 'bpmn:Lane', order: { level: -1 } }
45477	  ];
45478
45479	  function computeOrder(element) {
45480	    if (element.labelTarget) {
45481	      return { level: 10 };
45482	    }
45483
45484	    var entry = find(orders, function(o) {
45485	      return isAny(element, [ o.type ]);
45486	    });
45487
45488	    return entry && entry.order || { level: 1 };
45489	  }
45490
45491	  function getOrder(element) {
45492
45493	    var order = element.order;
45494
45495	    if (!order) {
45496	      element.order = order = computeOrder(element);
45497	    }
45498
45499	    if (!order) {
45500	      throw new Error('no order for <' + element.id + '>');
45501	    }
45502
45503	    return order;
45504	  }
45505
45506	  function findActualParent(element, newParent, containers) {
45507
45508	    var actualParent = newParent;
45509
45510	    while (actualParent) {
45511
45512	      if (isAny(actualParent, containers)) {
45513	        break;
45514	      }
45515
45516	      actualParent = actualParent.parent;
45517	    }
45518
45519	    if (!actualParent) {
45520	      throw new Error('no parent for <' + element.id + '> in <' + (newParent && newParent.id) + '>');
45521	    }
45522
45523	    return actualParent;
45524	  }
45525
45526	  this.getOrdering = function(element, newParent) {
45527
45528	    // render labels always on top
45529	    if (element.labelTarget) {
45530	      return {
45531	        parent: canvas.getRootElement(),
45532	        index: -1
45533	      };
45534	    }
45535
45536	    var elementOrder = getOrder(element);
45537
45538	    if (elementOrder.containers) {
45539	      newParent = findActualParent(element, newParent, elementOrder.containers);
45540	    }
45541
45542	    var currentIndex = newParent.children.indexOf(element);
45543
45544	    var insertIndex = findIndex(newParent.children, function(child) {
45545
45546	      // do not compare with labels, they are created
45547	      // in the wrong order (right after elements) during import and
45548	      // mess up the positioning.
45549	      if (!element.labelTarget && child.labelTarget) {
45550	        return false;
45551	      }
45552
45553	      return elementOrder.level < getOrder(child).level;
45554	    });
45555
45556
45557	    // if the element is already in the child list at
45558	    // a smaller index, we need to adjust the insert index.
45559	    // this takes into account that the element is being removed
45560	    // before being re-inserted
45561	    if (insertIndex !== -1) {
45562	      if (currentIndex !== -1 && currentIndex < insertIndex) {
45563	        insertIndex -= 1;
45564	      }
45565	    }
45566
45567	    return {
45568	      index: insertIndex,
45569	      parent: newParent
45570	    };
45571	  };
45572	}
45573
45574	BpmnOrderingProvider.$inject = [ 'eventBus', 'canvas', 'translate' ];
45575
45576	inherits$1(BpmnOrderingProvider, OrderingProvider);
45577
45578	var OrderingModule = {
45579	  __depends__: [
45580	    translate
45581	  ],
45582	  __init__: [ 'bpmnOrderingProvider' ],
45583	  bpmnOrderingProvider: [ 'type', BpmnOrderingProvider ]
45584	};
45585
45586	/**
45587	 * A service that offers un- and redoable execution of commands.
45588	 *
45589	 * The command stack is responsible for executing modeling actions
45590	 * in a un- and redoable manner. To do this it delegates the actual
45591	 * command execution to {@link CommandHandler}s.
45592	 *
45593	 * Command handlers provide {@link CommandHandler#execute(ctx)} and
45594	 * {@link CommandHandler#revert(ctx)} methods to un- and redo a command
45595	 * identified by a command context.
45596	 *
45597	 *
45598	 * ## Life-Cycle events
45599	 *
45600	 * In the process the command stack fires a number of life-cycle events
45601	 * that other components to participate in the command execution.
45602	 *
45603	 *    * preExecute
45604	 *    * preExecuted
45605	 *    * execute
45606	 *    * executed
45607	 *    * postExecute
45608	 *    * postExecuted
45609	 *    * revert
45610	 *    * reverted
45611	 *
45612	 * A special event is used for validating, whether a command can be
45613	 * performed prior to its execution.
45614	 *
45615	 *    * canExecute
45616	 *
45617	 * Each of the events is fired as `commandStack.{eventName}` and
45618	 * `commandStack.{commandName}.{eventName}`, respectively. This gives
45619	 * components fine grained control on where to hook into.
45620	 *
45621	 * The event object fired transports `command`, the name of the
45622	 * command and `context`, the command context.
45623	 *
45624	 *
45625	 * ## Creating Command Handlers
45626	 *
45627	 * Command handlers should provide the {@link CommandHandler#execute(ctx)}
45628	 * and {@link CommandHandler#revert(ctx)} methods to implement
45629	 * redoing and undoing of a command.
45630	 *
45631	 * A command handler _must_ ensure undo is performed properly in order
45632	 * not to break the undo chain. It must also return the shapes that
45633	 * got changed during the `execute` and `revert` operations.
45634	 *
45635	 * Command handlers may execute other modeling operations (and thus
45636	 * commands) in their `preExecute` and `postExecute` phases. The command
45637	 * stack will properly group all commands together into a logical unit
45638	 * that may be re- and undone atomically.
45639	 *
45640	 * Command handlers must not execute other commands from within their
45641	 * core implementation (`execute`, `revert`).
45642	 *
45643	 *
45644	 * ## Change Tracking
45645	 *
45646	 * During the execution of the CommandStack it will keep track of all
45647	 * elements that have been touched during the command's execution.
45648	 *
45649	 * At the end of the CommandStack execution it will notify interested
45650	 * components via an 'elements.changed' event with all the dirty
45651	 * elements.
45652	 *
45653	 * The event can be picked up by components that are interested in the fact
45654	 * that elements have been changed. One use case for this is updating
45655	 * their graphical representation after moving / resizing or deletion.
45656	 *
45657	 * @see CommandHandler
45658	 *
45659	 * @param {EventBus} eventBus
45660	 * @param {Injector} injector
45661	 */
45662	function CommandStack(eventBus, injector) {
45663
45664	  /**
45665	   * A map of all registered command handlers.
45666	   *
45667	   * @type {Object}
45668	   */
45669	  this._handlerMap = {};
45670
45671	  /**
45672	   * A stack containing all re/undoable actions on the diagram
45673	   *
45674	   * @type {Array<Object>}
45675	   */
45676	  this._stack = [];
45677
45678	  /**
45679	   * The current index on the stack
45680	   *
45681	   * @type {number}
45682	   */
45683	  this._stackIdx = -1;
45684
45685	  /**
45686	   * Current active commandStack execution
45687	   *
45688	   * @type {Object}
45689	   * @property {Object[]} actions
45690	   * @property {Object[]} dirty
45691	   * @property { 'undo' | 'redo' | 'clear' | 'execute' | null } trigger the cause of the current excecution
45692	   */
45693	  this._currentExecution = {
45694	    actions: [],
45695	    dirty: [],
45696	    trigger: null
45697	  };
45698
45699
45700	  this._injector = injector;
45701	  this._eventBus = eventBus;
45702
45703	  this._uid = 1;
45704
45705	  eventBus.on([
45706	    'diagram.destroy',
45707	    'diagram.clear'
45708	  ], function() {
45709	    this.clear(false);
45710	  }, this);
45711	}
45712
45713	CommandStack.$inject = [ 'eventBus', 'injector' ];
45714
45715
45716	/**
45717	 * Execute a command
45718	 *
45719	 * @param {string} command the command to execute
45720	 * @param {Object} context the environment to execute the command in
45721	 */
45722	CommandStack.prototype.execute = function(command, context) {
45723	  if (!command) {
45724	    throw new Error('command required');
45725	  }
45726
45727	  this._currentExecution.trigger = 'execute';
45728
45729	  var action = { command: command, context: context };
45730
45731	  this._pushAction(action);
45732	  this._internalExecute(action);
45733	  this._popAction(action);
45734	};
45735
45736
45737	/**
45738	 * Ask whether a given command can be executed.
45739	 *
45740	 * Implementors may hook into the mechanism on two ways:
45741	 *
45742	 *   * in event listeners:
45743	 *
45744	 *     Users may prevent the execution via an event listener.
45745	 *     It must prevent the default action for `commandStack.(<command>.)canExecute` events.
45746	 *
45747	 *   * in command handlers:
45748	 *
45749	 *     If the method {@link CommandHandler#canExecute} is implemented in a handler
45750	 *     it will be called to figure out whether the execution is allowed.
45751	 *
45752	 * @param  {string} command the command to execute
45753	 * @param  {Object} context the environment to execute the command in
45754	 *
45755	 * @return {boolean} true if the command can be executed
45756	 */
45757	CommandStack.prototype.canExecute = function(command, context) {
45758
45759	  var action = { command: command, context: context };
45760
45761	  var handler = this._getHandler(command);
45762
45763	  var result = this._fire(command, 'canExecute', action);
45764
45765	  // handler#canExecute will only be called if no listener
45766	  // decided on a result already
45767	  if (result === undefined) {
45768	    if (!handler) {
45769	      return false;
45770	    }
45771
45772	    if (handler.canExecute) {
45773	      result = handler.canExecute(context);
45774	    }
45775	  }
45776
45777	  return result;
45778	};
45779
45780
45781	/**
45782	 * Clear the command stack, erasing all undo / redo history
45783	 */
45784	CommandStack.prototype.clear = function(emit) {
45785	  this._stack.length = 0;
45786	  this._stackIdx = -1;
45787
45788	  if (emit !== false) {
45789	    this._fire('changed', { trigger: 'clear' });
45790	  }
45791	};
45792
45793
45794	/**
45795	 * Undo last command(s)
45796	 */
45797	CommandStack.prototype.undo = function() {
45798	  var action = this._getUndoAction(),
45799	      next;
45800
45801	  if (action) {
45802	    this._currentExecution.trigger = 'undo';
45803
45804	    this._pushAction(action);
45805
45806	    while (action) {
45807	      this._internalUndo(action);
45808	      next = this._getUndoAction();
45809
45810	      if (!next || next.id !== action.id) {
45811	        break;
45812	      }
45813
45814	      action = next;
45815	    }
45816
45817	    this._popAction();
45818	  }
45819	};
45820
45821
45822	/**
45823	 * Redo last command(s)
45824	 */
45825	CommandStack.prototype.redo = function() {
45826	  var action = this._getRedoAction(),
45827	      next;
45828
45829	  if (action) {
45830	    this._currentExecution.trigger = 'redo';
45831
45832	    this._pushAction(action);
45833
45834	    while (action) {
45835	      this._internalExecute(action, true);
45836	      next = this._getRedoAction();
45837
45838	      if (!next || next.id !== action.id) {
45839	        break;
45840	      }
45841
45842	      action = next;
45843	    }
45844
45845	    this._popAction();
45846	  }
45847	};
45848
45849
45850	/**
45851	 * Register a handler instance with the command stack
45852	 *
45853	 * @param {string} command
45854	 * @param {CommandHandler} handler
45855	 */
45856	CommandStack.prototype.register = function(command, handler) {
45857	  this._setHandler(command, handler);
45858	};
45859
45860
45861	/**
45862	 * Register a handler type with the command stack
45863	 * by instantiating it and injecting its dependencies.
45864	 *
45865	 * @param {string} command
45866	 * @param {Function} a constructor for a {@link CommandHandler}
45867	 */
45868	CommandStack.prototype.registerHandler = function(command, handlerCls) {
45869
45870	  if (!command || !handlerCls) {
45871	    throw new Error('command and handlerCls must be defined');
45872	  }
45873
45874	  var handler = this._injector.instantiate(handlerCls);
45875	  this.register(command, handler);
45876	};
45877
45878	CommandStack.prototype.canUndo = function() {
45879	  return !!this._getUndoAction();
45880	};
45881
45882	CommandStack.prototype.canRedo = function() {
45883	  return !!this._getRedoAction();
45884	};
45885
45886	// stack access  //////////////////////
45887
45888	CommandStack.prototype._getRedoAction = function() {
45889	  return this._stack[this._stackIdx + 1];
45890	};
45891
45892
45893	CommandStack.prototype._getUndoAction = function() {
45894	  return this._stack[this._stackIdx];
45895	};
45896
45897
45898	// internal functionality //////////////////////
45899
45900	CommandStack.prototype._internalUndo = function(action) {
45901	  var self = this;
45902
45903	  var command = action.command,
45904	      context = action.context;
45905
45906	  var handler = this._getHandler(command);
45907
45908	  // guard against illegal nested command stack invocations
45909	  this._atomicDo(function() {
45910	    self._fire(command, 'revert', action);
45911
45912	    if (handler.revert) {
45913	      self._markDirty(handler.revert(context));
45914	    }
45915
45916	    self._revertedAction(action);
45917
45918	    self._fire(command, 'reverted', action);
45919	  });
45920	};
45921
45922
45923	CommandStack.prototype._fire = function(command, qualifier, event) {
45924	  if (arguments.length < 3) {
45925	    event = qualifier;
45926	    qualifier = null;
45927	  }
45928
45929	  var names = qualifier ? [ command + '.' + qualifier, qualifier ] : [ command ],
45930	      i, name, result;
45931
45932	  event = this._eventBus.createEvent(event);
45933
45934	  for (i = 0; (name = names[i]); i++) {
45935	    result = this._eventBus.fire('commandStack.' + name, event);
45936
45937	    if (event.cancelBubble) {
45938	      break;
45939	    }
45940	  }
45941
45942	  return result;
45943	};
45944
45945	CommandStack.prototype._createId = function() {
45946	  return this._uid++;
45947	};
45948
45949	CommandStack.prototype._atomicDo = function(fn) {
45950
45951	  var execution = this._currentExecution;
45952
45953	  execution.atomic = true;
45954
45955	  try {
45956	    fn();
45957	  } finally {
45958	    execution.atomic = false;
45959	  }
45960	};
45961
45962	CommandStack.prototype._internalExecute = function(action, redo) {
45963	  var self = this;
45964
45965	  var command = action.command,
45966	      context = action.context;
45967
45968	  var handler = this._getHandler(command);
45969
45970	  if (!handler) {
45971	    throw new Error('no command handler registered for <' + command + '>');
45972	  }
45973
45974	  this._pushAction(action);
45975
45976	  if (!redo) {
45977	    this._fire(command, 'preExecute', action);
45978
45979	    if (handler.preExecute) {
45980	      handler.preExecute(context);
45981	    }
45982
45983	    this._fire(command, 'preExecuted', action);
45984	  }
45985
45986	  // guard against illegal nested command stack invocations
45987	  this._atomicDo(function() {
45988
45989	    self._fire(command, 'execute', action);
45990
45991	    if (handler.execute) {
45992
45993	      // actual execute + mark return results as dirty
45994	      self._markDirty(handler.execute(context));
45995	    }
45996
45997	    // log to stack
45998	    self._executedAction(action, redo);
45999
46000	    self._fire(command, 'executed', action);
46001	  });
46002
46003	  if (!redo) {
46004	    this._fire(command, 'postExecute', action);
46005
46006	    if (handler.postExecute) {
46007	      handler.postExecute(context);
46008	    }
46009
46010	    this._fire(command, 'postExecuted', action);
46011	  }
46012
46013	  this._popAction(action);
46014	};
46015
46016
46017	CommandStack.prototype._pushAction = function(action) {
46018
46019	  var execution = this._currentExecution,
46020	      actions = execution.actions;
46021
46022	  var baseAction = actions[0];
46023
46024	  if (execution.atomic) {
46025	    throw new Error('illegal invocation in <execute> or <revert> phase (action: ' + action.command + ')');
46026	  }
46027
46028	  if (!action.id) {
46029	    action.id = (baseAction && baseAction.id) || this._createId();
46030	  }
46031
46032	  actions.push(action);
46033	};
46034
46035
46036	CommandStack.prototype._popAction = function() {
46037	  var execution = this._currentExecution,
46038	      trigger = execution.trigger,
46039	      actions = execution.actions,
46040	      dirty = execution.dirty;
46041
46042	  actions.pop();
46043
46044	  if (!actions.length) {
46045	    this._eventBus.fire('elements.changed', { elements: uniqueBy('id', dirty.reverse()) });
46046
46047	    dirty.length = 0;
46048
46049	    this._fire('changed', { trigger: trigger });
46050
46051	    execution.trigger = null;
46052	  }
46053	};
46054
46055
46056	CommandStack.prototype._markDirty = function(elements) {
46057	  var execution = this._currentExecution;
46058
46059	  if (!elements) {
46060	    return;
46061	  }
46062
46063	  elements = isArray$2(elements) ? elements : [ elements ];
46064
46065	  execution.dirty = execution.dirty.concat(elements);
46066	};
46067
46068
46069	CommandStack.prototype._executedAction = function(action, redo) {
46070	  var stackIdx = ++this._stackIdx;
46071
46072	  if (!redo) {
46073	    this._stack.splice(stackIdx, this._stack.length, action);
46074	  }
46075	};
46076
46077
46078	CommandStack.prototype._revertedAction = function(action) {
46079	  this._stackIdx--;
46080	};
46081
46082
46083	CommandStack.prototype._getHandler = function(command) {
46084	  return this._handlerMap[command];
46085	};
46086
46087	CommandStack.prototype._setHandler = function(command, handler) {
46088	  if (!command || !handler) {
46089	    throw new Error('command and handler required');
46090	  }
46091
46092	  if (this._handlerMap[command]) {
46093	    throw new Error('overriding handler for command <' + command + '>');
46094	  }
46095
46096	  this._handlerMap[command] = handler;
46097	};
46098
46099	var CommandModule = {
46100	  commandStack: [ 'type', CommandStack ]
46101	};
46102
46103	// document wide unique tooltip ids
46104	var ids = new IdGenerator('tt');
46105
46106
46107	function createRoot(parentNode) {
46108	  var root = domify(
46109	    '<div class="djs-tooltip-container" style="position: absolute; width: 0; height: 0;" />'
46110	  );
46111
46112	  parentNode.insertBefore(root, parentNode.firstChild);
46113
46114	  return root;
46115	}
46116
46117
46118	function setPosition(el, x, y) {
46119	  assign(el.style, { left: x + 'px', top: y + 'px' });
46120	}
46121
46122	function setVisible(el, visible) {
46123	  el.style.display = visible === false ? 'none' : '';
46124	}
46125
46126
46127	var tooltipClass = 'djs-tooltip',
46128	    tooltipSelector = '.' + tooltipClass;
46129
46130	/**
46131	 * A service that allows users to render tool tips on the diagram.
46132	 *
46133	 * The tooltip service will take care of updating the tooltip positioning
46134	 * during navigation + zooming.
46135	 *
46136	 * @example
46137	 *
46138	 * ```javascript
46139	 *
46140	 * // add a pink badge on the top left of the shape
46141	 * tooltips.add({
46142	 *   position: {
46143	 *     x: 50,
46144	 *     y: 100
46145	 *   },
46146	 *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>'
46147	 * });
46148	 *
46149	 * // or with optional life span
46150	 * tooltips.add({
46151	 *   position: {
46152	 *     top: -5,
46153	 *     left: -5
46154	 *   },
46155	 *   html: '<div style="width: 10px; background: fuchsia; color: white;">0</div>',
46156	 *   ttl: 2000
46157	 * });
46158	 *
46159	 * // remove a tool tip
46160	 * var id = tooltips.add(...);
46161	 * tooltips.remove(id);
46162	 * ```
46163	 *
46164	 * @param {EventBus} eventBus
46165	 * @param {Canvas} canvas
46166	 */
46167	function Tooltips(eventBus, canvas) {
46168
46169	  this._eventBus = eventBus;
46170	  this._canvas = canvas;
46171
46172	  this._ids = ids;
46173
46174	  this._tooltipDefaults = {
46175	    show: {
46176	      minZoom: 0.7,
46177	      maxZoom: 5.0
46178	    }
46179	  };
46180
46181	  /**
46182	   * Mapping tooltipId -> tooltip
46183	   */
46184	  this._tooltips = {};
46185
46186	  // root html element for all tooltips
46187	  this._tooltipRoot = createRoot(canvas.getContainer());
46188
46189
46190	  var self = this;
46191
46192	  delegate.bind(this._tooltipRoot, tooltipSelector, 'mousedown', function(event) {
46193	    event.stopPropagation();
46194	  });
46195
46196	  delegate.bind(this._tooltipRoot, tooltipSelector, 'mouseover', function(event) {
46197	    self.trigger('mouseover', event);
46198	  });
46199
46200	  delegate.bind(this._tooltipRoot, tooltipSelector, 'mouseout', function(event) {
46201	    self.trigger('mouseout', event);
46202	  });
46203
46204	  this._init();
46205	}
46206
46207
46208	Tooltips.$inject = [ 'eventBus', 'canvas' ];
46209
46210
46211	/**
46212	 * Adds a HTML tooltip to the diagram
46213	 *
46214	 * @param {Object}               tooltip   the tooltip configuration
46215	 *
46216	 * @param {string|DOMElement}    tooltip.html                 html element to use as an tooltip
46217	 * @param {Object}               [tooltip.show]               show configuration
46218	 * @param {number}               [tooltip.show.minZoom]       minimal zoom level to show the tooltip
46219	 * @param {number}               [tooltip.show.maxZoom]       maximum zoom level to show the tooltip
46220	 * @param {Object}               tooltip.position             where to attach the tooltip
46221	 * @param {number}               [tooltip.position.left]      relative to element bbox left attachment
46222	 * @param {number}               [tooltip.position.top]       relative to element bbox top attachment
46223	 * @param {number}               [tooltip.position.bottom]    relative to element bbox bottom attachment
46224	 * @param {number}               [tooltip.position.right]     relative to element bbox right attachment
46225	 * @param {number}               [tooltip.timeout=-1]
46226	 *
46227	 * @return {string}              id that may be used to reference the tooltip for update or removal
46228	 */
46229	Tooltips.prototype.add = function(tooltip) {
46230
46231	  if (!tooltip.position) {
46232	    throw new Error('must specifiy tooltip position');
46233	  }
46234
46235	  if (!tooltip.html) {
46236	    throw new Error('must specifiy tooltip html');
46237	  }
46238
46239	  var id = this._ids.next();
46240
46241	  tooltip = assign({}, this._tooltipDefaults, tooltip, {
46242	    id: id
46243	  });
46244
46245	  this._addTooltip(tooltip);
46246
46247	  if (tooltip.timeout) {
46248	    this.setTimeout(tooltip);
46249	  }
46250
46251	  return id;
46252	};
46253
46254	Tooltips.prototype.trigger = function(action, event) {
46255
46256	  var node = event.delegateTarget || event.target;
46257
46258	  var tooltip = this.get(attr$1(node, 'data-tooltip-id'));
46259
46260	  if (!tooltip) {
46261	    return;
46262	  }
46263
46264	  if (action === 'mouseover' && tooltip.timeout) {
46265	    this.clearTimeout(tooltip);
46266	  }
46267
46268	  if (action === 'mouseout' && tooltip.timeout) {
46269
46270	    // cut timeout after mouse out
46271	    tooltip.timeout = 1000;
46272
46273	    this.setTimeout(tooltip);
46274	  }
46275	};
46276
46277	/**
46278	 * Get a tooltip with the given id
46279	 *
46280	 * @param {string} id
46281	 */
46282	Tooltips.prototype.get = function(id) {
46283
46284	  if (typeof id !== 'string') {
46285	    id = id.id;
46286	  }
46287
46288	  return this._tooltips[id];
46289	};
46290
46291	Tooltips.prototype.clearTimeout = function(tooltip) {
46292
46293	  tooltip = this.get(tooltip);
46294
46295	  if (!tooltip) {
46296	    return;
46297	  }
46298
46299	  var removeTimer = tooltip.removeTimer;
46300
46301	  if (removeTimer) {
46302	    clearTimeout(removeTimer);
46303	    tooltip.removeTimer = null;
46304	  }
46305	};
46306
46307	Tooltips.prototype.setTimeout = function(tooltip) {
46308
46309	  tooltip = this.get(tooltip);
46310
46311	  if (!tooltip) {
46312	    return;
46313	  }
46314
46315	  this.clearTimeout(tooltip);
46316
46317	  var self = this;
46318
46319	  tooltip.removeTimer = setTimeout(function() {
46320	    self.remove(tooltip);
46321	  }, tooltip.timeout);
46322	};
46323
46324	/**
46325	 * Remove an tooltip with the given id
46326	 *
46327	 * @param {string} id
46328	 */
46329	Tooltips.prototype.remove = function(id) {
46330
46331	  var tooltip = this.get(id);
46332
46333	  if (tooltip) {
46334	    remove$2(tooltip.html);
46335	    remove$2(tooltip.htmlContainer);
46336
46337	    delete tooltip.htmlContainer;
46338
46339	    delete this._tooltips[tooltip.id];
46340	  }
46341	};
46342
46343
46344	Tooltips.prototype.show = function() {
46345	  setVisible(this._tooltipRoot);
46346	};
46347
46348
46349	Tooltips.prototype.hide = function() {
46350	  setVisible(this._tooltipRoot, false);
46351	};
46352
46353
46354	Tooltips.prototype._updateRoot = function(viewbox) {
46355	  var a = viewbox.scale || 1;
46356	  var d = viewbox.scale || 1;
46357
46358	  var matrix = 'matrix(' + a + ',0,0,' + d + ',' + (-1 * viewbox.x * a) + ',' + (-1 * viewbox.y * d) + ')';
46359
46360	  this._tooltipRoot.style.transform = matrix;
46361	  this._tooltipRoot.style['-ms-transform'] = matrix;
46362	};
46363
46364
46365	Tooltips.prototype._addTooltip = function(tooltip) {
46366
46367	  var id = tooltip.id,
46368	      html = tooltip.html,
46369	      htmlContainer,
46370	      tooltipRoot = this._tooltipRoot;
46371
46372	  // unwrap jquery (for those who need it)
46373	  if (html.get && html.constructor.prototype.jquery) {
46374	    html = html.get(0);
46375	  }
46376
46377	  // create proper html elements from
46378	  // tooltip HTML strings
46379	  if (isString(html)) {
46380	    html = domify(html);
46381	  }
46382
46383	  htmlContainer = domify('<div data-tooltip-id="' + id + '" class="' + tooltipClass + '" style="position: absolute">');
46384
46385	  htmlContainer.appendChild(html);
46386
46387	  if (tooltip.type) {
46388	    classes$1(htmlContainer).add('djs-tooltip-' + tooltip.type);
46389	  }
46390
46391	  if (tooltip.className) {
46392	    classes$1(htmlContainer).add(tooltip.className);
46393	  }
46394
46395	  tooltip.htmlContainer = htmlContainer;
46396
46397	  tooltipRoot.appendChild(htmlContainer);
46398
46399	  this._tooltips[id] = tooltip;
46400
46401	  this._updateTooltip(tooltip);
46402	};
46403
46404
46405	Tooltips.prototype._updateTooltip = function(tooltip) {
46406
46407	  var position = tooltip.position,
46408	      htmlContainer = tooltip.htmlContainer;
46409
46410	  // update overlay html based on tooltip x, y
46411
46412	  setPosition(htmlContainer, position.x, position.y);
46413	};
46414
46415
46416	Tooltips.prototype._updateTooltipVisibilty = function(viewbox) {
46417
46418	  forEach(this._tooltips, function(tooltip) {
46419	    var show = tooltip.show,
46420	        htmlContainer = tooltip.htmlContainer,
46421	        visible = true;
46422
46423	    if (show) {
46424	      if (show.minZoom > viewbox.scale ||
46425	          show.maxZoom < viewbox.scale) {
46426	        visible = false;
46427	      }
46428
46429	      setVisible(htmlContainer, visible);
46430	    }
46431	  });
46432	};
46433
46434	Tooltips.prototype._init = function() {
46435
46436	  var self = this;
46437
46438	  // scroll/zoom integration
46439
46440	  function updateViewbox(viewbox) {
46441	    self._updateRoot(viewbox);
46442	    self._updateTooltipVisibilty(viewbox);
46443
46444	    self.show();
46445	  }
46446
46447	  this._eventBus.on('canvas.viewbox.changing', function(event) {
46448	    self.hide();
46449	  });
46450
46451	  this._eventBus.on('canvas.viewbox.changed', function(event) {
46452	    updateViewbox(event.viewbox);
46453	  });
46454	};
46455
46456	var TooltipsModule = {
46457	  __init__: [ 'tooltips' ],
46458	  tooltips: [ 'type', Tooltips ]
46459	};
46460
46461	/**
46462	 * Remove from the beginning of a collection until it is empty.
46463	 *
46464	 * This is a null-safe operation that ensures elements
46465	 * are being removed from the given collection until the
46466	 * collection is empty.
46467	 *
46468	 * The implementation deals with the fact that a remove operation
46469	 * may touch, i.e. remove multiple elements in the collection
46470	 * at a time.
46471	 *
46472	 * @param {Array<Object>} [collection]
46473	 * @param {Function} removeFn
46474	 *
46475	 * @return {Array<Object>} the cleared collection
46476	 */
46477	function saveClear(collection, removeFn) {
46478
46479	  if (typeof removeFn !== 'function') {
46480	    throw new Error('removeFn iterator must be a function');
46481	  }
46482
46483	  if (!collection) {
46484	    return;
46485	  }
46486
46487	  var e;
46488
46489	  while ((e = collection[0])) {
46490	    removeFn(e);
46491	  }
46492
46493	  return collection;
46494	}
46495
46496	var LOW_PRIORITY$6 = 250,
46497	    HIGH_PRIORITY$5 = 1400;
46498
46499
46500	/**
46501	 * A handler that makes sure labels are properly moved with
46502	 * their label targets.
46503	 *
46504	 * @param {didi.Injector} injector
46505	 * @param {EventBus} eventBus
46506	 * @param {Modeling} modeling
46507	 */
46508	function LabelSupport(injector, eventBus, modeling) {
46509
46510	  CommandInterceptor.call(this, eventBus);
46511
46512	  var movePreview = injector.get('movePreview', false);
46513
46514	  // remove labels from the collection that are being
46515	  // moved with other elements anyway
46516	  eventBus.on('shape.move.start', HIGH_PRIORITY$5, function(e) {
46517
46518	    var context = e.context,
46519	        shapes = context.shapes,
46520	        validatedShapes = context.validatedShapes;
46521
46522	    context.shapes = removeLabels(shapes);
46523	    context.validatedShapes = removeLabels(validatedShapes);
46524	  });
46525
46526	  // add labels to visual's group
46527	  movePreview && eventBus.on('shape.move.start', LOW_PRIORITY$6, function(e) {
46528
46529	    var context = e.context,
46530	        shapes = context.shapes;
46531
46532	    var labels = [];
46533
46534	    forEach(shapes, function(element) {
46535
46536	      forEach(element.labels, function(label) {
46537
46538	        if (!label.hidden && context.shapes.indexOf(label) === -1) {
46539	          labels.push(label);
46540	        }
46541
46542	        if (element.labelTarget) {
46543	          labels.push(element);
46544	        }
46545	      });
46546	    });
46547
46548	    forEach(labels, function(label) {
46549	      movePreview.makeDraggable(context, label, true);
46550	    });
46551
46552	  });
46553
46554	  // add all labels to move closure
46555	  this.preExecuted('elements.move', HIGH_PRIORITY$5, function(e) {
46556	    var context = e.context,
46557	        closure = context.closure,
46558	        enclosedElements = closure.enclosedElements;
46559
46560	    var enclosedLabels = [];
46561
46562	    // find labels that are not part of
46563	    // move closure yet and add them
46564	    forEach(enclosedElements, function(element) {
46565	      forEach(element.labels, function(label) {
46566
46567	        if (!enclosedElements[label.id]) {
46568	          enclosedLabels.push(label);
46569	        }
46570	      });
46571	    });
46572
46573	    closure.addAll(enclosedLabels);
46574	  });
46575
46576
46577	  this.preExecute([
46578	    'connection.delete',
46579	    'shape.delete'
46580	  ], function(e) {
46581
46582	    var context = e.context,
46583	        element = context.connection || context.shape;
46584
46585	    saveClear(element.labels, function(label) {
46586	      modeling.removeShape(label, { nested: true });
46587	    });
46588	  });
46589
46590
46591	  this.execute('shape.delete', function(e) {
46592
46593	    var context = e.context,
46594	        shape = context.shape,
46595	        labelTarget = shape.labelTarget;
46596
46597	    // unset labelTarget
46598	    if (labelTarget) {
46599	      context.labelTargetIndex = indexOf(labelTarget.labels, shape);
46600	      context.labelTarget = labelTarget;
46601
46602	      shape.labelTarget = null;
46603	    }
46604	  });
46605
46606	  this.revert('shape.delete', function(e) {
46607
46608	    var context = e.context,
46609	        shape = context.shape,
46610	        labelTarget = context.labelTarget,
46611	        labelTargetIndex = context.labelTargetIndex;
46612
46613	    // restore labelTarget
46614	    if (labelTarget) {
46615	      add(labelTarget.labels, shape, labelTargetIndex);
46616
46617	      shape.labelTarget = labelTarget;
46618	    }
46619	  });
46620
46621	}
46622
46623	inherits$1(LabelSupport, CommandInterceptor);
46624
46625	LabelSupport.$inject = [
46626	  'injector',
46627	  'eventBus',
46628	  'modeling'
46629	];
46630
46631
46632	/**
46633	 * Return a filtered list of elements that do not
46634	 * contain attached elements with hosts being part
46635	 * of the selection.
46636	 *
46637	 * @param  {Array<djs.model.Base>} elements
46638	 *
46639	 * @return {Array<djs.model.Base>} filtered
46640	 */
46641	function removeLabels(elements) {
46642
46643	  return filter(elements, function(element) {
46644
46645	    // filter out labels that are move together
46646	    // with their label targets
46647	    return elements.indexOf(element.labelTarget) === -1;
46648	  });
46649	}
46650
46651	var LabelSupportModule = {
46652	  __init__: [ 'labelSupport'],
46653	  labelSupport: [ 'type', LabelSupport ]
46654	};
46655
46656	var LOW_PRIORITY$5 = 251,
46657	    HIGH_PRIORITY$4 = 1401;
46658
46659	var MARKER_ATTACH$1 = 'attach-ok';
46660
46661
46662	/**
46663	 * Adds the notion of attached elements to the modeler.
46664	 *
46665	 * Optionally depends on `diagram-js/lib/features/move` to render
46666	 * the attached elements during move preview.
46667	 *
46668	 * Optionally depends on `diagram-js/lib/features/label-support`
46669	 * to render attached labels during move preview.
46670	 *
46671	 * @param {didi.Injector} injector
46672	 * @param {EventBus} eventBus
46673	 * @param {Canvas} canvas
46674	 * @param {Rules} rules
46675	 * @param {Modeling} modeling
46676	 */
46677	function AttachSupport(injector, eventBus, canvas, rules, modeling) {
46678
46679	  CommandInterceptor.call(this, eventBus);
46680
46681	  var movePreview = injector.get('movePreview', false);
46682
46683
46684	  // remove all the attached elements from the shapes to be validated
46685	  // add all the attached shapes to the overall list of moved shapes
46686	  eventBus.on('shape.move.start', HIGH_PRIORITY$4, function(e) {
46687
46688	    var context = e.context,
46689	        shapes = context.shapes,
46690	        validatedShapes = context.validatedShapes;
46691
46692	    context.shapes = addAttached(shapes);
46693
46694	    context.validatedShapes = removeAttached(validatedShapes);
46695	  });
46696
46697	  // add attachers to the visual's group
46698	  movePreview && eventBus.on('shape.move.start', LOW_PRIORITY$5, function(e) {
46699
46700	    var context = e.context,
46701	        shapes = context.shapes,
46702	        attachers = getAttachers(shapes);
46703
46704	    forEach(attachers, function(attacher) {
46705	      movePreview.makeDraggable(context, attacher, true);
46706
46707	      forEach(attacher.labels, function(label) {
46708	        movePreview.makeDraggable(context, label, true);
46709	      });
46710	    });
46711	  });
46712
46713	  // add attach-ok marker to current host
46714	  movePreview && eventBus.on('shape.move.start', function(event) {
46715	    var context = event.context,
46716	        shapes = context.shapes;
46717
46718	    if (shapes.length !== 1) {
46719	      return;
46720	    }
46721
46722	    var shape = shapes[0];
46723
46724	    var host = shape.host;
46725
46726	    if (host) {
46727	      canvas.addMarker(host, MARKER_ATTACH$1);
46728
46729	      eventBus.once([
46730	        'shape.move.out',
46731	        'shape.move.cleanup'
46732	      ], function() {
46733	        canvas.removeMarker(host, MARKER_ATTACH$1);
46734	      });
46735	    }
46736	  });
46737
46738	  // add all attachers to move closure
46739	  this.preExecuted('elements.move', HIGH_PRIORITY$4, function(e) {
46740	    var context = e.context,
46741	        closure = context.closure,
46742	        shapes = context.shapes,
46743	        attachers = getAttachers(shapes);
46744
46745	    forEach(attachers, function(attacher) {
46746	      closure.add(attacher, closure.topLevel[attacher.host.id]);
46747	    });
46748	  });
46749
46750	  // perform the attaching after shapes are done moving
46751	  this.postExecuted('elements.move', function(e) {
46752
46753	    var context = e.context,
46754	        shapes = context.shapes,
46755	        newHost = context.newHost,
46756	        attachers;
46757
46758	    // only single elements can be attached
46759	    // multiply elements can be detached
46760	    if (newHost && shapes.length !== 1) {
46761	      return;
46762	    }
46763
46764	    if (newHost) {
46765	      attachers = shapes;
46766	    } else {
46767
46768	      // find attachers moved without host
46769	      attachers = filter(shapes, function(shape) {
46770	        var host = shape.host;
46771
46772	        return isAttacher(shape) && !includes$4(shapes, host);
46773	      });
46774	    }
46775
46776	    forEach(attachers, function(attacher) {
46777	      modeling.updateAttachment(attacher, newHost);
46778	    });
46779	  });
46780
46781	  // ensure invalid attachment connections are removed
46782	  this.postExecuted('elements.move', function(e) {
46783
46784	    var shapes = e.context.shapes;
46785
46786	    forEach(shapes, function(shape) {
46787
46788	      forEach(shape.attachers, function(attacher) {
46789
46790	        // remove invalid outgoing connections
46791	        forEach(attacher.outgoing.slice(), function(connection) {
46792	          var allowed = rules.allowed('connection.reconnect', {
46793	            connection: connection,
46794	            source: connection.source,
46795	            target: connection.target
46796	          });
46797
46798	          if (!allowed) {
46799	            modeling.removeConnection(connection);
46800	          }
46801	        });
46802
46803	        // remove invalid incoming connections
46804	        forEach(attacher.incoming.slice(), function(connection) {
46805	          var allowed = rules.allowed('connection.reconnect', {
46806	            connection: connection,
46807	            source: connection.source,
46808	            target: connection.target
46809	          });
46810
46811	          if (!allowed) {
46812	            modeling.removeConnection(connection);
46813	          }
46814	        });
46815	      });
46816	    });
46817	  });
46818
46819	  this.postExecute('shape.create', function(e) {
46820	    var context = e.context,
46821	        shape = context.shape,
46822	        host = context.host;
46823
46824	    if (host) {
46825	      modeling.updateAttachment(shape, host);
46826	    }
46827	  });
46828
46829	  // update attachments if the host is replaced
46830	  this.postExecute('shape.replace', function(e) {
46831
46832	    var context = e.context,
46833	        oldShape = context.oldShape,
46834	        newShape = context.newShape;
46835
46836	    // move the attachers to the new host
46837	    saveClear(oldShape.attachers, function(attacher) {
46838	      var allowed = rules.allowed('elements.move', {
46839	        target: newShape,
46840	        shapes: [attacher]
46841	      });
46842
46843	      if (allowed === 'attach') {
46844	        modeling.updateAttachment(attacher, newShape);
46845	      } else {
46846	        modeling.removeShape(attacher);
46847	      }
46848	    });
46849
46850	    // move attachers if new host has different size
46851	    if (newShape.attachers.length) {
46852
46853	      forEach(newShape.attachers, function(attacher) {
46854	        var delta = getNewAttachShapeDelta(attacher, oldShape, newShape);
46855	        modeling.moveShape(attacher, delta, attacher.parent);
46856	      });
46857	    }
46858
46859	  });
46860
46861	  // move shape on host resize
46862	  this.postExecute('shape.resize', function(event) {
46863	    var context = event.context,
46864	        shape = context.shape,
46865	        oldBounds = context.oldBounds,
46866	        newBounds = context.newBounds,
46867	        attachers = shape.attachers,
46868	        hints = context.hints || {};
46869
46870	    if (hints.attachSupport === false) {
46871	      return;
46872	    }
46873
46874	    forEach(attachers, function(attacher) {
46875	      var delta = getNewAttachShapeDelta(attacher, oldBounds, newBounds);
46876
46877	      modeling.moveShape(attacher, delta, attacher.parent);
46878
46879	      forEach(attacher.labels, function(label) {
46880	        modeling.moveShape(label, delta, label.parent);
46881	      });
46882	    });
46883	  });
46884
46885	  // remove attachments
46886	  this.preExecute('shape.delete', function(event) {
46887
46888	    var shape = event.context.shape;
46889
46890	    saveClear(shape.attachers, function(attacher) {
46891	      modeling.removeShape(attacher);
46892	    });
46893
46894	    if (shape.host) {
46895	      modeling.updateAttachment(shape, null);
46896	    }
46897	  });
46898	}
46899
46900	inherits$1(AttachSupport, CommandInterceptor);
46901
46902	AttachSupport.$inject = [
46903	  'injector',
46904	  'eventBus',
46905	  'canvas',
46906	  'rules',
46907	  'modeling'
46908	];
46909
46910
46911	/**
46912	 * Return attachers of the given shapes
46913	 *
46914	 * @param {Array<djs.model.Base>} shapes
46915	 * @return {Array<djs.model.Base>}
46916	 */
46917	function getAttachers(shapes) {
46918	  return flatten(map$1(shapes, function(s) {
46919	    return s.attachers || [];
46920	  }));
46921	}
46922
46923	/**
46924	 * Return a combined list of elements and
46925	 * attachers.
46926	 *
46927	 * @param {Array<djs.model.Base>} elements
46928	 * @return {Array<djs.model.Base>} filtered
46929	 */
46930	function addAttached(elements) {
46931	  var attachers = getAttachers(elements);
46932
46933	  return unionBy('id', elements, attachers);
46934	}
46935
46936	/**
46937	 * Return a filtered list of elements that do not
46938	 * contain attached elements with hosts being part
46939	 * of the selection.
46940	 *
46941	 * @param  {Array<djs.model.Base>} elements
46942	 *
46943	 * @return {Array<djs.model.Base>} filtered
46944	 */
46945	function removeAttached(elements) {
46946
46947	  var ids = groupBy(elements, 'id');
46948
46949	  return filter(elements, function(element) {
46950	    while (element) {
46951
46952	      // host in selection
46953	      if (element.host && ids[element.host.id]) {
46954	        return false;
46955	      }
46956
46957	      element = element.parent;
46958	    }
46959
46960	    return true;
46961	  });
46962	}
46963
46964	function isAttacher(shape) {
46965	  return !!shape.host;
46966	}
46967
46968	function includes$4(array, item) {
46969	  return array.indexOf(item) !== -1;
46970	}
46971
46972	var AttachSupportModule = {
46973	  __depends__: [
46974	    RulesModule$1
46975	  ],
46976	  __init__: [ 'attachSupport' ],
46977	  attachSupport: [ 'type', AttachSupport ]
46978	};
46979
46980	var LOW_PRIORITY$4 = 250;
46981
46982	/**
46983	 * The tool manager acts as middle-man between the available tool's and the Palette,
46984	 * it takes care of making sure that the correct active state is set.
46985	 *
46986	 * @param  {Object}    eventBus
46987	 * @param  {Object}    dragging
46988	 */
46989	function ToolManager(eventBus, dragging) {
46990	  this._eventBus = eventBus;
46991	  this._dragging = dragging;
46992
46993	  this._tools = [];
46994	  this._active = null;
46995	}
46996
46997	ToolManager.$inject = [ 'eventBus', 'dragging' ];
46998
46999	ToolManager.prototype.registerTool = function(name, events) {
47000	  var tools = this._tools;
47001
47002	  if (!events) {
47003	    throw new Error('A tool has to be registered with it\'s "events"');
47004	  }
47005
47006	  tools.push(name);
47007
47008	  this.bindEvents(name, events);
47009	};
47010
47011	ToolManager.prototype.isActive = function(tool) {
47012	  return tool && this._active === tool;
47013	};
47014
47015	ToolManager.prototype.length = function(tool) {
47016	  return this._tools.length;
47017	};
47018
47019	ToolManager.prototype.setActive = function(tool) {
47020	  var eventBus = this._eventBus;
47021
47022	  if (this._active !== tool) {
47023	    this._active = tool;
47024
47025	    eventBus.fire('tool-manager.update', { tool: tool });
47026	  }
47027	};
47028
47029	ToolManager.prototype.bindEvents = function(name, events) {
47030	  var eventBus = this._eventBus,
47031	      dragging = this._dragging;
47032
47033	  var eventsToRegister = [];
47034
47035	  eventBus.on(events.tool + '.init', function(event) {
47036	    var context = event.context;
47037
47038	    // Active tools that want to reactivate themselves must do this explicitly
47039	    if (!context.reactivate && this.isActive(name)) {
47040	      this.setActive(null);
47041
47042	      dragging.cancel();
47043	      return;
47044	    }
47045
47046	    this.setActive(name);
47047
47048	  }, this);
47049
47050	  // Todo[ricardo]: add test cases
47051	  forEach(events, function(event) {
47052	    eventsToRegister.push(event + '.ended');
47053	    eventsToRegister.push(event + '.canceled');
47054	  });
47055
47056	  eventBus.on(eventsToRegister, LOW_PRIORITY$4, function(event) {
47057
47058	    // We defer the de-activation of the tool to the .activate phase,
47059	    // so we're able to check if we want to toggle off the current
47060	    // active tool or switch to a new one
47061	    if (!this._active) {
47062	      return;
47063	    }
47064
47065	    if (isPaletteClick(event)) {
47066	      return;
47067	    }
47068
47069	    this.setActive(null);
47070	  }, this);
47071
47072	};
47073
47074
47075	// helpers ///////////////
47076
47077	/**
47078	 * Check if a given event is a palette click event.
47079	 *
47080	 * @param {EventBus.Event} event
47081	 *
47082	 * @return {boolean}
47083	 */
47084	function isPaletteClick(event) {
47085	  var target = event.originalEvent && event.originalEvent.target;
47086
47087	  return target && closest(target, '.group[data-group="tools"]');
47088	}
47089
47090	var ToolManagerModule = {
47091	  __depends__: [
47092	    DraggingModule
47093	  ],
47094	  __init__: [ 'toolManager' ],
47095	  toolManager: [ 'type', ToolManager ]
47096	};
47097
47098	/**
47099	 * Return direction given axis and delta.
47100	 *
47101	 * @param {string} axis
47102	 * @param {number} delta
47103	 *
47104	 * @return {string}
47105	 */
47106	function getDirection(axis, delta) {
47107
47108	  if (axis === 'x') {
47109	    if (delta > 0) {
47110	      return 'e';
47111	    }
47112
47113	    if (delta < 0) {
47114	      return 'w';
47115	    }
47116	  }
47117
47118	  if (axis === 'y') {
47119	    if (delta > 0) {
47120	      return 's';
47121	    }
47122
47123	    if (delta < 0) {
47124	      return 'n';
47125	    }
47126	  }
47127
47128	  return null;
47129	}
47130
47131	/**
47132	 * Returns connections whose waypoints are to be updated. Waypoints are to be updated if start
47133	 * or end is to be moved or resized.
47134	 *
47135	 * @param {Array<djs.model.Shape} movingShapes
47136	 * @param {Array<djs.model.Shape} resizingShapes
47137	 *
47138	 * @returns {Array<djs.model.Connection>}
47139	 */
47140	function getWaypointsUpdatingConnections(movingShapes, resizingShapes) {
47141	  var waypointsUpdatingConnections = [];
47142
47143	  forEach(movingShapes.concat(resizingShapes), function(shape) {
47144	    var incoming = shape.incoming,
47145	        outgoing = shape.outgoing;
47146
47147	    forEach(incoming.concat(outgoing), function(connection) {
47148	      var source = connection.source,
47149	          target = connection.target;
47150
47151	      if (includes$3(movingShapes, source) ||
47152	        includes$3(movingShapes, target) ||
47153	        includes$3(resizingShapes, source) ||
47154	        includes$3(resizingShapes, target)) {
47155
47156	        if (!includes$3(waypointsUpdatingConnections, connection)) {
47157	          waypointsUpdatingConnections.push(connection);
47158	        }
47159	      }
47160	    });
47161	  });
47162
47163	  return waypointsUpdatingConnections;
47164	}
47165
47166	function includes$3(array, item) {
47167	  return array.indexOf(item) !== -1;
47168	}
47169
47170	/**
47171	 * Resize bounds.
47172	 *
47173	 * @param {Object} bounds
47174	 * @param {number} bounds.x
47175	 * @param {number} bounds.y
47176	 * @param {number} bounds.width
47177	 * @param {number} bounds.height
47178	 * @param {string} direction
47179	 * @param {Object} delta
47180	 * @param {number} delta.x
47181	 * @param {number} delta.y
47182	 *
47183	 * @return {Object}
47184	 */
47185	function resizeBounds(bounds, direction, delta) {
47186	  var x = bounds.x,
47187	      y = bounds.y,
47188	      width = bounds.width,
47189	      height = bounds.height,
47190	      dx = delta.x,
47191	      dy = delta.y;
47192
47193	  switch (direction) {
47194	  case 'n':
47195	    return {
47196	      x: x,
47197	      y: y + dy,
47198	      width: width,
47199	      height: height - dy
47200	    };
47201	  case 's':
47202	    return {
47203	      x: x,
47204	      y: y,
47205	      width: width,
47206	      height: height + dy
47207	    };
47208	  case 'w':
47209	    return {
47210	      x: x + dx,
47211	      y: y,
47212	      width: width - dx,
47213	      height: height
47214	    };
47215	  case 'e':
47216	    return {
47217	      x: x,
47218	      y: y,
47219	      width: width + dx,
47220	      height: height
47221	    };
47222	  default:
47223	    throw new Error('unknown direction: ' + direction);
47224	  }
47225	}
47226
47227	var abs$1 = Math.abs,
47228	    round$4 = Math.round;
47229
47230	var AXIS_TO_DIMENSION = {
47231	  x: 'width',
47232	  y: 'height'
47233	};
47234
47235	var CURSOR_CROSSHAIR = 'crosshair';
47236
47237	var DIRECTION_TO_TRBL = {
47238	  n: 'top',
47239	  w: 'left',
47240	  s: 'bottom',
47241	  e: 'right'
47242	};
47243
47244	var HIGH_PRIORITY$3 = 1500;
47245
47246	var DIRECTION_TO_OPPOSITE = {
47247	  n: 's',
47248	  w: 'e',
47249	  s: 'n',
47250	  e: 'w'
47251	};
47252
47253	var PADDING = 20;
47254
47255
47256	/**
47257	 * Add or remove space by moving and resizing elements.
47258	 *
47259	 * @param {Canvas} canvas
47260	 * @param {Dragging} dragging
47261	 * @param {EventBus} eventBus
47262	 * @param {Modeling} modeling
47263	 * @param {Rules} rules
47264	 * @param {ToolManager} toolManager
47265	 * @param {Mouse} mouse
47266	 */
47267	function SpaceTool(
47268	    canvas, dragging, eventBus,
47269	    modeling, rules, toolManager,
47270	    mouse) {
47271
47272	  this._canvas = canvas;
47273	  this._dragging = dragging;
47274	  this._eventBus = eventBus;
47275	  this._modeling = modeling;
47276	  this._rules = rules;
47277	  this._toolManager = toolManager;
47278	  this._mouse = mouse;
47279
47280	  var self = this;
47281
47282	  toolManager.registerTool('space', {
47283	    tool: 'spaceTool.selection',
47284	    dragging: 'spaceTool'
47285	  });
47286
47287	  eventBus.on('spaceTool.selection.end', function(event) {
47288	    eventBus.once('spaceTool.selection.ended', function() {
47289	      self.activateMakeSpace(event.originalEvent);
47290	    });
47291	  });
47292
47293	  eventBus.on('spaceTool.move', HIGH_PRIORITY$3 , function(event) {
47294	    var context = event.context,
47295	        initialized = context.initialized;
47296
47297	    if (!initialized) {
47298	      initialized = context.initialized = self.init(event, context);
47299	    }
47300
47301	    if (initialized) {
47302	      ensureConstraints(event);
47303	    }
47304	  });
47305
47306	  eventBus.on('spaceTool.end', function(event) {
47307	    var context = event.context,
47308	        axis = context.axis,
47309	        direction = context.direction,
47310	        movingShapes = context.movingShapes,
47311	        resizingShapes = context.resizingShapes,
47312	        start = context.start;
47313
47314	    if (!context.initialized) {
47315	      return;
47316	    }
47317
47318	    ensureConstraints(event);
47319
47320	    var delta = {
47321	      x: 0,
47322	      y: 0
47323	    };
47324
47325	    delta[ axis ] = round$4(event[ 'd' + axis ]);
47326
47327	    self.makeSpace(movingShapes, resizingShapes, delta, direction, start);
47328
47329	    eventBus.once('spaceTool.ended', function(event) {
47330
47331	      // activate space tool selection after make space
47332	      self.activateSelection(event.originalEvent, true, true);
47333	    });
47334	  });
47335	}
47336
47337	SpaceTool.$inject = [
47338	  'canvas',
47339	  'dragging',
47340	  'eventBus',
47341	  'modeling',
47342	  'rules',
47343	  'toolManager',
47344	  'mouse'
47345	];
47346
47347	/**
47348	 * Activate space tool selection.
47349	 *
47350	 * @param {Object} event
47351	 * @param {boolean} autoActivate
47352	 */
47353	SpaceTool.prototype.activateSelection = function(event, autoActivate, reactivate) {
47354	  this._dragging.init(event, 'spaceTool.selection', {
47355	    autoActivate: autoActivate,
47356	    cursor: CURSOR_CROSSHAIR,
47357	    data: {
47358	      context: {
47359	        reactivate: reactivate
47360	      }
47361	    },
47362	    trapClick: false
47363	  });
47364	};
47365
47366	/**
47367	 * Activate space tool make space.
47368	 *
47369	 * @param  {MouseEvent} event
47370	 */
47371	SpaceTool.prototype.activateMakeSpace = function(event) {
47372	  this._dragging.init(event, 'spaceTool', {
47373	    autoActivate: true,
47374	    cursor: CURSOR_CROSSHAIR,
47375	    data: {
47376	      context: {}
47377	    }
47378	  });
47379	};
47380
47381	/**
47382	 * Make space.
47383	 *
47384	 * @param  {Array<djs.model.Shape>} movingShapes
47385	 * @param  {Array<djs.model.Shape>} resizingShapes
47386	 * @param  {Object} delta
47387	 * @param  {number} delta.x
47388	 * @param  {number} delta.y
47389	 * @param  {string} direction
47390	 * @param  {number} start
47391	 */
47392	SpaceTool.prototype.makeSpace = function(movingShapes, resizingShapes, delta, direction, start) {
47393	  return this._modeling.createSpace(movingShapes, resizingShapes, delta, direction, start);
47394	};
47395
47396	/**
47397	 * Initialize make space and return true if that was successful.
47398	 *
47399	 * @param {Object} event
47400	 * @param {Object} context
47401	 *
47402	 * @return {boolean}
47403	 */
47404	SpaceTool.prototype.init = function(event, context) {
47405	  var axis = abs$1(event.dx) > abs$1(event.dy) ? 'x' : 'y',
47406	      delta = event[ 'd' + axis ],
47407	      start = event[ axis ] - delta;
47408
47409	  if (abs$1(delta) < 5) {
47410	    return false;
47411	  }
47412
47413	  // invert delta to remove space when moving left
47414	  if (delta < 0) {
47415	    delta *= -1;
47416	  }
47417
47418	  // invert delta to add/remove space when removing/adding space if modifier key is pressed
47419	  if (hasPrimaryModifier(event)) {
47420	    delta *= -1;
47421	  }
47422
47423	  var direction = getDirection(axis, delta);
47424
47425	  var root = this._canvas.getRootElement();
47426
47427	  var children = selfAndAllChildren(root, true);
47428
47429	  var elements = this.calculateAdjustments(children, axis, delta, start);
47430
47431	  var minDimensions = this._eventBus.fire('spaceTool.getMinDimensions', {
47432	    axis: axis,
47433	    direction: direction,
47434	    shapes: elements.resizingShapes,
47435	    start: start
47436	  });
47437
47438	  var spaceToolConstraints = getSpaceToolConstraints(elements, axis, direction, start, minDimensions);
47439
47440	  assign(
47441	    context,
47442	    elements,
47443	    {
47444	      axis: axis,
47445	      direction: direction,
47446	      spaceToolConstraints: spaceToolConstraints,
47447	      start: start
47448	    }
47449	  );
47450
47451	  set('resize-' + (axis === 'x' ? 'ew' : 'ns'));
47452
47453	  return true;
47454	};
47455
47456	/**
47457	 * Get elements to be moved and resized.
47458	 *
47459	 * @param  {Array<djs.model.Shape>} elements
47460	 * @param  {string} axis
47461	 * @param  {number} delta
47462	 * @param  {number} start
47463	 *
47464	 * @return {Object}
47465	 */
47466	SpaceTool.prototype.calculateAdjustments = function(elements, axis, delta, start) {
47467	  var rules = this._rules;
47468
47469	  var movingShapes = [],
47470	      resizingShapes = [];
47471
47472	  forEach(elements, function(element) {
47473	    if (!element.parent || isConnection$7(element)) {
47474	      return;
47475	    }
47476
47477	    var shapeStart = element[ axis ],
47478	        shapeEnd = shapeStart + element[ AXIS_TO_DIMENSION[ axis ] ];
47479
47480	    // shape to be moved
47481	    if ((delta > 0 && shapeStart > start) || (delta < 0 && shapeEnd < start)) {
47482	      return movingShapes.push(element);
47483	    }
47484
47485	    // shape to be resized
47486	    if (shapeStart < start &&
47487	      shapeEnd > start &&
47488	      rules.allowed('shape.resize', { shape: element })
47489	    ) {
47490
47491	      return resizingShapes.push(element);
47492	    }
47493	  });
47494
47495	  return {
47496	    movingShapes: movingShapes,
47497	    resizingShapes: resizingShapes
47498	  };
47499	};
47500
47501	SpaceTool.prototype.toggle = function() {
47502
47503	  if (this.isActive()) {
47504	    return this._dragging.cancel();
47505	  }
47506
47507	  var mouseEvent = this._mouse.getLastMoveEvent();
47508
47509	  this.activateSelection(mouseEvent, !!mouseEvent);
47510	};
47511
47512	SpaceTool.prototype.isActive = function() {
47513	  var context = this._dragging.context();
47514
47515	  return context && /^spaceTool/.test(context.prefix);
47516	};
47517
47518	// helpers //////////
47519
47520	function addPadding(trbl) {
47521	  return {
47522	    top: trbl.top - PADDING,
47523	    right: trbl.right + PADDING,
47524	    bottom: trbl.bottom + PADDING,
47525	    left: trbl.left - PADDING
47526	  };
47527	}
47528
47529	function ensureConstraints(event) {
47530	  var context = event.context,
47531	      spaceToolConstraints = context.spaceToolConstraints;
47532
47533	  if (!spaceToolConstraints) {
47534	    return;
47535	  }
47536
47537	  var x, y;
47538
47539	  if (isNumber(spaceToolConstraints.left)) {
47540	    x = Math.max(event.x, spaceToolConstraints.left);
47541
47542	    event.dx = event.dx + x - event.x;
47543	    event.x = x;
47544	  }
47545
47546	  if (isNumber(spaceToolConstraints.right)) {
47547	    x = Math.min(event.x, spaceToolConstraints.right);
47548
47549	    event.dx = event.dx + x - event.x;
47550	    event.x = x;
47551	  }
47552
47553	  if (isNumber(spaceToolConstraints.top)) {
47554	    y = Math.max(event.y, spaceToolConstraints.top);
47555
47556	    event.dy = event.dy + y - event.y;
47557	    event.y = y;
47558	  }
47559
47560	  if (isNumber(spaceToolConstraints.bottom)) {
47561	    y = Math.min(event.y, spaceToolConstraints.bottom);
47562
47563	    event.dy = event.dy + y - event.y;
47564	    event.y = y;
47565	  }
47566	}
47567
47568	function getSpaceToolConstraints(elements, axis, direction, start, minDimensions) {
47569	  var movingShapes = elements.movingShapes,
47570	      resizingShapes = elements.resizingShapes;
47571
47572	  if (!resizingShapes.length) {
47573	    return;
47574	  }
47575
47576	  var spaceToolConstraints = {},
47577	      min,
47578	      max;
47579
47580	  forEach(resizingShapes, function(resizingShape) {
47581	    var resizingShapeBBox = asTRBL(resizingShape);
47582
47583	    // find children that are not moving or resizing
47584	    var nonMovingResizingChildren = filter(resizingShape.children, function(child) {
47585	      return !isConnection$7(child) &&
47586	        !isLabel$2(child) &&
47587	        !includes$2(movingShapes, child) &&
47588	        !includes$2(resizingShapes, child);
47589	    });
47590
47591	    // find children that are moving
47592	    var movingChildren = filter(resizingShape.children, function(child) {
47593	      return !isConnection$7(child) && !isLabel$2(child) && includes$2(movingShapes, child);
47594	    });
47595
47596	    var minOrMax,
47597	        nonMovingResizingChildrenBBox,
47598	        movingChildrenBBox;
47599
47600	    if (nonMovingResizingChildren.length) {
47601	      nonMovingResizingChildrenBBox = addPadding(asTRBL(getBBox(nonMovingResizingChildren)));
47602
47603	      minOrMax = start -
47604	        resizingShapeBBox[ DIRECTION_TO_TRBL[ direction ] ] +
47605	        nonMovingResizingChildrenBBox[ DIRECTION_TO_TRBL[ direction ] ];
47606
47607	      if (direction === 'n') {
47608	        spaceToolConstraints.bottom = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47609	      } else if (direction === 'w') {
47610	        spaceToolConstraints.right = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47611	      } else if (direction === 's') {
47612	        spaceToolConstraints.top = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47613	      } else if (direction === 'e') {
47614	        spaceToolConstraints.left = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47615	      }
47616	    }
47617
47618	    if (movingChildren.length) {
47619	      movingChildrenBBox = addPadding(asTRBL(getBBox(movingChildren)));
47620
47621	      minOrMax = start -
47622	        movingChildrenBBox[ DIRECTION_TO_TRBL[ DIRECTION_TO_OPPOSITE[ direction ] ] ] +
47623	        resizingShapeBBox[ DIRECTION_TO_TRBL[ DIRECTION_TO_OPPOSITE[ direction ] ] ];
47624
47625	      if (direction === 'n') {
47626	        spaceToolConstraints.bottom = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47627	      } else if (direction === 'w') {
47628	        spaceToolConstraints.right = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47629	      } else if (direction === 's') {
47630	        spaceToolConstraints.top = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47631	      } else if (direction === 'e') {
47632	        spaceToolConstraints.left = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47633	      }
47634	    }
47635
47636	    var resizingShapeMinDimensions = minDimensions && minDimensions[ resizingShape.id ];
47637
47638	    if (resizingShapeMinDimensions) {
47639	      if (direction === 'n') {
47640	        minOrMax = start +
47641	          resizingShape[ AXIS_TO_DIMENSION [ axis ] ] -
47642	          resizingShapeMinDimensions[ AXIS_TO_DIMENSION[ axis ] ];
47643
47644	        spaceToolConstraints.bottom = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47645	      } else if (direction === 'w') {
47646	        minOrMax = start +
47647	          resizingShape[ AXIS_TO_DIMENSION [ axis ] ] -
47648	          resizingShapeMinDimensions[ AXIS_TO_DIMENSION[ axis ] ];
47649
47650	        spaceToolConstraints.right = max = isNumber(max) ? Math.min(max, minOrMax) : minOrMax;
47651	      } else if (direction === 's') {
47652	        minOrMax = start -
47653	          resizingShape[ AXIS_TO_DIMENSION [ axis ] ] +
47654	          resizingShapeMinDimensions[ AXIS_TO_DIMENSION[ axis ] ];
47655
47656	        spaceToolConstraints.top = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47657	      } else if (direction === 'e') {
47658	        minOrMax = start -
47659	          resizingShape[ AXIS_TO_DIMENSION [ axis ] ] +
47660	          resizingShapeMinDimensions[ AXIS_TO_DIMENSION[ axis ] ];
47661
47662	        spaceToolConstraints.left = min = isNumber(min) ? Math.max(min, minOrMax) : minOrMax;
47663	      }
47664	    }
47665	  });
47666
47667	  return spaceToolConstraints;
47668	}
47669
47670	function includes$2(array, item) {
47671	  return array.indexOf(item) !== -1;
47672	}
47673
47674	function isConnection$7(element) {
47675	  return !!element.waypoints;
47676	}
47677
47678	function isLabel$2(element) {
47679	  return !!element.labelTarget;
47680	}
47681
47682	var MARKER_DRAGGING$1 = 'djs-dragging',
47683	    MARKER_RESIZING = 'djs-resizing';
47684
47685	var LOW_PRIORITY$3 = 250;
47686
47687	var max = Math.max;
47688
47689
47690	/**
47691	 * Provides previews for selecting/moving/resizing shapes when creating/removing space.
47692	 *
47693	 * @param {EventBus} eventBus
47694	 * @param {ElementRegistry} elementRegistry
47695	 * @param {Canvas} canvas
47696	 * @param {Styles} styles
47697	 */
47698	function SpaceToolPreview(
47699	    eventBus, elementRegistry, canvas,
47700	    styles, previewSupport) {
47701
47702	  function addPreviewGfx(collection, dragGroup) {
47703	    forEach(collection, function(element) {
47704	      previewSupport.addDragger(element, dragGroup);
47705
47706	      canvas.addMarker(element, MARKER_DRAGGING$1);
47707	    });
47708	  }
47709
47710	  // add crosshair
47711	  eventBus.on('spaceTool.selection.start', function(event) {
47712	    var space = canvas.getLayer('space'),
47713	        context = event.context;
47714
47715	    var orientation = {
47716	      x: 'M 0,-10000 L 0,10000',
47717	      y: 'M -10000,0 L 10000,0'
47718	    };
47719
47720	    var crosshairGroup = create$1('g');
47721	    attr(crosshairGroup, styles.cls('djs-crosshair-group', [ 'no-events' ]));
47722
47723	    append(space, crosshairGroup);
47724
47725	    // horizontal path
47726	    var pathX = create$1('path');
47727	    attr(pathX, 'd', orientation.x);
47728	    classes(pathX).add('djs-crosshair');
47729
47730	    append(crosshairGroup, pathX);
47731
47732	    // vertical path
47733	    var pathY = create$1('path');
47734	    attr(pathY, 'd', orientation.y);
47735	    classes(pathY).add('djs-crosshair');
47736
47737	    append(crosshairGroup, pathY);
47738
47739	    context.crosshairGroup = crosshairGroup;
47740	  });
47741
47742	  // update crosshair
47743	  eventBus.on('spaceTool.selection.move', function(event) {
47744	    var crosshairGroup = event.context.crosshairGroup;
47745
47746	    translate$2(crosshairGroup, event.x, event.y);
47747	  });
47748
47749	  // remove crosshair
47750	  eventBus.on('spaceTool.selection.cleanup', function(event) {
47751	    var context = event.context,
47752	        crosshairGroup = context.crosshairGroup;
47753
47754	    if (crosshairGroup) {
47755	      remove$1(crosshairGroup);
47756	    }
47757	  });
47758
47759	  // add and update move/resize previews
47760	  eventBus.on('spaceTool.move', LOW_PRIORITY$3, function(event) {
47761
47762	    var context = event.context,
47763	        line = context.line,
47764	        axis = context.axis,
47765	        movingShapes = context.movingShapes,
47766	        resizingShapes = context.resizingShapes;
47767
47768	    if (!context.initialized) {
47769	      return;
47770	    }
47771
47772	    if (!context.dragGroup) {
47773	      var spaceLayer = canvas.getLayer('space');
47774
47775	      line = create$1('path');
47776	      attr(line, 'd', 'M0,0 L0,0');
47777	      classes(line).add('djs-crosshair');
47778
47779	      append(spaceLayer, line);
47780
47781	      context.line = line;
47782
47783	      var dragGroup = create$1('g');
47784	      attr(dragGroup, styles.cls('djs-drag-group', [ 'no-events' ]));
47785
47786	      append(canvas.getActiveLayer(), dragGroup);
47787
47788	      // shapes
47789	      addPreviewGfx(movingShapes, dragGroup);
47790
47791	      // connections
47792	      var movingConnections = context.movingConnections = elementRegistry.filter(function(element) {
47793	        var sourceIsMoving = false;
47794
47795	        forEach(movingShapes, function(shape) {
47796	          forEach(shape.outgoing, function(connection) {
47797	            if (element === connection) {
47798	              sourceIsMoving = true;
47799	            }
47800	          });
47801	        });
47802
47803	        var targetIsMoving = false;
47804
47805	        forEach(movingShapes, function(shape) {
47806	          forEach(shape.incoming, function(connection) {
47807	            if (element === connection) {
47808	              targetIsMoving = true;
47809	            }
47810	          });
47811	        });
47812
47813	        var sourceIsResizing = false;
47814
47815	        forEach(resizingShapes, function(shape) {
47816	          forEach(shape.outgoing, function(connection) {
47817	            if (element === connection) {
47818	              sourceIsResizing = true;
47819	            }
47820	          });
47821	        });
47822
47823	        var targetIsResizing = false;
47824
47825	        forEach(resizingShapes, function(shape) {
47826	          forEach(shape.incoming, function(connection) {
47827	            if (element === connection) {
47828	              targetIsResizing = true;
47829	            }
47830	          });
47831	        });
47832
47833	        return isConnection$6(element)
47834	          && (sourceIsMoving || sourceIsResizing)
47835	          && (targetIsMoving || targetIsResizing);
47836	      });
47837
47838
47839	      addPreviewGfx(movingConnections, dragGroup);
47840
47841	      context.dragGroup = dragGroup;
47842	    }
47843
47844	    if (!context.frameGroup) {
47845	      var frameGroup = create$1('g');
47846	      attr(frameGroup, styles.cls('djs-frame-group', [ 'no-events' ]));
47847
47848	      append(canvas.getActiveLayer(), frameGroup);
47849
47850	      var frames = [];
47851
47852	      forEach(resizingShapes, function(shape) {
47853	        var frame = previewSupport.addFrame(shape, frameGroup);
47854
47855	        var initialBounds = frame.getBBox();
47856
47857	        frames.push({
47858	          element: frame,
47859	          initialBounds: initialBounds
47860	        });
47861
47862	        canvas.addMarker(shape, MARKER_RESIZING);
47863	      });
47864
47865	      context.frameGroup = frameGroup;
47866	      context.frames = frames;
47867	    }
47868
47869	    var orientation = {
47870	      x: 'M' + event.x + ', -10000 L' + event.x + ', 10000',
47871	      y: 'M -10000, ' + event.y + ' L 10000, ' + event.y
47872	    };
47873
47874	    attr(line, { d: orientation[ axis ] });
47875
47876	    var opposite = { x: 'y', y: 'x' };
47877	    var delta = { x: event.dx, y: event.dy };
47878	    delta[ opposite[ context.axis ] ] = 0;
47879
47880	    // update move previews
47881	    translate$2(context.dragGroup, delta.x, delta.y);
47882
47883	    // update resize previews
47884	    forEach(context.frames, function(frame) {
47885	      var element = frame.element,
47886	          initialBounds = frame.initialBounds,
47887	          width,
47888	          height;
47889
47890	      if (context.direction === 'e') {
47891	        attr(element, {
47892	          width: max(initialBounds.width + delta.x, 5)
47893	        });
47894	      } else {
47895	        width = max(initialBounds.width - delta.x, 5);
47896
47897	        attr(element, {
47898	          width: width,
47899	          x: initialBounds.x + initialBounds.width - width
47900	        });
47901	      }
47902
47903	      if (context.direction === 's') {
47904	        attr(element, {
47905	          height: max(initialBounds.height + delta.y, 5)
47906	        });
47907	      } else {
47908	        height = max(initialBounds.height - delta.y, 5);
47909
47910	        attr(element, {
47911	          height: height,
47912	          y: initialBounds.y + initialBounds.height - height
47913	        });
47914	      }
47915	    });
47916
47917	  });
47918
47919	  // remove move/resize previews
47920	  eventBus.on('spaceTool.cleanup', function(event) {
47921
47922	    var context = event.context,
47923	        movingShapes = context.movingShapes,
47924	        movingConnections = context.movingConnections,
47925	        resizingShapes = context.resizingShapes,
47926	        line = context.line,
47927	        dragGroup = context.dragGroup,
47928	        frameGroup = context.frameGroup;
47929
47930	    // moving shapes
47931	    forEach(movingShapes, function(shape) {
47932	      canvas.removeMarker(shape, MARKER_DRAGGING$1);
47933	    });
47934
47935	    // moving connections
47936	    forEach(movingConnections, function(connection) {
47937	      canvas.removeMarker(connection, MARKER_DRAGGING$1);
47938	    });
47939
47940	    if (dragGroup) {
47941	      remove$1(line);
47942	      remove$1(dragGroup);
47943	    }
47944
47945	    forEach(resizingShapes, function(shape) {
47946	      canvas.removeMarker(shape, MARKER_RESIZING);
47947	    });
47948
47949	    if (frameGroup) {
47950	      remove$1(frameGroup);
47951	    }
47952	  });
47953	}
47954
47955	SpaceToolPreview.$inject = [
47956	  'eventBus',
47957	  'elementRegistry',
47958	  'canvas',
47959	  'styles',
47960	  'previewSupport'
47961	];
47962
47963
47964	// helpers //////////////////////
47965
47966	/**
47967	 * Checks if an element is a connection.
47968	 */
47969	function isConnection$6(element) {
47970	  return element.waypoints;
47971	}
47972
47973	var SpaceToolModule = {
47974	  __init__: ['spaceToolPreview'],
47975	  __depends__: [
47976	    DraggingModule,
47977	    RulesModule$1,
47978	    ToolManagerModule,
47979	    PreviewSupportModule,
47980	    MouseModule
47981	  ],
47982	  spaceTool: ['type', SpaceTool ],
47983	  spaceToolPreview: ['type', SpaceToolPreview ]
47984	};
47985
47986	function BpmnFactory(moddle) {
47987	  this._model = moddle;
47988	}
47989
47990	BpmnFactory.$inject = [ 'moddle' ];
47991
47992
47993	BpmnFactory.prototype._needsId = function(element) {
47994	  return isAny(element, [
47995	    'bpmn:RootElement',
47996	    'bpmn:FlowElement',
47997	    'bpmn:MessageFlow',
47998	    'bpmn:DataAssociation',
47999	    'bpmn:Artifact',
48000	    'bpmn:Participant',
48001	    'bpmn:Lane',
48002	    'bpmn:LaneSet',
48003	    'bpmn:Process',
48004	    'bpmn:Collaboration',
48005	    'bpmndi:BPMNShape',
48006	    'bpmndi:BPMNEdge',
48007	    'bpmndi:BPMNDiagram',
48008	    'bpmndi:BPMNPlane',
48009	    'bpmn:Property',
48010	    'bpmn:CategoryValue'
48011	  ]);
48012	};
48013
48014	BpmnFactory.prototype._ensureId = function(element) {
48015
48016	  // generate semantic ids for elements
48017	  // bpmn:SequenceFlow -> SequenceFlow_ID
48018	  var prefix;
48019
48020	  if (is$1(element, 'bpmn:Activity')) {
48021	    prefix = 'Activity';
48022	  } else if (is$1(element, 'bpmn:Event')) {
48023	    prefix = 'Event';
48024	  } else if (is$1(element, 'bpmn:Gateway')) {
48025	    prefix = 'Gateway';
48026	  } else if (isAny(element, [ 'bpmn:SequenceFlow', 'bpmn:MessageFlow' ])) {
48027	    prefix = 'Flow';
48028	  } else {
48029	    prefix = (element.$type || '').replace(/^[^:]*:/g, '');
48030	  }
48031
48032	  prefix += '_';
48033
48034	  if (!element.id && this._needsId(element)) {
48035	    element.id = this._model.ids.nextPrefixed(prefix, element);
48036	  }
48037	};
48038
48039
48040	BpmnFactory.prototype.create = function(type, attrs) {
48041	  var element = this._model.create(type, attrs || {});
48042
48043	  this._ensureId(element);
48044
48045	  return element;
48046	};
48047
48048
48049	BpmnFactory.prototype.createDiLabel = function() {
48050	  return this.create('bpmndi:BPMNLabel', {
48051	    bounds: this.createDiBounds()
48052	  });
48053	};
48054
48055
48056	BpmnFactory.prototype.createDiShape = function(semantic, bounds, attrs) {
48057
48058	  return this.create('bpmndi:BPMNShape', assign({
48059	    bpmnElement: semantic,
48060	    bounds: this.createDiBounds(bounds)
48061	  }, attrs));
48062	};
48063
48064
48065	BpmnFactory.prototype.createDiBounds = function(bounds) {
48066	  return this.create('dc:Bounds', bounds);
48067	};
48068
48069
48070	BpmnFactory.prototype.createDiWaypoints = function(waypoints) {
48071	  var self = this;
48072
48073	  return map$1(waypoints, function(pos) {
48074	    return self.createDiWaypoint(pos);
48075	  });
48076	};
48077
48078	BpmnFactory.prototype.createDiWaypoint = function(point) {
48079	  return this.create('dc:Point', pick(point, [ 'x', 'y' ]));
48080	};
48081
48082
48083	BpmnFactory.prototype.createDiEdge = function(semantic, waypoints, attrs) {
48084	  return this.create('bpmndi:BPMNEdge', assign({
48085	    bpmnElement: semantic
48086	  }, attrs));
48087	};
48088
48089	BpmnFactory.prototype.createDiPlane = function(semantic) {
48090	  return this.create('bpmndi:BPMNPlane', {
48091	    bpmnElement: semantic
48092	  });
48093	};
48094
48095	/**
48096	 * A handler responsible for updating the underlying BPMN 2.0 XML + DI
48097	 * once changes on the diagram happen
48098	 */
48099	function BpmnUpdater(
48100	    eventBus, bpmnFactory, connectionDocking,
48101	    translate) {
48102
48103	  CommandInterceptor.call(this, eventBus);
48104
48105	  this._bpmnFactory = bpmnFactory;
48106	  this._translate = translate;
48107
48108	  var self = this;
48109
48110
48111
48112	  // connection cropping //////////////////////
48113
48114	  // crop connection ends during create/update
48115	  function cropConnection(e) {
48116	    var context = e.context,
48117	        hints = context.hints || {},
48118	        connection;
48119
48120	    if (!context.cropped && hints.createElementsBehavior !== false) {
48121	      connection = context.connection;
48122	      connection.waypoints = connectionDocking.getCroppedWaypoints(connection);
48123	      context.cropped = true;
48124	    }
48125	  }
48126
48127	  this.executed([
48128	    'connection.layout',
48129	    'connection.create'
48130	  ], cropConnection);
48131
48132	  this.reverted([ 'connection.layout' ], function(e) {
48133	    delete e.context.cropped;
48134	  });
48135
48136
48137
48138	  // BPMN + DI update //////////////////////
48139
48140
48141	  // update parent
48142	  function updateParent(e) {
48143	    var context = e.context;
48144
48145	    self.updateParent(context.shape || context.connection, context.oldParent);
48146	  }
48147
48148	  function reverseUpdateParent(e) {
48149	    var context = e.context;
48150
48151	    var element = context.shape || context.connection,
48152
48153	        // oldParent is the (old) new parent, because we are undoing
48154	        oldParent = context.parent || context.newParent;
48155
48156	    self.updateParent(element, oldParent);
48157	  }
48158
48159	  this.executed([
48160	    'shape.move',
48161	    'shape.create',
48162	    'shape.delete',
48163	    'connection.create',
48164	    'connection.move',
48165	    'connection.delete'
48166	  ], ifBpmn(updateParent));
48167
48168	  this.reverted([
48169	    'shape.move',
48170	    'shape.create',
48171	    'shape.delete',
48172	    'connection.create',
48173	    'connection.move',
48174	    'connection.delete'
48175	  ], ifBpmn(reverseUpdateParent));
48176
48177	  /*
48178	   * ## Updating Parent
48179	   *
48180	   * When morphing a Process into a Collaboration or vice-versa,
48181	   * make sure that both the *semantic* and *di* parent of each element
48182	   * is updated.
48183	   *
48184	   */
48185	  function updateRoot(event) {
48186	    var context = event.context,
48187	        oldRoot = context.oldRoot,
48188	        children = oldRoot.children;
48189
48190	    forEach(children, function(child) {
48191	      if (is$1(child, 'bpmn:BaseElement')) {
48192	        self.updateParent(child);
48193	      }
48194	    });
48195	  }
48196
48197	  this.executed([ 'canvas.updateRoot' ], updateRoot);
48198	  this.reverted([ 'canvas.updateRoot' ], updateRoot);
48199
48200
48201	  // update bounds
48202	  function updateBounds(e) {
48203	    var shape = e.context.shape;
48204
48205	    if (!is$1(shape, 'bpmn:BaseElement')) {
48206	      return;
48207	    }
48208
48209	    self.updateBounds(shape);
48210	  }
48211
48212	  this.executed([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
48213
48214	    // exclude labels because they're handled separately during shape.changed
48215	    if (event.context.shape.type === 'label') {
48216	      return;
48217	    }
48218
48219	    updateBounds(event);
48220	  }));
48221
48222	  this.reverted([ 'shape.move', 'shape.create', 'shape.resize' ], ifBpmn(function(event) {
48223
48224	    // exclude labels because they're handled separately during shape.changed
48225	    if (event.context.shape.type === 'label') {
48226	      return;
48227	    }
48228
48229	    updateBounds(event);
48230	  }));
48231
48232	  // Handle labels separately. This is necessary, because the label bounds have to be updated
48233	  // every time its shape changes, not only on move, create and resize.
48234	  eventBus.on('shape.changed', function(event) {
48235	    if (event.element.type === 'label') {
48236	      updateBounds({ context: { shape: event.element } });
48237	    }
48238	  });
48239
48240	  // attach / detach connection
48241	  function updateConnection(e) {
48242	    self.updateConnection(e.context);
48243	  }
48244
48245	  this.executed([
48246	    'connection.create',
48247	    'connection.move',
48248	    'connection.delete',
48249	    'connection.reconnect'
48250	  ], ifBpmn(updateConnection));
48251
48252	  this.reverted([
48253	    'connection.create',
48254	    'connection.move',
48255	    'connection.delete',
48256	    'connection.reconnect'
48257	  ], ifBpmn(updateConnection));
48258
48259
48260	  // update waypoints
48261	  function updateConnectionWaypoints(e) {
48262	    self.updateConnectionWaypoints(e.context.connection);
48263	  }
48264
48265	  this.executed([
48266	    'connection.layout',
48267	    'connection.move',
48268	    'connection.updateWaypoints',
48269	  ], ifBpmn(updateConnectionWaypoints));
48270
48271	  this.reverted([
48272	    'connection.layout',
48273	    'connection.move',
48274	    'connection.updateWaypoints',
48275	  ], ifBpmn(updateConnectionWaypoints));
48276
48277	  // update conditional/default flows
48278	  this.executed('connection.reconnect', ifBpmn(function(event) {
48279	    var context = event.context,
48280	        connection = context.connection,
48281	        oldSource = context.oldSource,
48282	        newSource = context.newSource,
48283	        connectionBo = getBusinessObject(connection),
48284	        oldSourceBo = getBusinessObject(oldSource),
48285	        newSourceBo = getBusinessObject(newSource);
48286
48287	    // remove condition from connection on reconnect to new source
48288	    // if new source can NOT have condional sequence flow
48289	    if (connectionBo.conditionExpression && !isAny(newSourceBo, [
48290	      'bpmn:Activity',
48291	      'bpmn:ExclusiveGateway',
48292	      'bpmn:InclusiveGateway'
48293	    ])) {
48294	      context.oldConditionExpression = connectionBo.conditionExpression;
48295
48296	      delete connectionBo.conditionExpression;
48297	    }
48298
48299	    // remove default from old source flow on reconnect to new source
48300	    // if source changed
48301	    if (oldSource !== newSource && oldSourceBo.default === connectionBo) {
48302	      context.oldDefault = oldSourceBo.default;
48303
48304	      delete oldSourceBo.default;
48305	    }
48306	  }));
48307
48308	  this.reverted('connection.reconnect', ifBpmn(function(event) {
48309	    var context = event.context,
48310	        connection = context.connection,
48311	        oldSource = context.oldSource,
48312	        newSource = context.newSource,
48313	        connectionBo = getBusinessObject(connection),
48314	        oldSourceBo = getBusinessObject(oldSource),
48315	        newSourceBo = getBusinessObject(newSource);
48316
48317	    // add condition to connection on revert reconnect to new source
48318	    if (context.oldConditionExpression) {
48319	      connectionBo.conditionExpression = context.oldConditionExpression;
48320	    }
48321
48322	    // add default to old source on revert reconnect to new source
48323	    if (context.oldDefault) {
48324	      oldSourceBo.default = context.oldDefault;
48325
48326	      delete newSourceBo.default;
48327	    }
48328	  }));
48329
48330	  // update attachments
48331	  function updateAttachment(e) {
48332	    self.updateAttachment(e.context);
48333	  }
48334
48335	  this.executed([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
48336	  this.reverted([ 'element.updateAttachment' ], ifBpmn(updateAttachment));
48337	}
48338
48339	inherits$1(BpmnUpdater, CommandInterceptor);
48340
48341	BpmnUpdater.$inject = [
48342	  'eventBus',
48343	  'bpmnFactory',
48344	  'connectionDocking',
48345	  'translate'
48346	];
48347
48348
48349	// implementation //////////////////////
48350
48351	BpmnUpdater.prototype.updateAttachment = function(context) {
48352
48353	  var shape = context.shape,
48354	      businessObject = shape.businessObject,
48355	      host = shape.host;
48356
48357	  businessObject.attachedToRef = host && host.businessObject;
48358	};
48359
48360	BpmnUpdater.prototype.updateParent = function(element, oldParent) {
48361
48362	  // do not update BPMN 2.0 label parent
48363	  if (element instanceof Label) {
48364	    return;
48365	  }
48366
48367	  // data stores in collaborations are handled separately by DataStoreBehavior
48368	  if (is$1(element, 'bpmn:DataStoreReference') &&
48369	      element.parent &&
48370	      is$1(element.parent, 'bpmn:Collaboration')) {
48371	    return;
48372	  }
48373
48374	  var parentShape = element.parent;
48375
48376	  var businessObject = element.businessObject,
48377	      parentBusinessObject = parentShape && parentShape.businessObject,
48378	      parentDi = parentBusinessObject && parentBusinessObject.di;
48379
48380	  if (is$1(element, 'bpmn:FlowNode')) {
48381	    this.updateFlowNodeRefs(businessObject, parentBusinessObject, oldParent && oldParent.businessObject);
48382	  }
48383
48384	  if (is$1(element, 'bpmn:DataOutputAssociation')) {
48385	    if (element.source) {
48386	      parentBusinessObject = element.source.businessObject;
48387	    } else {
48388	      parentBusinessObject = null;
48389	    }
48390	  }
48391
48392	  if (is$1(element, 'bpmn:DataInputAssociation')) {
48393	    if (element.target) {
48394	      parentBusinessObject = element.target.businessObject;
48395	    } else {
48396	      parentBusinessObject = null;
48397	    }
48398	  }
48399
48400	  this.updateSemanticParent(businessObject, parentBusinessObject);
48401
48402	  if (is$1(element, 'bpmn:DataObjectReference') && businessObject.dataObjectRef) {
48403	    this.updateSemanticParent(businessObject.dataObjectRef, parentBusinessObject);
48404	  }
48405
48406	  this.updateDiParent(businessObject.di, parentDi);
48407	};
48408
48409
48410	BpmnUpdater.prototype.updateBounds = function(shape) {
48411
48412	  var di = shape.businessObject.di;
48413
48414	  var target = (shape instanceof Label) ? this._getLabel(di) : di;
48415
48416	  var bounds = target.bounds;
48417
48418	  if (!bounds) {
48419	    bounds = this._bpmnFactory.createDiBounds();
48420	    target.set('bounds', bounds);
48421	  }
48422
48423	  assign(bounds, {
48424	    x: shape.x,
48425	    y: shape.y,
48426	    width: shape.width,
48427	    height: shape.height
48428	  });
48429	};
48430
48431	BpmnUpdater.prototype.updateFlowNodeRefs = function(businessObject, newContainment, oldContainment) {
48432
48433	  if (oldContainment === newContainment) {
48434	    return;
48435	  }
48436
48437	  var oldRefs, newRefs;
48438
48439	  if (is$1 (oldContainment, 'bpmn:Lane')) {
48440	    oldRefs = oldContainment.get('flowNodeRef');
48441	    remove(oldRefs, businessObject);
48442	  }
48443
48444	  if (is$1(newContainment, 'bpmn:Lane')) {
48445	    newRefs = newContainment.get('flowNodeRef');
48446	    add(newRefs, businessObject);
48447	  }
48448	};
48449
48450
48451	// update existing sourceElement and targetElement di information
48452	BpmnUpdater.prototype.updateDiConnection = function(di, newSource, newTarget) {
48453
48454	  if (di.sourceElement && di.sourceElement.bpmnElement !== newSource) {
48455	    di.sourceElement = newSource && newSource.di;
48456	  }
48457
48458	  if (di.targetElement && di.targetElement.bpmnElement !== newTarget) {
48459	    di.targetElement = newTarget && newTarget.di;
48460	  }
48461
48462	};
48463
48464
48465	BpmnUpdater.prototype.updateDiParent = function(di, parentDi) {
48466
48467	  if (parentDi && !is$1(parentDi, 'bpmndi:BPMNPlane')) {
48468	    parentDi = parentDi.$parent;
48469	  }
48470
48471	  if (di.$parent === parentDi) {
48472	    return;
48473	  }
48474
48475	  var planeElements = (parentDi || di.$parent).get('planeElement');
48476
48477	  if (parentDi) {
48478	    planeElements.push(di);
48479	    di.$parent = parentDi;
48480	  } else {
48481	    remove(planeElements, di);
48482	    di.$parent = null;
48483	  }
48484	};
48485
48486	function getDefinitions(element) {
48487	  while (element && !is$1(element, 'bpmn:Definitions')) {
48488	    element = element.$parent;
48489	  }
48490
48491	  return element;
48492	}
48493
48494	BpmnUpdater.prototype.getLaneSet = function(container) {
48495
48496	  var laneSet, laneSets;
48497
48498	  // bpmn:Lane
48499	  if (is$1(container, 'bpmn:Lane')) {
48500	    laneSet = container.childLaneSet;
48501
48502	    if (!laneSet) {
48503	      laneSet = this._bpmnFactory.create('bpmn:LaneSet');
48504	      container.childLaneSet = laneSet;
48505	      laneSet.$parent = container;
48506	    }
48507
48508	    return laneSet;
48509	  }
48510
48511	  // bpmn:Participant
48512	  if (is$1(container, 'bpmn:Participant')) {
48513	    container = container.processRef;
48514	  }
48515
48516	  // bpmn:FlowElementsContainer
48517	  laneSets = container.get('laneSets');
48518	  laneSet = laneSets[0];
48519
48520	  if (!laneSet) {
48521	    laneSet = this._bpmnFactory.create('bpmn:LaneSet');
48522	    laneSet.$parent = container;
48523	    laneSets.push(laneSet);
48524	  }
48525
48526	  return laneSet;
48527	};
48528
48529	BpmnUpdater.prototype.updateSemanticParent = function(businessObject, newParent, visualParent) {
48530
48531	  var containment,
48532	      translate = this._translate;
48533
48534	  if (businessObject.$parent === newParent) {
48535	    return;
48536	  }
48537
48538	  if (is$1(businessObject, 'bpmn:DataInput') || is$1(businessObject, 'bpmn:DataOutput')) {
48539
48540	    if (is$1(newParent, 'bpmn:Participant') && 'processRef' in newParent) {
48541	      newParent = newParent.processRef;
48542	    }
48543
48544	    // already in correct ioSpecification
48545	    if ('ioSpecification' in newParent && newParent.ioSpecification === businessObject.$parent) {
48546	      return;
48547	    }
48548	  }
48549
48550	  if (is$1(businessObject, 'bpmn:Lane')) {
48551
48552	    if (newParent) {
48553	      newParent = this.getLaneSet(newParent);
48554	    }
48555
48556	    containment = 'lanes';
48557	  } else
48558
48559	  if (is$1(businessObject, 'bpmn:FlowElement')) {
48560
48561	    if (newParent) {
48562
48563	      if (is$1(newParent, 'bpmn:Participant')) {
48564	        newParent = newParent.processRef;
48565	      } else
48566
48567	      if (is$1(newParent, 'bpmn:Lane')) {
48568	        do {
48569
48570	          // unwrap Lane -> LaneSet -> (Lane | FlowElementsContainer)
48571	          newParent = newParent.$parent.$parent;
48572	        } while (is$1(newParent, 'bpmn:Lane'));
48573
48574	      }
48575	    }
48576
48577	    containment = 'flowElements';
48578
48579	  } else
48580
48581	  if (is$1(businessObject, 'bpmn:Artifact')) {
48582
48583	    while (newParent &&
48584	           !is$1(newParent, 'bpmn:Process') &&
48585	           !is$1(newParent, 'bpmn:SubProcess') &&
48586	           !is$1(newParent, 'bpmn:Collaboration')) {
48587
48588	      if (is$1(newParent, 'bpmn:Participant')) {
48589	        newParent = newParent.processRef;
48590	        break;
48591	      } else {
48592	        newParent = newParent.$parent;
48593	      }
48594	    }
48595
48596	    containment = 'artifacts';
48597	  } else
48598
48599	  if (is$1(businessObject, 'bpmn:MessageFlow')) {
48600	    containment = 'messageFlows';
48601
48602	  } else
48603
48604	  if (is$1(businessObject, 'bpmn:Participant')) {
48605	    containment = 'participants';
48606
48607	    // make sure the participants process is properly attached / detached
48608	    // from the XML document
48609
48610	    var process = businessObject.processRef,
48611	        definitions;
48612
48613	    if (process) {
48614	      definitions = getDefinitions(businessObject.$parent || newParent);
48615
48616	      if (businessObject.$parent) {
48617	        remove(definitions.get('rootElements'), process);
48618	        process.$parent = null;
48619	      }
48620
48621	      if (newParent) {
48622	        add(definitions.get('rootElements'), process);
48623	        process.$parent = definitions;
48624	      }
48625	    }
48626	  } else
48627
48628	  if (is$1(businessObject, 'bpmn:DataOutputAssociation')) {
48629	    containment = 'dataOutputAssociations';
48630	  } else
48631
48632	  if (is$1(businessObject, 'bpmn:DataInputAssociation')) {
48633	    containment = 'dataInputAssociations';
48634	  }
48635
48636	  if (!containment) {
48637	    throw new Error(translate(
48638	      'no parent for {element} in {parent}',
48639	      {
48640	        element: businessObject.id,
48641	        parent: newParent.id
48642	      }
48643	    ));
48644	  }
48645
48646	  var children;
48647
48648	  if (businessObject.$parent) {
48649
48650	    // remove from old parent
48651	    children = businessObject.$parent.get(containment);
48652	    remove(children, businessObject);
48653	  }
48654
48655	  if (!newParent) {
48656	    businessObject.$parent = null;
48657	  } else {
48658
48659	    // add to new parent
48660	    children = newParent.get(containment);
48661	    children.push(businessObject);
48662	    businessObject.$parent = newParent;
48663	  }
48664
48665	  if (visualParent) {
48666	    var diChildren = visualParent.get(containment);
48667
48668	    remove(children, businessObject);
48669
48670	    if (newParent) {
48671
48672	      if (!diChildren) {
48673	        diChildren = [];
48674	        newParent.set(containment, diChildren);
48675	      }
48676
48677	      diChildren.push(businessObject);
48678	    }
48679	  }
48680	};
48681
48682
48683	BpmnUpdater.prototype.updateConnectionWaypoints = function(connection) {
48684	  connection.businessObject.di.set('waypoint', this._bpmnFactory.createDiWaypoints(connection.waypoints));
48685	};
48686
48687
48688	BpmnUpdater.prototype.updateConnection = function(context) {
48689
48690	  var connection = context.connection,
48691	      businessObject = getBusinessObject(connection),
48692	      newSource = getBusinessObject(connection.source),
48693	      newTarget = getBusinessObject(connection.target),
48694	      visualParent;
48695
48696	  if (!is$1(businessObject, 'bpmn:DataAssociation')) {
48697
48698	    var inverseSet = is$1(businessObject, 'bpmn:SequenceFlow');
48699
48700	    if (businessObject.sourceRef !== newSource) {
48701	      if (inverseSet) {
48702	        remove(businessObject.sourceRef && businessObject.sourceRef.get('outgoing'), businessObject);
48703
48704	        if (newSource && newSource.get('outgoing')) {
48705	          newSource.get('outgoing').push(businessObject);
48706	        }
48707	      }
48708
48709	      businessObject.sourceRef = newSource;
48710	    }
48711
48712	    if (businessObject.targetRef !== newTarget) {
48713	      if (inverseSet) {
48714	        remove(businessObject.targetRef && businessObject.targetRef.get('incoming'), businessObject);
48715
48716	        if (newTarget && newTarget.get('incoming')) {
48717	          newTarget.get('incoming').push(businessObject);
48718	        }
48719	      }
48720
48721	      businessObject.targetRef = newTarget;
48722	    }
48723	  } else
48724
48725	  if (is$1(businessObject, 'bpmn:DataInputAssociation')) {
48726
48727	    // handle obnoxious isMsome sourceRef
48728	    businessObject.get('sourceRef')[0] = newSource;
48729
48730	    visualParent = context.parent || context.newParent || newTarget;
48731
48732	    this.updateSemanticParent(businessObject, newTarget, visualParent);
48733	  } else
48734
48735	  if (is$1(businessObject, 'bpmn:DataOutputAssociation')) {
48736	    visualParent = context.parent || context.newParent || newSource;
48737
48738	    this.updateSemanticParent(businessObject, newSource, visualParent);
48739
48740	    // targetRef = new target
48741	    businessObject.targetRef = newTarget;
48742	  }
48743
48744	  this.updateConnectionWaypoints(connection);
48745
48746	  this.updateDiConnection(businessObject.di, newSource, newTarget);
48747	};
48748
48749
48750	// helpers //////////////////////
48751
48752	BpmnUpdater.prototype._getLabel = function(di) {
48753	  if (!di.label) {
48754	    di.label = this._bpmnFactory.createDiLabel();
48755	  }
48756
48757	  return di.label;
48758	};
48759
48760
48761	/**
48762	 * Make sure the event listener is only called
48763	 * if the touched element is a BPMN element.
48764	 *
48765	 * @param  {Function} fn
48766	 * @return {Function} guarded function
48767	 */
48768	function ifBpmn(fn) {
48769
48770	  return function(event) {
48771
48772	    var context = event.context,
48773	        element = context.shape || context.connection;
48774
48775	    if (is$1(element, 'bpmn:BaseElement')) {
48776	      fn(event);
48777	    }
48778	  };
48779	}
48780
48781	/**
48782	 * A bpmn-aware factory for diagram-js shapes
48783	 */
48784	function ElementFactory(bpmnFactory, moddle, translate) {
48785	  ElementFactory$1.call(this);
48786
48787	  this._bpmnFactory = bpmnFactory;
48788	  this._moddle = moddle;
48789	  this._translate = translate;
48790	}
48791
48792	inherits$1(ElementFactory, ElementFactory$1);
48793
48794	ElementFactory.$inject = [
48795	  'bpmnFactory',
48796	  'moddle',
48797	  'translate'
48798	];
48799
48800	ElementFactory.prototype.baseCreate = ElementFactory$1.prototype.create;
48801
48802	ElementFactory.prototype.create = function(elementType, attrs) {
48803
48804	  // no special magic for labels,
48805	  // we assume their businessObjects have already been created
48806	  // and wired via attrs
48807	  if (elementType === 'label') {
48808	    return this.baseCreate(elementType, assign({ type: 'label' }, DEFAULT_LABEL_SIZE, attrs));
48809	  }
48810
48811	  return this.createBpmnElement(elementType, attrs);
48812	};
48813
48814	ElementFactory.prototype.createBpmnElement = function(elementType, attrs) {
48815	  var size,
48816	      translate = this._translate;
48817
48818	  attrs = attrs || {};
48819
48820	  var businessObject = attrs.businessObject;
48821
48822	  if (!businessObject) {
48823	    if (!attrs.type) {
48824	      throw new Error(translate('no shape type specified'));
48825	    }
48826
48827	    businessObject = this._bpmnFactory.create(attrs.type);
48828	  }
48829
48830	  if (!businessObject.di) {
48831	    if (elementType === 'root') {
48832	      businessObject.di = this._bpmnFactory.createDiPlane(businessObject, [], {
48833	        id: businessObject.id + '_di'
48834	      });
48835	    } else
48836	    if (elementType === 'connection') {
48837	      businessObject.di = this._bpmnFactory.createDiEdge(businessObject, [], {
48838	        id: businessObject.id + '_di'
48839	      });
48840	    } else {
48841	      businessObject.di = this._bpmnFactory.createDiShape(businessObject, {}, {
48842	        id: businessObject.id + '_di'
48843	      });
48844	    }
48845	  }
48846
48847	  if (is$1(businessObject, 'bpmn:Group')) {
48848	    attrs = assign({
48849	      isFrame: true
48850	    }, attrs);
48851	  }
48852
48853	  if (attrs.di) {
48854	    assign(businessObject.di, attrs.di);
48855
48856	    delete attrs.di;
48857	  }
48858
48859	  applyAttributes(businessObject, attrs, [
48860	    'processRef',
48861	    'isInterrupting',
48862	    'associationDirection',
48863	    'isForCompensation'
48864	  ]);
48865
48866	  if (attrs.isExpanded) {
48867	    applyAttribute(businessObject.di, attrs, 'isExpanded');
48868	  }
48869
48870	  if (is$1(businessObject, 'bpmn:ExclusiveGateway')) {
48871	    businessObject.di.isMarkerVisible = true;
48872	  }
48873
48874	  var eventDefinitions,
48875	      newEventDefinition;
48876
48877	  if (attrs.eventDefinitionType) {
48878	    eventDefinitions = businessObject.get('eventDefinitions') || [];
48879	    newEventDefinition = this._bpmnFactory.create(attrs.eventDefinitionType, attrs.eventDefinitionAttrs);
48880
48881	    if (attrs.eventDefinitionType === 'bpmn:ConditionalEventDefinition') {
48882	      newEventDefinition.condition = this._bpmnFactory.create('bpmn:FormalExpression');
48883	    }
48884
48885	    eventDefinitions.push(newEventDefinition);
48886
48887	    newEventDefinition.$parent = businessObject;
48888	    businessObject.eventDefinitions = eventDefinitions;
48889
48890	    delete attrs.eventDefinitionType;
48891	  }
48892
48893	  size = this._getDefaultSize(businessObject);
48894
48895	  attrs = assign({
48896	    businessObject: businessObject,
48897	    id: businessObject.id
48898	  }, size, attrs);
48899
48900	  return this.baseCreate(elementType, attrs);
48901	};
48902
48903
48904	ElementFactory.prototype._getDefaultSize = function(semantic) {
48905
48906	  if (is$1(semantic, 'bpmn:SubProcess')) {
48907
48908	    if (isExpanded(semantic)) {
48909	      return { width: 350, height: 200 };
48910	    } else {
48911	      return { width: 100, height: 80 };
48912	    }
48913	  }
48914
48915	  if (is$1(semantic, 'bpmn:Task')) {
48916	    return { width: 100, height: 80 };
48917	  }
48918
48919	  if (is$1(semantic, 'bpmn:Gateway')) {
48920	    return { width: 50, height: 50 };
48921	  }
48922
48923	  if (is$1(semantic, 'bpmn:Event')) {
48924	    return { width: 36, height: 36 };
48925	  }
48926
48927	  if (is$1(semantic, 'bpmn:Participant')) {
48928	    if (isExpanded(semantic)) {
48929	      return { width: 600, height: 250 };
48930	    } else {
48931	      return { width: 400, height: 60 };
48932	    }
48933	  }
48934
48935	  if (is$1(semantic, 'bpmn:Lane')) {
48936	    return { width: 400, height: 100 };
48937	  }
48938
48939	  if (is$1(semantic, 'bpmn:DataObjectReference')) {
48940	    return { width: 36, height: 50 };
48941	  }
48942
48943	  if (is$1(semantic, 'bpmn:DataStoreReference')) {
48944	    return { width: 50, height: 50 };
48945	  }
48946
48947	  if (is$1(semantic, 'bpmn:TextAnnotation')) {
48948	    return { width: 100, height: 30 };
48949	  }
48950
48951	  if (is$1(semantic, 'bpmn:Group')) {
48952	    return { width: 300, height: 300 };
48953	  }
48954
48955	  return { width: 100, height: 80 };
48956	};
48957
48958
48959	/**
48960	 * Create participant.
48961	 *
48962	 * @param {boolean|Object} [attrs] attrs
48963	 *
48964	 * @returns {djs.model.Shape}
48965	 */
48966	ElementFactory.prototype.createParticipantShape = function(attrs) {
48967
48968	  if (!isObject(attrs)) {
48969	    attrs = { isExpanded: attrs };
48970	  }
48971
48972	  attrs = assign({ type: 'bpmn:Participant' }, attrs || {});
48973
48974	  // participants are expanded by default
48975	  if (attrs.isExpanded !== false) {
48976	    attrs.processRef = this._bpmnFactory.create('bpmn:Process');
48977	  }
48978
48979	  return this.createShape(attrs);
48980	};
48981
48982
48983	// helpers //////////////////////
48984
48985	/**
48986	 * Apply attributes from a map to the given element,
48987	 * remove attribute from the map on application.
48988	 *
48989	 * @param {Base} element
48990	 * @param {Object} attrs (in/out map of attributes)
48991	 * @param {Array<string>} attributeNames name of attributes to apply
48992	 */
48993	function applyAttributes(element, attrs, attributeNames) {
48994
48995	  forEach(attributeNames, function(property) {
48996	    if (attrs[property] !== undefined) {
48997	      applyAttribute(element, attrs, property);
48998	    }
48999	  });
49000	}
49001
49002	/**
49003	 * Apply named property to element and drain it from the attrs
49004	 * collection.
49005	 *
49006	 * @param {Base} element
49007	 * @param {Object} attrs (in/out map of attributes)
49008	 * @param {string} attributeName to apply
49009	 */
49010	function applyAttribute(element, attrs, attributeName) {
49011	  element[attributeName] = attrs[attributeName];
49012
49013	  delete attrs[attributeName];
49014	}
49015
49016	/**
49017	 * A handler that align elements in a certain way.
49018	 *
49019	 */
49020	function AlignElements(modeling, canvas) {
49021	  this._modeling = modeling;
49022	  this._canvas = canvas;
49023	}
49024
49025	AlignElements.$inject = [ 'modeling', 'canvas' ];
49026
49027
49028	AlignElements.prototype.preExecute = function(context) {
49029	  var modeling = this._modeling;
49030
49031	  var elements = context.elements,
49032	      alignment = context.alignment;
49033
49034
49035	  forEach(elements, function(element) {
49036	    var delta = {
49037	      x: 0,
49038	      y: 0
49039	    };
49040
49041	    if (alignment.left) {
49042	      delta.x = alignment.left - element.x;
49043
49044	    } else if (alignment.right) {
49045	      delta.x = (alignment.right - element.width) - element.x;
49046
49047	    } else if (alignment.center) {
49048	      delta.x = (alignment.center - Math.round(element.width / 2)) - element.x;
49049
49050	    } else if (alignment.top) {
49051	      delta.y = alignment.top - element.y;
49052
49053	    } else if (alignment.bottom) {
49054	      delta.y = (alignment.bottom - element.height) - element.y;
49055
49056	    } else if (alignment.middle) {
49057	      delta.y = (alignment.middle - Math.round(element.height / 2)) - element.y;
49058	    }
49059
49060	    modeling.moveElements([ element ], delta, element.parent);
49061	  });
49062	};
49063
49064	AlignElements.prototype.postExecute = function(context) {
49065
49066	};
49067
49068	/**
49069	 * A handler that implements reversible appending of shapes
49070	 * to a source shape.
49071	 *
49072	 * @param {canvas} Canvas
49073	 * @param {elementFactory} ElementFactory
49074	 * @param {modeling} Modeling
49075	 */
49076	function AppendShapeHandler(modeling) {
49077	  this._modeling = modeling;
49078	}
49079
49080	AppendShapeHandler.$inject = [ 'modeling' ];
49081
49082
49083	// api //////////////////////
49084
49085
49086	/**
49087	 * Creates a new shape
49088	 *
49089	 * @param {Object} context
49090	 * @param {ElementDescriptor} context.shape the new shape
49091	 * @param {ElementDescriptor} context.source the source object
49092	 * @param {ElementDescriptor} context.parent the parent object
49093	 * @param {Point} context.position position of the new element
49094	 */
49095	AppendShapeHandler.prototype.preExecute = function(context) {
49096
49097	  var source = context.source;
49098
49099	  if (!source) {
49100	    throw new Error('source required');
49101	  }
49102
49103	  var target = context.target || source.parent,
49104	      shape = context.shape,
49105	      hints = context.hints || {};
49106
49107	  shape = context.shape =
49108	    this._modeling.createShape(
49109	      shape,
49110	      context.position,
49111	      target, { attach: hints.attach });
49112
49113	  context.shape = shape;
49114	};
49115
49116	AppendShapeHandler.prototype.postExecute = function(context) {
49117	  var hints = context.hints || {};
49118
49119	  if (!existsConnection(context.source, context.shape)) {
49120
49121	    // create connection
49122	    if (hints.connectionTarget === context.source) {
49123	      this._modeling.connect(context.shape, context.source, context.connection);
49124	    } else {
49125	      this._modeling.connect(context.source, context.shape, context.connection);
49126	    }
49127	  }
49128	};
49129
49130
49131	function existsConnection(source, target) {
49132	  return some(source.outgoing, function(c) {
49133	    return c.target === target;
49134	  });
49135	}
49136
49137	function CreateConnectionHandler(canvas, layouter) {
49138	  this._canvas = canvas;
49139	  this._layouter = layouter;
49140	}
49141
49142	CreateConnectionHandler.$inject = [ 'canvas', 'layouter' ];
49143
49144
49145	// api //////////////////////
49146
49147
49148	/**
49149	 * Appends a shape to a target shape
49150	 *
49151	 * @param {Object} context
49152	 * @param {djs.element.Base} context.source the source object
49153	 * @param {djs.element.Base} context.target the parent object
49154	 * @param {Point} context.position position of the new element
49155	 */
49156	CreateConnectionHandler.prototype.execute = function(context) {
49157
49158	  var connection = context.connection,
49159	      source = context.source,
49160	      target = context.target,
49161	      parent = context.parent,
49162	      parentIndex = context.parentIndex,
49163	      hints = context.hints;
49164
49165	  if (!source || !target) {
49166	    throw new Error('source and target required');
49167	  }
49168
49169	  if (!parent) {
49170	    throw new Error('parent required');
49171	  }
49172
49173	  connection.source = source;
49174	  connection.target = target;
49175
49176	  if (!connection.waypoints) {
49177	    connection.waypoints = this._layouter.layoutConnection(connection, hints);
49178	  }
49179
49180	  // add connection
49181	  this._canvas.addConnection(connection, parent, parentIndex);
49182
49183	  return connection;
49184	};
49185
49186	CreateConnectionHandler.prototype.revert = function(context) {
49187	  var connection = context.connection;
49188
49189	  this._canvas.removeConnection(connection);
49190
49191	  connection.source = null;
49192	  connection.target = null;
49193
49194	  return connection;
49195	};
49196
49197	var round$3 = Math.round;
49198
49199	function CreateElementsHandler(modeling) {
49200	  this._modeling = modeling;
49201	}
49202
49203	CreateElementsHandler.$inject = [
49204	  'modeling'
49205	];
49206
49207	CreateElementsHandler.prototype.preExecute = function(context) {
49208	  var elements = context.elements,
49209	      parent = context.parent,
49210	      parentIndex = context.parentIndex,
49211	      position = context.position,
49212	      hints = context.hints;
49213
49214	  var modeling = this._modeling;
49215
49216	  // make sure each element has x and y
49217	  forEach(elements, function(element) {
49218	    if (!isNumber(element.x)) {
49219	      element.x = 0;
49220	    }
49221
49222	    if (!isNumber(element.y)) {
49223	      element.y = 0;
49224	    }
49225	  });
49226
49227	  var bbox = getBBox(elements);
49228
49229	  // center elements around position
49230	  forEach(elements, function(element) {
49231	    if (isConnection$5(element)) {
49232	      element.waypoints = map$1(element.waypoints, function(waypoint) {
49233	        return {
49234	          x: round$3(waypoint.x - bbox.x - bbox.width / 2 + position.x),
49235	          y: round$3(waypoint.y - bbox.y - bbox.height / 2 + position.y)
49236	        };
49237	      });
49238	    }
49239
49240	    assign(element, {
49241	      x: round$3(element.x - bbox.x - bbox.width / 2 + position.x),
49242	      y: round$3(element.y - bbox.y - bbox.height / 2 + position.y)
49243	    });
49244	  });
49245
49246	  var parents = getParents$1(elements);
49247
49248	  var cache = {};
49249
49250	  forEach(elements, function(element) {
49251	    if (isConnection$5(element)) {
49252	      cache[ element.id ] = isNumber(parentIndex) ?
49253	        modeling.createConnection(
49254	          cache[ element.source.id ],
49255	          cache[ element.target.id ],
49256	          parentIndex,
49257	          element,
49258	          element.parent || parent,
49259	          hints
49260	        ) :
49261	        modeling.createConnection(
49262	          cache[ element.source.id ],
49263	          cache[ element.target.id ],
49264	          element,
49265	          element.parent || parent,
49266	          hints
49267	        );
49268
49269	      return;
49270	    }
49271
49272	    var createShapeHints = assign({}, hints);
49273
49274	    if (parents.indexOf(element) === -1) {
49275	      createShapeHints.autoResize = false;
49276	    }
49277
49278	    cache[ element.id ] = isNumber(parentIndex) ?
49279	      modeling.createShape(
49280	        element,
49281	        pick(element, [ 'x', 'y', 'width', 'height' ]),
49282	        element.parent || parent,
49283	        parentIndex,
49284	        createShapeHints
49285	      ) :
49286	      modeling.createShape(
49287	        element,
49288	        pick(element, [ 'x', 'y', 'width', 'height' ]),
49289	        element.parent || parent,
49290	        createShapeHints
49291	      );
49292	  });
49293
49294	  context.elements = values(cache);
49295	};
49296
49297	// helpers //////////
49298
49299	function isConnection$5(element) {
49300	  return !!element.waypoints;
49301	}
49302
49303	var round$2 = Math.round;
49304
49305
49306	/**
49307	 * A handler that implements reversible addition of shapes.
49308	 *
49309	 * @param {canvas} Canvas
49310	 */
49311	function CreateShapeHandler(canvas) {
49312	  this._canvas = canvas;
49313	}
49314
49315	CreateShapeHandler.$inject = [ 'canvas' ];
49316
49317
49318	// api //////////////////////
49319
49320
49321	/**
49322	 * Appends a shape to a target shape
49323	 *
49324	 * @param {Object} context
49325	 * @param {djs.model.Base} context.parent the parent object
49326	 * @param {Point} context.position position of the new element
49327	 */
49328	CreateShapeHandler.prototype.execute = function(context) {
49329
49330	  var shape = context.shape,
49331	      positionOrBounds = context.position,
49332	      parent = context.parent,
49333	      parentIndex = context.parentIndex;
49334
49335	  if (!parent) {
49336	    throw new Error('parent required');
49337	  }
49338
49339	  if (!positionOrBounds) {
49340	    throw new Error('position required');
49341	  }
49342
49343	  // (1) add at event center position _or_ at given bounds
49344	  if (positionOrBounds.width !== undefined) {
49345	    assign(shape, positionOrBounds);
49346	  } else {
49347	    assign(shape, {
49348	      x: positionOrBounds.x - round$2(shape.width / 2),
49349	      y: positionOrBounds.y - round$2(shape.height / 2)
49350	    });
49351	  }
49352
49353	  // (2) add to canvas
49354	  this._canvas.addShape(shape, parent, parentIndex);
49355
49356	  return shape;
49357	};
49358
49359
49360	/**
49361	 * Undo append by removing the shape
49362	 */
49363	CreateShapeHandler.prototype.revert = function(context) {
49364
49365	  var shape = context.shape;
49366
49367	  // (3) remove form canvas
49368	  this._canvas.removeShape(shape);
49369
49370	  return shape;
49371	};
49372
49373	/**
49374	 * A handler that attaches a label to a given target shape.
49375	 *
49376	 * @param {Canvas} canvas
49377	 */
49378	function CreateLabelHandler(canvas) {
49379	  CreateShapeHandler.call(this, canvas);
49380	}
49381
49382	inherits$1(CreateLabelHandler, CreateShapeHandler);
49383
49384	CreateLabelHandler.$inject = [ 'canvas' ];
49385
49386
49387	// api //////////////////////
49388
49389
49390	var originalExecute = CreateShapeHandler.prototype.execute;
49391
49392	/**
49393	 * Appends a label to a target shape.
49394	 *
49395	 * @method CreateLabelHandler#execute
49396	 *
49397	 * @param {Object} context
49398	 * @param {ElementDescriptor} context.target the element the label is attached to
49399	 * @param {ElementDescriptor} context.parent the parent object
49400	 * @param {Point} context.position position of the new element
49401	 */
49402	CreateLabelHandler.prototype.execute = function(context) {
49403
49404	  var label = context.shape;
49405
49406	  ensureValidDimensions(label);
49407
49408	  label.labelTarget = context.labelTarget;
49409
49410	  return originalExecute.call(this, context);
49411	};
49412
49413	var originalRevert = CreateShapeHandler.prototype.revert;
49414
49415	/**
49416	 * Undo append by removing the shape
49417	 */
49418	CreateLabelHandler.prototype.revert = function(context) {
49419	  context.shape.labelTarget = null;
49420
49421	  return originalRevert.call(this, context);
49422	};
49423
49424
49425	// helpers //////////////////////
49426
49427	function ensureValidDimensions(label) {
49428
49429	  // make sure a label has valid { width, height } dimensions
49430	  [ 'width', 'height' ].forEach(function(prop) {
49431	    if (typeof label[prop] === 'undefined') {
49432	      label[prop] = 0;
49433	    }
49434	  });
49435	}
49436
49437	/**
49438	 * A handler that implements reversible deletion of Connections.
49439	 */
49440	function DeleteConnectionHandler(canvas, modeling) {
49441	  this._canvas = canvas;
49442	  this._modeling = modeling;
49443	}
49444
49445	DeleteConnectionHandler.$inject = [
49446	  'canvas',
49447	  'modeling'
49448	];
49449
49450
49451	DeleteConnectionHandler.prototype.execute = function(context) {
49452
49453	  var connection = context.connection,
49454	      parent = connection.parent;
49455
49456	  context.parent = parent;
49457
49458	  // remember containment
49459	  context.parentIndex = indexOf(parent.children, connection);
49460
49461	  context.source = connection.source;
49462	  context.target = connection.target;
49463
49464	  this._canvas.removeConnection(connection);
49465
49466	  connection.source = null;
49467	  connection.target = null;
49468
49469	  return connection;
49470	};
49471
49472	/**
49473	 * Command revert implementation.
49474	 */
49475	DeleteConnectionHandler.prototype.revert = function(context) {
49476
49477	  var connection = context.connection,
49478	      parent = context.parent,
49479	      parentIndex = context.parentIndex;
49480
49481	  connection.source = context.source;
49482	  connection.target = context.target;
49483
49484	  // restore containment
49485	  add(parent.children, connection, parentIndex);
49486
49487	  this._canvas.addConnection(connection, parent);
49488
49489	  return connection;
49490	};
49491
49492	function DeleteElementsHandler(modeling, elementRegistry) {
49493	  this._modeling = modeling;
49494	  this._elementRegistry = elementRegistry;
49495	}
49496
49497	DeleteElementsHandler.$inject = [
49498	  'modeling',
49499	  'elementRegistry'
49500	];
49501
49502
49503	DeleteElementsHandler.prototype.postExecute = function(context) {
49504
49505	  var modeling = this._modeling,
49506	      elementRegistry = this._elementRegistry,
49507	      elements = context.elements;
49508
49509	  forEach(elements, function(element) {
49510
49511	    // element may have been removed with previous
49512	    // remove operations already (e.g. in case of nesting)
49513	    if (!elementRegistry.get(element.id)) {
49514	      return;
49515	    }
49516
49517	    if (element.waypoints) {
49518	      modeling.removeConnection(element);
49519	    } else {
49520	      modeling.removeShape(element);
49521	    }
49522	  });
49523	};
49524
49525	/**
49526	 * A handler that implements reversible deletion of shapes.
49527	 *
49528	 */
49529	function DeleteShapeHandler(canvas, modeling) {
49530	  this._canvas = canvas;
49531	  this._modeling = modeling;
49532	}
49533
49534	DeleteShapeHandler.$inject = [ 'canvas', 'modeling' ];
49535
49536
49537	/**
49538	 * - Remove connections
49539	 * - Remove all direct children
49540	 */
49541	DeleteShapeHandler.prototype.preExecute = function(context) {
49542
49543	  var modeling = this._modeling;
49544
49545	  var shape = context.shape;
49546
49547	  // remove connections
49548	  saveClear(shape.incoming, function(connection) {
49549
49550	    // To make sure that the connection isn't removed twice
49551	    // For example if a container is removed
49552	    modeling.removeConnection(connection, { nested: true });
49553	  });
49554
49555	  saveClear(shape.outgoing, function(connection) {
49556	    modeling.removeConnection(connection, { nested: true });
49557	  });
49558
49559	  // remove child shapes and connections
49560	  saveClear(shape.children, function(child) {
49561	    if (isConnection$4(child)) {
49562	      modeling.removeConnection(child, { nested: true });
49563	    } else {
49564	      modeling.removeShape(child, { nested: true });
49565	    }
49566	  });
49567	};
49568
49569	/**
49570	 * Remove shape and remember the parent
49571	 */
49572	DeleteShapeHandler.prototype.execute = function(context) {
49573	  var canvas = this._canvas;
49574
49575	  var shape = context.shape,
49576	      oldParent = shape.parent;
49577
49578	  context.oldParent = oldParent;
49579
49580	  // remove containment
49581	  context.oldParentIndex = indexOf(oldParent.children, shape);
49582
49583	  // remove shape
49584	  canvas.removeShape(shape);
49585
49586	  return shape;
49587	};
49588
49589
49590	/**
49591	 * Command revert implementation
49592	 */
49593	DeleteShapeHandler.prototype.revert = function(context) {
49594
49595	  var canvas = this._canvas;
49596
49597	  var shape = context.shape,
49598	      oldParent = context.oldParent,
49599	      oldParentIndex = context.oldParentIndex;
49600
49601	  // restore containment
49602	  add(oldParent.children, shape, oldParentIndex);
49603
49604	  canvas.addShape(shape, oldParent);
49605
49606	  return shape;
49607	};
49608
49609	function isConnection$4(element) {
49610	  return element.waypoints;
49611	}
49612
49613	/**
49614	 * A handler that distributes elements evenly.
49615	 */
49616	function DistributeElements(modeling) {
49617	  this._modeling = modeling;
49618	}
49619
49620	DistributeElements.$inject = [ 'modeling' ];
49621
49622	var OFF_AXIS = {
49623	  x: 'y',
49624	  y: 'x'
49625	};
49626
49627	DistributeElements.prototype.preExecute = function(context) {
49628	  var modeling = this._modeling;
49629
49630	  var groups = context.groups,
49631	      axis = context.axis,
49632	      dimension = context.dimension;
49633
49634	  function updateRange(group, element) {
49635	    group.range.min = Math.min(element[axis], group.range.min);
49636	    group.range.max = Math.max(element[axis] + element[dimension], group.range.max);
49637	  }
49638
49639	  function center(element) {
49640	    return element[axis] + element[dimension] / 2;
49641	  }
49642
49643	  function lastIdx(arr) {
49644	    return arr.length - 1;
49645	  }
49646
49647	  function rangeDiff(range) {
49648	    return range.max - range.min;
49649	  }
49650
49651	  function centerElement(refCenter, element) {
49652	    var delta = { y: 0 };
49653
49654	    delta[axis] = refCenter - center(element);
49655
49656	    if (delta[axis]) {
49657
49658	      delta[OFF_AXIS[axis]] = 0;
49659
49660	      modeling.moveElements([ element ], delta, element.parent);
49661	    }
49662	  }
49663
49664	  var firstGroup = groups[0],
49665	      lastGroupIdx = lastIdx(groups),
49666	      lastGroup = groups[ lastGroupIdx ];
49667
49668	  var margin,
49669	      spaceInBetween,
49670	      groupsSize = 0; // the size of each range
49671
49672	  forEach(groups, function(group, idx) {
49673	    var sortedElements,
49674	        refElem,
49675	        refCenter;
49676
49677	    if (group.elements.length < 2) {
49678	      if (idx && idx !== groups.length - 1) {
49679	        updateRange(group, group.elements[0]);
49680
49681	        groupsSize += rangeDiff(group.range);
49682	      }
49683	      return;
49684	    }
49685
49686	    sortedElements = sortBy(group.elements, axis);
49687
49688	    refElem = sortedElements[0];
49689
49690	    if (idx === lastGroupIdx) {
49691	      refElem = sortedElements[lastIdx(sortedElements)];
49692	    }
49693
49694	    refCenter = center(refElem);
49695
49696	    // wanna update the ranges after the shapes have been centered
49697	    group.range = null;
49698
49699	    forEach(sortedElements, function(element) {
49700
49701	      centerElement(refCenter, element);
49702
49703	      if (group.range === null) {
49704	        group.range = {
49705	          min: element[axis],
49706	          max: element[axis] + element[dimension]
49707	        };
49708
49709	        return;
49710	      }
49711
49712	      // update group's range after centering the range elements
49713	      updateRange(group, element);
49714	    });
49715
49716	    if (idx && idx !== groups.length - 1) {
49717	      groupsSize += rangeDiff(group.range);
49718	    }
49719	  });
49720
49721	  spaceInBetween = Math.abs(lastGroup.range.min - firstGroup.range.max);
49722
49723	  margin = Math.round((spaceInBetween - groupsSize) / (groups.length - 1));
49724
49725	  if (margin < groups.length - 1) {
49726	    return;
49727	  }
49728
49729	  forEach(groups, function(group, groupIdx) {
49730	    var delta = {},
49731	        prevGroup;
49732
49733	    if (group === firstGroup || group === lastGroup) {
49734	      return;
49735	    }
49736
49737	    prevGroup = groups[groupIdx - 1];
49738
49739	    group.range.max = 0;
49740
49741	    forEach(group.elements, function(element, idx) {
49742	      delta[OFF_AXIS[axis]] = 0;
49743	      delta[axis] = (prevGroup.range.max - element[axis]) + margin;
49744
49745	      if (group.range.min !== element[axis]) {
49746	        delta[axis] += element[axis] - group.range.min;
49747	      }
49748
49749	      if (delta[axis]) {
49750	        modeling.moveElements([ element ], delta, element.parent);
49751	      }
49752
49753	      group.range.max = Math.max(element[axis] + element[dimension], idx ? group.range.max : 0);
49754	    });
49755	  });
49756	};
49757
49758	DistributeElements.prototype.postExecute = function(context) {
49759
49760	};
49761
49762	/**
49763	 * A handler that implements reversible moving of shapes.
49764	 */
49765	function LayoutConnectionHandler(layouter, canvas) {
49766	  this._layouter = layouter;
49767	  this._canvas = canvas;
49768	}
49769
49770	LayoutConnectionHandler.$inject = [ 'layouter', 'canvas' ];
49771
49772	LayoutConnectionHandler.prototype.execute = function(context) {
49773
49774	  var connection = context.connection;
49775
49776	  var oldWaypoints = connection.waypoints;
49777
49778	  assign(context, {
49779	    oldWaypoints: oldWaypoints
49780	  });
49781
49782	  connection.waypoints = this._layouter.layoutConnection(connection, context.hints);
49783
49784	  return connection;
49785	};
49786
49787	LayoutConnectionHandler.prototype.revert = function(context) {
49788
49789	  var connection = context.connection;
49790
49791	  connection.waypoints = context.oldWaypoints;
49792
49793	  return connection;
49794	};
49795
49796	/**
49797	 * A handler that implements reversible moving of connections.
49798	 *
49799	 * The handler differs from the layout connection handler in a sense
49800	 * that it preserves the connection layout.
49801	 */
49802	function MoveConnectionHandler() { }
49803
49804
49805	MoveConnectionHandler.prototype.execute = function(context) {
49806
49807	  var connection = context.connection,
49808	      delta = context.delta;
49809
49810	  var newParent = context.newParent || connection.parent,
49811	      newParentIndex = context.newParentIndex,
49812	      oldParent = connection.parent;
49813
49814	  // save old parent in context
49815	  context.oldParent = oldParent;
49816	  context.oldParentIndex = remove(oldParent.children, connection);
49817
49818	  // add to new parent at position
49819	  add(newParent.children, connection, newParentIndex);
49820
49821	  // update parent
49822	  connection.parent = newParent;
49823
49824	  // update waypoint positions
49825	  forEach(connection.waypoints, function(p) {
49826	    p.x += delta.x;
49827	    p.y += delta.y;
49828
49829	    if (p.original) {
49830	      p.original.x += delta.x;
49831	      p.original.y += delta.y;
49832	    }
49833	  });
49834
49835	  return connection;
49836	};
49837
49838	MoveConnectionHandler.prototype.revert = function(context) {
49839
49840	  var connection = context.connection,
49841	      newParent = connection.parent,
49842	      oldParent = context.oldParent,
49843	      oldParentIndex = context.oldParentIndex,
49844	      delta = context.delta;
49845
49846	  // remove from newParent
49847	  remove(newParent.children, connection);
49848
49849	  // restore previous location in old parent
49850	  add(oldParent.children, connection, oldParentIndex);
49851
49852	  // restore parent
49853	  connection.parent = oldParent;
49854
49855	  // revert to old waypoint positions
49856	  forEach(connection.waypoints, function(p) {
49857	    p.x -= delta.x;
49858	    p.y -= delta.y;
49859
49860	    if (p.original) {
49861	      p.original.x -= delta.x;
49862	      p.original.y -= delta.y;
49863	    }
49864	  });
49865
49866	  return connection;
49867	};
49868
49869	function MoveClosure() {
49870
49871	  this.allShapes = {};
49872	  this.allConnections = {};
49873
49874	  this.enclosedElements = {};
49875	  this.enclosedConnections = {};
49876
49877	  this.topLevel = {};
49878	}
49879
49880
49881	MoveClosure.prototype.add = function(element, isTopLevel) {
49882	  return this.addAll([ element ], isTopLevel);
49883	};
49884
49885
49886	MoveClosure.prototype.addAll = function(elements, isTopLevel) {
49887
49888	  var newClosure = getClosure(elements, !!isTopLevel, this);
49889
49890	  assign(this, newClosure);
49891
49892	  return this;
49893	};
49894
49895	/**
49896	 * A helper that is able to carry out serialized move
49897	 * operations on multiple elements.
49898	 *
49899	 * @param {Modeling} modeling
49900	 */
49901	function MoveHelper(modeling) {
49902	  this._modeling = modeling;
49903	}
49904
49905	/**
49906	 * Move the specified elements and all children by the given delta.
49907	 *
49908	 * This moves all enclosed connections, too and layouts all affected
49909	 * external connections.
49910	 *
49911	 * @param  {Array<djs.model.Base>} elements
49912	 * @param  {Point} delta
49913	 * @param  {djs.model.Base} newParent applied to the first level of shapes
49914	 *
49915	 * @return {Array<djs.model.Base>} list of touched elements
49916	 */
49917	MoveHelper.prototype.moveRecursive = function(elements, delta, newParent) {
49918	  if (!elements) {
49919	    return [];
49920	  } else {
49921	    return this.moveClosure(this.getClosure(elements), delta, newParent);
49922	  }
49923	};
49924
49925	/**
49926	 * Move the given closure of elmements.
49927	 *
49928	 * @param {Object} closure
49929	 * @param {Point} delta
49930	 * @param {djs.model.Base} [newParent]
49931	 * @param {djs.model.Base} [newHost]
49932	 */
49933	MoveHelper.prototype.moveClosure = function(closure, delta, newParent, newHost, primaryShape) {
49934	  var modeling = this._modeling;
49935
49936	  var allShapes = closure.allShapes,
49937	      allConnections = closure.allConnections,
49938	      enclosedConnections = closure.enclosedConnections,
49939	      topLevel = closure.topLevel,
49940	      keepParent = false;
49941
49942	  if (primaryShape && primaryShape.parent === newParent) {
49943	    keepParent = true;
49944	  }
49945
49946	  // move all shapes
49947	  forEach(allShapes, function(shape) {
49948
49949	    // move the element according to the given delta
49950	    modeling.moveShape(shape, delta, topLevel[shape.id] && !keepParent && newParent, {
49951	      recurse: false,
49952	      layout: false
49953	    });
49954	  });
49955
49956	  // move all child connections / layout external connections
49957	  forEach(allConnections, function(c) {
49958
49959	    var sourceMoved = !!allShapes[c.source.id],
49960	        targetMoved = !!allShapes[c.target.id];
49961
49962	    if (enclosedConnections[c.id] && sourceMoved && targetMoved) {
49963	      modeling.moveConnection(c, delta, topLevel[c.id] && !keepParent && newParent);
49964	    } else {
49965	      modeling.layoutConnection(c, {
49966	        connectionStart: sourceMoved && getMovedSourceAnchor(c, c.source, delta),
49967	        connectionEnd: targetMoved && getMovedTargetAnchor(c, c.target, delta)
49968	      });
49969	    }
49970	  });
49971	};
49972
49973	/**
49974	 * Returns the closure for the selected elements
49975	 *
49976	 * @param  {Array<djs.model.Base>} elements
49977	 * @return {MoveClosure} closure
49978	 */
49979	MoveHelper.prototype.getClosure = function(elements) {
49980	  return new MoveClosure().addAll(elements, true);
49981	};
49982
49983	/**
49984	 * A handler that implements reversible moving of shapes.
49985	 */
49986	function MoveElementsHandler(modeling) {
49987	  this._helper = new MoveHelper(modeling);
49988	}
49989
49990	MoveElementsHandler.$inject = [ 'modeling' ];
49991
49992	MoveElementsHandler.prototype.preExecute = function(context) {
49993	  context.closure = this._helper.getClosure(context.shapes);
49994	};
49995
49996	MoveElementsHandler.prototype.postExecute = function(context) {
49997
49998	  var hints = context.hints,
49999	      primaryShape;
50000
50001	  if (hints && hints.primaryShape) {
50002	    primaryShape = hints.primaryShape;
50003	    hints.oldParent = primaryShape.parent;
50004	  }
50005
50006	  this._helper.moveClosure(
50007	    context.closure,
50008	    context.delta,
50009	    context.newParent,
50010	    context.newHost,
50011	    primaryShape
50012	  );
50013	};
50014
50015	/**
50016	 * A handler that implements reversible moving of shapes.
50017	 */
50018	function MoveShapeHandler(modeling) {
50019	  this._modeling = modeling;
50020
50021	  this._helper = new MoveHelper(modeling);
50022	}
50023
50024	MoveShapeHandler.$inject = [ 'modeling' ];
50025
50026
50027	MoveShapeHandler.prototype.execute = function(context) {
50028
50029	  var shape = context.shape,
50030	      delta = context.delta,
50031	      newParent = context.newParent || shape.parent,
50032	      newParentIndex = context.newParentIndex,
50033	      oldParent = shape.parent;
50034
50035	  context.oldBounds = pick(shape, [ 'x', 'y', 'width', 'height']);
50036
50037	  // save old parent in context
50038	  context.oldParent = oldParent;
50039	  context.oldParentIndex = remove(oldParent.children, shape);
50040
50041	  // add to new parent at position
50042	  add(newParent.children, shape, newParentIndex);
50043
50044	  // update shape parent + position
50045	  assign(shape, {
50046	    parent: newParent,
50047	    x: shape.x + delta.x,
50048	    y: shape.y + delta.y
50049	  });
50050
50051	  return shape;
50052	};
50053
50054	MoveShapeHandler.prototype.postExecute = function(context) {
50055
50056	  var shape = context.shape,
50057	      delta = context.delta,
50058	      hints = context.hints;
50059
50060	  var modeling = this._modeling;
50061
50062	  if (hints.layout !== false) {
50063
50064	    forEach(shape.incoming, function(c) {
50065	      modeling.layoutConnection(c, {
50066	        connectionEnd: getMovedTargetAnchor(c, shape, delta)
50067	      });
50068	    });
50069
50070	    forEach(shape.outgoing, function(c) {
50071	      modeling.layoutConnection(c, {
50072	        connectionStart: getMovedSourceAnchor(c, shape, delta)
50073	      });
50074	    });
50075	  }
50076
50077	  if (hints.recurse !== false) {
50078	    this.moveChildren(context);
50079	  }
50080	};
50081
50082	MoveShapeHandler.prototype.revert = function(context) {
50083
50084	  var shape = context.shape,
50085	      oldParent = context.oldParent,
50086	      oldParentIndex = context.oldParentIndex,
50087	      delta = context.delta;
50088
50089	  // restore previous location in old parent
50090	  add(oldParent.children, shape, oldParentIndex);
50091
50092	  // revert to old position and parent
50093	  assign(shape, {
50094	    parent: oldParent,
50095	    x: shape.x - delta.x,
50096	    y: shape.y - delta.y
50097	  });
50098
50099	  return shape;
50100	};
50101
50102	MoveShapeHandler.prototype.moveChildren = function(context) {
50103
50104	  var delta = context.delta,
50105	      shape = context.shape;
50106
50107	  this._helper.moveRecursive(shape.children, delta, null);
50108	};
50109
50110	MoveShapeHandler.prototype.getNewParent = function(context) {
50111	  return context.newParent || context.shape.parent;
50112	};
50113
50114	/**
50115	 * Reconnect connection handler
50116	 */
50117	function ReconnectConnectionHandler(modeling) {
50118	  this._modeling = modeling;
50119	}
50120
50121	ReconnectConnectionHandler.$inject = [ 'modeling' ];
50122
50123	ReconnectConnectionHandler.prototype.execute = function(context) {
50124	  var newSource = context.newSource,
50125	      newTarget = context.newTarget,
50126	      connection = context.connection,
50127	      dockingOrPoints = context.dockingOrPoints;
50128
50129	  if (!newSource && !newTarget) {
50130	    throw new Error('newSource or newTarget required');
50131	  }
50132
50133	  if (isArray$2(dockingOrPoints)) {
50134	    context.oldWaypoints = connection.waypoints;
50135	    connection.waypoints = dockingOrPoints;
50136	  }
50137
50138	  if (newSource) {
50139	    context.oldSource = connection.source;
50140	    connection.source = newSource;
50141	  }
50142
50143	  if (newTarget) {
50144	    context.oldTarget = connection.target;
50145	    connection.target = newTarget;
50146	  }
50147
50148	  return connection;
50149	};
50150
50151	ReconnectConnectionHandler.prototype.postExecute = function(context) {
50152	  var connection = context.connection,
50153	      newSource = context.newSource,
50154	      newTarget = context.newTarget,
50155	      dockingOrPoints = context.dockingOrPoints,
50156	      hints = context.hints || {};
50157
50158	  var layoutConnectionHints = {};
50159
50160	  if (hints.connectionStart) {
50161	    layoutConnectionHints.connectionStart = hints.connectionStart;
50162	  }
50163
50164	  if (hints.connectionEnd) {
50165	    layoutConnectionHints.connectionEnd = hints.connectionEnd;
50166	  }
50167
50168	  if (hints.layoutConnection === false) {
50169	    return;
50170	  }
50171
50172	  if (newSource && (!newTarget || hints.docking === 'source')) {
50173	    layoutConnectionHints.connectionStart = layoutConnectionHints.connectionStart
50174	      || getDocking(isArray$2(dockingOrPoints) ? dockingOrPoints[ 0 ] : dockingOrPoints);
50175	  }
50176
50177	  if (newTarget && (!newSource || hints.docking === 'target')) {
50178	    layoutConnectionHints.connectionEnd = layoutConnectionHints.connectionEnd
50179	      || getDocking(isArray$2(dockingOrPoints) ? dockingOrPoints[ dockingOrPoints.length - 1 ] : dockingOrPoints);
50180	  }
50181
50182	  if (hints.newWaypoints) {
50183	    layoutConnectionHints.waypoints = hints.newWaypoints;
50184	  }
50185
50186	  this._modeling.layoutConnection(connection, layoutConnectionHints);
50187	};
50188
50189	ReconnectConnectionHandler.prototype.revert = function(context) {
50190	  var oldSource = context.oldSource,
50191	      oldTarget = context.oldTarget,
50192	      oldWaypoints = context.oldWaypoints,
50193	      connection = context.connection;
50194
50195	  if (oldSource) {
50196	    connection.source = oldSource;
50197	  }
50198
50199	  if (oldTarget) {
50200	    connection.target = oldTarget;
50201	  }
50202
50203	  if (oldWaypoints) {
50204	    connection.waypoints = oldWaypoints;
50205	  }
50206
50207	  return connection;
50208	};
50209
50210
50211
50212	// helpers //////////
50213
50214	function getDocking(point) {
50215	  return point.original || point;
50216	}
50217
50218	/**
50219	 * Replace shape by adding new shape and removing old shape. Incoming and outgoing connections will
50220	 * be kept if possible.
50221	 *
50222	 * @class
50223	 * @constructor
50224	 *
50225	 * @param {Modeling} modeling
50226	 * @param {Rules} rules
50227	 */
50228	function ReplaceShapeHandler(modeling, rules) {
50229	  this._modeling = modeling;
50230	  this._rules = rules;
50231	}
50232
50233	ReplaceShapeHandler.$inject = [ 'modeling', 'rules' ];
50234
50235
50236	/**
50237	 * Add new shape.
50238	 *
50239	 * @param {Object} context
50240	 * @param {djs.model.Shape} context.oldShape
50241	 * @param {Object} context.newData
50242	 * @param {string} context.newData.type
50243	 * @param {number} context.newData.x
50244	 * @param {number} context.newData.y
50245	 * @param {Object} [hints]
50246	 */
50247	ReplaceShapeHandler.prototype.preExecute = function(context) {
50248	  var self = this,
50249	      modeling = this._modeling,
50250	      rules = this._rules;
50251
50252	  var oldShape = context.oldShape,
50253	      newData = context.newData,
50254	      hints = context.hints || {},
50255	      newShape;
50256
50257	  function canReconnect(source, target, connection) {
50258	    return rules.allowed('connection.reconnect', {
50259	      connection: connection,
50260	      source: source,
50261	      target: target
50262	    });
50263	  }
50264
50265	  // (1) add new shape at given position
50266	  var position = {
50267	    x: newData.x,
50268	    y: newData.y
50269	  };
50270
50271	  var oldBounds = {
50272	    x: oldShape.x,
50273	    y: oldShape.y,
50274	    width: oldShape.width,
50275	    height: oldShape.height
50276	  };
50277
50278	  newShape = context.newShape =
50279	    context.newShape ||
50280	    self.createShape(newData, position, oldShape.parent, hints);
50281
50282	  // (2) update host
50283	  if (oldShape.host) {
50284	    modeling.updateAttachment(newShape, oldShape.host);
50285	  }
50286
50287	  // (3) adopt all children from old shape
50288	  var children;
50289
50290	  if (hints.moveChildren !== false) {
50291	    children = oldShape.children.slice();
50292
50293	    modeling.moveElements(children, { x: 0, y: 0 }, newShape, hints);
50294	  }
50295
50296	  // (4) reconnect connections to new shape if possible
50297	  var incoming = oldShape.incoming.slice(),
50298	      outgoing = oldShape.outgoing.slice();
50299
50300	  forEach(incoming, function(connection) {
50301	    var source = connection.source,
50302	        allowed = canReconnect(source, newShape, connection);
50303
50304	    if (allowed) {
50305	      self.reconnectEnd(
50306	        connection, newShape,
50307	        getResizedTargetAnchor(connection, newShape, oldBounds),
50308	        hints
50309	      );
50310	    }
50311	  });
50312
50313	  forEach(outgoing, function(connection) {
50314	    var target = connection.target,
50315	        allowed = canReconnect(newShape, target, connection);
50316
50317	    if (allowed) {
50318	      self.reconnectStart(
50319	        connection, newShape,
50320	        getResizedSourceAnchor(connection, newShape, oldBounds),
50321	        hints
50322	      );
50323	    }
50324	  });
50325	};
50326
50327
50328	/**
50329	 * Remove old shape.
50330	 */
50331	ReplaceShapeHandler.prototype.postExecute = function(context) {
50332	  var oldShape = context.oldShape;
50333
50334	  this._modeling.removeShape(oldShape);
50335	};
50336
50337
50338	ReplaceShapeHandler.prototype.execute = function(context) {};
50339
50340
50341	ReplaceShapeHandler.prototype.revert = function(context) {};
50342
50343
50344	ReplaceShapeHandler.prototype.createShape = function(shape, position, target, hints) {
50345	  return this._modeling.createShape(shape, position, target, hints);
50346	};
50347
50348
50349	ReplaceShapeHandler.prototype.reconnectStart = function(connection, newSource, dockingPoint, hints) {
50350	  this._modeling.reconnectStart(connection, newSource, dockingPoint, hints);
50351	};
50352
50353
50354	ReplaceShapeHandler.prototype.reconnectEnd = function(connection, newTarget, dockingPoint, hints) {
50355	  this._modeling.reconnectEnd(connection, newTarget, dockingPoint, hints);
50356	};
50357
50358	/**
50359	 * A handler that implements reversible resizing of shapes.
50360	 *
50361	 * @param {Modeling} modeling
50362	 */
50363	function ResizeShapeHandler(modeling) {
50364	  this._modeling = modeling;
50365	}
50366
50367	ResizeShapeHandler.$inject = [ 'modeling' ];
50368
50369	/**
50370	 * {
50371	 *   shape: {....}
50372	 *   newBounds: {
50373	 *     width:  20,
50374	 *     height: 40,
50375	 *     x:       5,
50376	 *     y:      10
50377	 *   }
50378	 *
50379	 * }
50380	 */
50381	ResizeShapeHandler.prototype.execute = function(context) {
50382	  var shape = context.shape,
50383	      newBounds = context.newBounds,
50384	      minBounds = context.minBounds;
50385
50386	  if (newBounds.x === undefined || newBounds.y === undefined ||
50387	      newBounds.width === undefined || newBounds.height === undefined) {
50388	    throw new Error('newBounds must have {x, y, width, height} properties');
50389	  }
50390
50391	  if (minBounds && (newBounds.width < minBounds.width
50392	    || newBounds.height < minBounds.height)) {
50393	    throw new Error('width and height cannot be less than minimum height and width');
50394	  } else if (!minBounds
50395	    && newBounds.width < 10 || newBounds.height < 10) {
50396	    throw new Error('width and height cannot be less than 10px');
50397	  }
50398
50399	  // save old bbox in context
50400	  context.oldBounds = {
50401	    width:  shape.width,
50402	    height: shape.height,
50403	    x:      shape.x,
50404	    y:      shape.y
50405	  };
50406
50407	  // update shape
50408	  assign(shape, {
50409	    width:  newBounds.width,
50410	    height: newBounds.height,
50411	    x:      newBounds.x,
50412	    y:      newBounds.y
50413	  });
50414
50415	  return shape;
50416	};
50417
50418	ResizeShapeHandler.prototype.postExecute = function(context) {
50419	  var modeling = this._modeling;
50420
50421	  var shape = context.shape,
50422	      oldBounds = context.oldBounds,
50423	      hints = context.hints || {};
50424
50425	  if (hints.layout === false) {
50426	    return;
50427	  }
50428
50429	  forEach(shape.incoming, function(c) {
50430	    modeling.layoutConnection(c, {
50431	      connectionEnd: getResizedTargetAnchor(c, shape, oldBounds)
50432	    });
50433	  });
50434
50435	  forEach(shape.outgoing, function(c) {
50436	    modeling.layoutConnection(c, {
50437	      connectionStart: getResizedSourceAnchor(c, shape, oldBounds)
50438	    });
50439	  });
50440
50441	};
50442
50443	ResizeShapeHandler.prototype.revert = function(context) {
50444
50445	  var shape = context.shape,
50446	      oldBounds = context.oldBounds;
50447
50448	  // restore previous bbox
50449	  assign(shape, {
50450	    width:  oldBounds.width,
50451	    height: oldBounds.height,
50452	    x:      oldBounds.x,
50453	    y:      oldBounds.y
50454	  });
50455
50456	  return shape;
50457	};
50458
50459	/**
50460	 * Add or remove space by moving and resizing shapes and updating connection waypoints.
50461	 */
50462	function SpaceToolHandler(modeling) {
50463	  this._modeling = modeling;
50464	}
50465
50466	SpaceToolHandler.$inject = [ 'modeling' ];
50467
50468	SpaceToolHandler.prototype.preExecute = function(context) {
50469	  var delta = context.delta,
50470	      direction = context.direction,
50471	      movingShapes = context.movingShapes,
50472	      resizingShapes = context.resizingShapes,
50473	      start = context.start,
50474	      oldBounds = {};
50475
50476	  // (1) move shapes
50477	  this.moveShapes(movingShapes, delta);
50478
50479	  // (2a) save old bounds of resized shapes
50480	  forEach(resizingShapes, function(shape) {
50481	    oldBounds[shape.id] = getBounds(shape);
50482	  });
50483
50484	  // (2b) resize shapes
50485	  this.resizeShapes(resizingShapes, delta, direction);
50486
50487	  // (3) update connection waypoints
50488	  this.updateConnectionWaypoints(
50489	    getWaypointsUpdatingConnections(movingShapes, resizingShapes),
50490	    delta,
50491	    direction,
50492	    start,
50493	    movingShapes,
50494	    resizingShapes,
50495	    oldBounds
50496	  );
50497	};
50498
50499	SpaceToolHandler.prototype.execute = function() {};
50500	SpaceToolHandler.prototype.revert = function() {};
50501
50502	SpaceToolHandler.prototype.moveShapes = function(shapes, delta) {
50503	  var self = this;
50504
50505	  forEach(shapes, function(element) {
50506	    self._modeling.moveShape(element, delta, null, {
50507	      autoResize: false,
50508	      layout: false,
50509	      recurse: false
50510	    });
50511	  });
50512	};
50513
50514	SpaceToolHandler.prototype.resizeShapes = function(shapes, delta, direction) {
50515	  var self = this;
50516
50517	  forEach(shapes, function(shape) {
50518	    var newBounds = resizeBounds(shape, direction, delta);
50519
50520	    self._modeling.resizeShape(shape, newBounds, null, {
50521	      attachSupport: false,
50522	      autoResize: false,
50523	      layout: false
50524	    });
50525	  });
50526	};
50527
50528	/**
50529	 * Update connections waypoints according to the rules:
50530	 *   1. Both source and target are moved/resized => move waypoints by the delta
50531	 *   2. Only one of source and target is moved/resized => re-layout connection with moved start/end
50532	 */
50533	SpaceToolHandler.prototype.updateConnectionWaypoints = function(
50534	    connections,
50535	    delta,
50536	    direction,
50537	    start,
50538	    movingShapes,
50539	    resizingShapes,
50540	    oldBounds
50541	) {
50542	  var self = this,
50543	      affectedShapes = movingShapes.concat(resizingShapes);
50544
50545	  forEach(connections, function(connection) {
50546	    var source = connection.source,
50547	        target = connection.target,
50548	        waypoints = copyWaypoints(connection),
50549	        axis = getAxisFromDirection(direction),
50550	        layoutHints = {
50551	          labelBehavior: false
50552	        };
50553
50554	    if (includes$1(affectedShapes, source) && includes$1(affectedShapes, target)) {
50555
50556	      // move waypoints
50557	      waypoints = map$1(waypoints, function(waypoint) {
50558	        if (shouldMoveWaypoint(waypoint, start, direction)) {
50559
50560	          // move waypoint
50561	          waypoint[ axis ] = waypoint[ axis ] + delta[ axis ];
50562	        }
50563
50564	        if (waypoint.original && shouldMoveWaypoint(waypoint.original, start, direction)) {
50565
50566	          // move waypoint original
50567	          waypoint.original[ axis ] = waypoint.original[ axis ] + delta[ axis ];
50568	        }
50569
50570	        return waypoint;
50571	      });
50572
50573	      self._modeling.updateWaypoints(connection, waypoints, {
50574	        labelBehavior: false
50575	      });
50576	    } else if (includes$1(affectedShapes, source) || includes$1(affectedShapes, target)) {
50577
50578	      // re-layout connection with moved start/end
50579	      if (includes$1(movingShapes, source)) {
50580	        layoutHints.connectionStart = getMovedSourceAnchor(connection, source, delta);
50581	      } else if (includes$1(movingShapes, target)) {
50582	        layoutHints.connectionEnd = getMovedTargetAnchor(connection, target, delta);
50583	      } else if (includes$1(resizingShapes, source)) {
50584	        layoutHints.connectionStart = getResizedSourceAnchor(
50585	          connection, source, oldBounds[source.id]
50586	        );
50587	      } else if (includes$1(resizingShapes, target)) {
50588	        layoutHints.connectionEnd = getResizedTargetAnchor(
50589	          connection, target, oldBounds[target.id]
50590	        );
50591	      }
50592
50593	      self._modeling.layoutConnection(connection, layoutHints);
50594	    }
50595	  });
50596	};
50597
50598
50599	// helpers //////////
50600
50601	function copyWaypoint(waypoint) {
50602	  return assign({}, waypoint);
50603	}
50604
50605	function copyWaypoints(connection) {
50606	  return map$1(connection.waypoints, function(waypoint) {
50607
50608	    waypoint = copyWaypoint(waypoint);
50609
50610	    if (waypoint.original) {
50611	      waypoint.original = copyWaypoint(waypoint.original);
50612	    }
50613
50614	    return waypoint;
50615	  });
50616	}
50617
50618	function getAxisFromDirection(direction) {
50619	  switch (direction) {
50620	  case 'n':
50621	    return 'y';
50622	  case 'w':
50623	    return 'x';
50624	  case 's':
50625	    return 'y';
50626	  case 'e':
50627	    return 'x';
50628	  }
50629	}
50630
50631	function shouldMoveWaypoint(waypoint, start, direction) {
50632	  var relevantAxis = getAxisFromDirection(direction);
50633
50634	  if (/e|s/.test(direction)) {
50635	    return waypoint[ relevantAxis ] > start;
50636	  } else if (/n|w/.test(direction)) {
50637	    return waypoint[ relevantAxis ] < start;
50638	  }
50639	}
50640
50641	function includes$1(array, item) {
50642	  return array.indexOf(item) !== -1;
50643	}
50644
50645	function getBounds(shape) {
50646	  return {
50647	    x: shape.x,
50648	    y: shape.y,
50649	    height: shape.height,
50650	    width: shape.width
50651	  };
50652	}
50653
50654	/**
50655	 * A handler that toggles the collapsed state of an element
50656	 * and the visibility of all its children.
50657	 *
50658	 * @param {Modeling} modeling
50659	 */
50660	function ToggleShapeCollapseHandler(modeling) {
50661	  this._modeling = modeling;
50662	}
50663
50664	ToggleShapeCollapseHandler.$inject = [ 'modeling' ];
50665
50666
50667	ToggleShapeCollapseHandler.prototype.execute = function(context) {
50668
50669	  var shape = context.shape,
50670	      children = shape.children;
50671
50672	  // recursively remember previous visibility of children
50673	  context.oldChildrenVisibility = getElementsVisibilityRecursive(children);
50674
50675	  // toggle state
50676	  shape.collapsed = !shape.collapsed;
50677
50678	  // recursively hide/show children
50679	  var result = setHiddenRecursive(children, shape.collapsed);
50680
50681	  return [shape].concat(result);
50682	};
50683
50684
50685	ToggleShapeCollapseHandler.prototype.revert = function(context) {
50686
50687	  var shape = context.shape,
50688	      oldChildrenVisibility = context.oldChildrenVisibility;
50689
50690	  var children = shape.children;
50691
50692	  // recursively set old visability of children
50693	  var result = restoreVisibilityRecursive(children, oldChildrenVisibility);
50694
50695	  // retoggle state
50696	  shape.collapsed = !shape.collapsed;
50697
50698	  return [shape].concat(result);
50699	};
50700
50701
50702	// helpers //////////////////////
50703
50704	/**
50705	 * Return a map { elementId -> hiddenState}.
50706	 *
50707	 * @param {Array<djs.model.Shape>} elements
50708	 *
50709	 * @return {Object}
50710	 */
50711	function getElementsVisibilityRecursive(elements) {
50712
50713	  var result = {};
50714
50715	  forEach(elements, function(element) {
50716	    result[element.id] = element.hidden;
50717
50718	    if (element.children) {
50719	      result = assign({}, result, getElementsVisibilityRecursive(element.children));
50720	    }
50721	  });
50722
50723	  return result;
50724	}
50725
50726
50727	function setHiddenRecursive(elements, newHidden) {
50728	  var result = [];
50729	  forEach(elements, function(element) {
50730	    element.hidden = newHidden;
50731
50732	    result = result.concat(element);
50733
50734	    if (element.children) {
50735	      result = result.concat(setHiddenRecursive(element.children, element.collapsed || newHidden));
50736	    }
50737	  });
50738
50739	  return result;
50740	}
50741
50742	function restoreVisibilityRecursive(elements, lastState) {
50743	  var result = [];
50744	  forEach(elements, function(element) {
50745	    element.hidden = lastState[element.id];
50746
50747	    result = result.concat(element);
50748
50749	    if (element.children) {
50750	      result = result.concat(restoreVisibilityRecursive(element.children, lastState));
50751	    }
50752	  });
50753
50754	  return result;
50755	}
50756
50757	/**
50758	 * A handler that implements reversible attaching/detaching of shapes.
50759	 */
50760	function UpdateAttachmentHandler(modeling) {
50761	  this._modeling = modeling;
50762	}
50763
50764	UpdateAttachmentHandler.$inject = [ 'modeling' ];
50765
50766
50767	UpdateAttachmentHandler.prototype.execute = function(context) {
50768	  var shape = context.shape,
50769	      newHost = context.newHost,
50770	      oldHost = shape.host;
50771
50772	  // (0) detach from old host
50773	  context.oldHost = oldHost;
50774	  context.attacherIdx = removeAttacher(oldHost, shape);
50775
50776	  // (1) attach to new host
50777	  addAttacher(newHost, shape);
50778
50779	  // (2) update host
50780	  shape.host = newHost;
50781
50782	  return shape;
50783	};
50784
50785	UpdateAttachmentHandler.prototype.revert = function(context) {
50786	  var shape = context.shape,
50787	      newHost = context.newHost,
50788	      oldHost = context.oldHost,
50789	      attacherIdx = context.attacherIdx;
50790
50791	  // (2) update host
50792	  shape.host = oldHost;
50793
50794	  // (1) attach to new host
50795	  removeAttacher(newHost, shape);
50796
50797	  // (0) detach from old host
50798	  addAttacher(oldHost, shape, attacherIdx);
50799
50800	  return shape;
50801	};
50802
50803
50804	function removeAttacher(host, attacher) {
50805
50806	  // remove attacher from host
50807	  return remove(host && host.attachers, attacher);
50808	}
50809
50810	function addAttacher(host, attacher, idx) {
50811
50812	  if (!host) {
50813	    return;
50814	  }
50815
50816	  var attachers = host.attachers;
50817
50818	  if (!attachers) {
50819	    host.attachers = attachers = [];
50820	  }
50821
50822	  add(attachers, attacher, idx);
50823	}
50824
50825	function UpdateWaypointsHandler() { }
50826
50827	UpdateWaypointsHandler.prototype.execute = function(context) {
50828
50829	  var connection = context.connection,
50830	      newWaypoints = context.newWaypoints;
50831
50832	  context.oldWaypoints = connection.waypoints;
50833
50834	  connection.waypoints = newWaypoints;
50835
50836	  return connection;
50837	};
50838
50839	UpdateWaypointsHandler.prototype.revert = function(context) {
50840
50841	  var connection = context.connection,
50842	      oldWaypoints = context.oldWaypoints;
50843
50844	  connection.waypoints = oldWaypoints;
50845
50846	  return connection;
50847	};
50848
50849	/**
50850	 * The basic modeling entry point.
50851	 *
50852	 * @param {EventBus} eventBus
50853	 * @param {ElementFactory} elementFactory
50854	 * @param {CommandStack} commandStack
50855	 */
50856	function Modeling$1(eventBus, elementFactory, commandStack) {
50857	  this._eventBus = eventBus;
50858	  this._elementFactory = elementFactory;
50859	  this._commandStack = commandStack;
50860
50861	  var self = this;
50862
50863	  eventBus.on('diagram.init', function() {
50864
50865	    // register modeling handlers
50866	    self.registerHandlers(commandStack);
50867	  });
50868	}
50869
50870	Modeling$1.$inject = [ 'eventBus', 'elementFactory', 'commandStack' ];
50871
50872
50873	Modeling$1.prototype.getHandlers = function() {
50874	  return {
50875	    'shape.append': AppendShapeHandler,
50876	    'shape.create': CreateShapeHandler,
50877	    'shape.delete': DeleteShapeHandler,
50878	    'shape.move': MoveShapeHandler,
50879	    'shape.resize': ResizeShapeHandler,
50880	    'shape.replace': ReplaceShapeHandler,
50881	    'shape.toggleCollapse': ToggleShapeCollapseHandler,
50882
50883	    'spaceTool': SpaceToolHandler,
50884
50885	    'label.create': CreateLabelHandler,
50886
50887	    'connection.create': CreateConnectionHandler,
50888	    'connection.delete': DeleteConnectionHandler,
50889	    'connection.move': MoveConnectionHandler,
50890	    'connection.layout': LayoutConnectionHandler,
50891
50892	    'connection.updateWaypoints': UpdateWaypointsHandler,
50893
50894	    'connection.reconnect': ReconnectConnectionHandler,
50895
50896	    'elements.create': CreateElementsHandler,
50897	    'elements.move': MoveElementsHandler,
50898	    'elements.delete': DeleteElementsHandler,
50899
50900	    'elements.distribute': DistributeElements,
50901	    'elements.align': AlignElements,
50902
50903	    'element.updateAttachment': UpdateAttachmentHandler
50904	  };
50905	};
50906
50907	/**
50908	 * Register handlers with the command stack
50909	 *
50910	 * @param {CommandStack} commandStack
50911	 */
50912	Modeling$1.prototype.registerHandlers = function(commandStack) {
50913	  forEach(this.getHandlers(), function(handler, id) {
50914	    commandStack.registerHandler(id, handler);
50915	  });
50916	};
50917
50918
50919	// modeling helpers //////////////////////
50920
50921	Modeling$1.prototype.moveShape = function(shape, delta, newParent, newParentIndex, hints) {
50922
50923	  if (typeof newParentIndex === 'object') {
50924	    hints = newParentIndex;
50925	    newParentIndex = null;
50926	  }
50927
50928	  var context = {
50929	    shape: shape,
50930	    delta:  delta,
50931	    newParent: newParent,
50932	    newParentIndex: newParentIndex,
50933	    hints: hints || {}
50934	  };
50935
50936	  this._commandStack.execute('shape.move', context);
50937	};
50938
50939
50940	/**
50941	 * Update the attachment of the given shape.
50942	 *
50943	 * @param {djs.mode.Base} shape
50944	 * @param {djs.model.Base} [newHost]
50945	 */
50946	Modeling$1.prototype.updateAttachment = function(shape, newHost) {
50947	  var context = {
50948	    shape: shape,
50949	    newHost: newHost
50950	  };
50951
50952	  this._commandStack.execute('element.updateAttachment', context);
50953	};
50954
50955
50956	/**
50957	 * Move a number of shapes to a new target, either setting it as
50958	 * the new parent or attaching it.
50959	 *
50960	 * @param {Array<djs.mode.Base>} shapes
50961	 * @param {Point} delta
50962	 * @param {djs.model.Base} [target]
50963	 * @param {Object} [hints]
50964	 * @param {boolean} [hints.attach=false]
50965	 */
50966	Modeling$1.prototype.moveElements = function(shapes, delta, target, hints) {
50967
50968	  hints = hints || {};
50969
50970	  var attach = hints.attach;
50971
50972	  var newParent = target,
50973	      newHost;
50974
50975	  if (attach === true) {
50976	    newHost = target;
50977	    newParent = target.parent;
50978	  } else
50979
50980	  if (attach === false) {
50981	    newHost = null;
50982	  }
50983
50984	  var context = {
50985	    shapes: shapes,
50986	    delta: delta,
50987	    newParent: newParent,
50988	    newHost: newHost,
50989	    hints: hints
50990	  };
50991
50992	  this._commandStack.execute('elements.move', context);
50993	};
50994
50995
50996	Modeling$1.prototype.moveConnection = function(connection, delta, newParent, newParentIndex, hints) {
50997
50998	  if (typeof newParentIndex === 'object') {
50999	    hints = newParentIndex;
51000	    newParentIndex = undefined;
51001	  }
51002
51003	  var context = {
51004	    connection: connection,
51005	    delta: delta,
51006	    newParent: newParent,
51007	    newParentIndex: newParentIndex,
51008	    hints: hints || {}
51009	  };
51010
51011	  this._commandStack.execute('connection.move', context);
51012	};
51013
51014
51015	Modeling$1.prototype.layoutConnection = function(connection, hints) {
51016	  var context = {
51017	    connection: connection,
51018	    hints: hints || {}
51019	  };
51020
51021	  this._commandStack.execute('connection.layout', context);
51022	};
51023
51024
51025	/**
51026	 * Create connection.
51027	 *
51028	 * @param {djs.model.Base} source
51029	 * @param {djs.model.Base} target
51030	 * @param {number} [parentIndex]
51031	 * @param {Object|djs.model.Connection} connection
51032	 * @param {djs.model.Base} parent
51033	 * @param {Object} hints
51034	 *
51035	 * @return {djs.model.Connection} the created connection.
51036	 */
51037	Modeling$1.prototype.createConnection = function(source, target, parentIndex, connection, parent, hints) {
51038
51039	  if (typeof parentIndex === 'object') {
51040	    hints = parent;
51041	    parent = connection;
51042	    connection = parentIndex;
51043	    parentIndex = undefined;
51044	  }
51045
51046	  connection = this._create('connection', connection);
51047
51048	  var context = {
51049	    source: source,
51050	    target: target,
51051	    parent: parent,
51052	    parentIndex: parentIndex,
51053	    connection: connection,
51054	    hints: hints
51055	  };
51056
51057	  this._commandStack.execute('connection.create', context);
51058
51059	  return context.connection;
51060	};
51061
51062
51063	/**
51064	 * Create a shape at the specified position.
51065	 *
51066	 * @param {djs.model.Shape|Object} shape
51067	 * @param {Point} position
51068	 * @param {djs.model.Shape|djs.model.Root} target
51069	 * @param {number} [parentIndex] position in parents children list
51070	 * @param {Object} [hints]
51071	 * @param {boolean} [hints.attach] whether to attach to target or become a child
51072	 *
51073	 * @return {djs.model.Shape} the created shape
51074	 */
51075	Modeling$1.prototype.createShape = function(shape, position, target, parentIndex, hints) {
51076
51077	  if (typeof parentIndex !== 'number') {
51078	    hints = parentIndex;
51079	    parentIndex = undefined;
51080	  }
51081
51082	  hints = hints || {};
51083
51084	  var attach = hints.attach,
51085	      parent,
51086	      host;
51087
51088	  shape = this._create('shape', shape);
51089
51090	  if (attach) {
51091	    parent = target.parent;
51092	    host = target;
51093	  } else {
51094	    parent = target;
51095	  }
51096
51097	  var context = {
51098	    position: position,
51099	    shape: shape,
51100	    parent: parent,
51101	    parentIndex: parentIndex,
51102	    host: host,
51103	    hints: hints
51104	  };
51105
51106	  this._commandStack.execute('shape.create', context);
51107
51108	  return context.shape;
51109	};
51110
51111
51112	Modeling$1.prototype.createElements = function(elements, position, parent, parentIndex, hints) {
51113	  if (!isArray$2(elements)) {
51114	    elements = [ elements ];
51115	  }
51116
51117	  if (typeof parentIndex !== 'number') {
51118	    hints = parentIndex;
51119	    parentIndex = undefined;
51120	  }
51121
51122	  hints = hints || {};
51123
51124	  var context = {
51125	    position: position,
51126	    elements: elements,
51127	    parent: parent,
51128	    parentIndex: parentIndex,
51129	    hints: hints
51130	  };
51131
51132	  this._commandStack.execute('elements.create', context);
51133
51134	  return context.elements;
51135	};
51136
51137
51138	Modeling$1.prototype.createLabel = function(labelTarget, position, label, parent) {
51139
51140	  label = this._create('label', label);
51141
51142	  var context = {
51143	    labelTarget: labelTarget,
51144	    position: position,
51145	    parent: parent || labelTarget.parent,
51146	    shape: label
51147	  };
51148
51149	  this._commandStack.execute('label.create', context);
51150
51151	  return context.shape;
51152	};
51153
51154
51155	/**
51156	 * Append shape to given source, drawing a connection
51157	 * between source and the newly created shape.
51158	 *
51159	 * @param {djs.model.Shape} source
51160	 * @param {djs.model.Shape|Object} shape
51161	 * @param {Point} position
51162	 * @param {djs.model.Shape} target
51163	 * @param {Object} [hints]
51164	 * @param {boolean} [hints.attach]
51165	 * @param {djs.model.Connection|Object} [hints.connection]
51166	 * @param {djs.model.Base} [hints.connectionParent]
51167	 *
51168	 * @return {djs.model.Shape} the newly created shape
51169	 */
51170	Modeling$1.prototype.appendShape = function(source, shape, position, target, hints) {
51171
51172	  hints = hints || {};
51173
51174	  shape = this._create('shape', shape);
51175
51176	  var context = {
51177	    source: source,
51178	    position: position,
51179	    target: target,
51180	    shape: shape,
51181	    connection: hints.connection,
51182	    connectionParent: hints.connectionParent,
51183	    hints: hints
51184	  };
51185
51186	  this._commandStack.execute('shape.append', context);
51187
51188	  return context.shape;
51189	};
51190
51191
51192	Modeling$1.prototype.removeElements = function(elements) {
51193	  var context = {
51194	    elements: elements
51195	  };
51196
51197	  this._commandStack.execute('elements.delete', context);
51198	};
51199
51200
51201	Modeling$1.prototype.distributeElements = function(groups, axis, dimension) {
51202	  var context = {
51203	    groups: groups,
51204	    axis: axis,
51205	    dimension: dimension
51206	  };
51207
51208	  this._commandStack.execute('elements.distribute', context);
51209	};
51210
51211
51212	Modeling$1.prototype.removeShape = function(shape, hints) {
51213	  var context = {
51214	    shape: shape,
51215	    hints: hints || {}
51216	  };
51217
51218	  this._commandStack.execute('shape.delete', context);
51219	};
51220
51221
51222	Modeling$1.prototype.removeConnection = function(connection, hints) {
51223	  var context = {
51224	    connection: connection,
51225	    hints: hints || {}
51226	  };
51227
51228	  this._commandStack.execute('connection.delete', context);
51229	};
51230
51231	Modeling$1.prototype.replaceShape = function(oldShape, newShape, hints) {
51232	  var context = {
51233	    oldShape: oldShape,
51234	    newData: newShape,
51235	    hints: hints || {}
51236	  };
51237
51238	  this._commandStack.execute('shape.replace', context);
51239
51240	  return context.newShape;
51241	};
51242
51243	Modeling$1.prototype.alignElements = function(elements, alignment) {
51244	  var context = {
51245	    elements: elements,
51246	    alignment: alignment
51247	  };
51248
51249	  this._commandStack.execute('elements.align', context);
51250	};
51251
51252	Modeling$1.prototype.resizeShape = function(shape, newBounds, minBounds, hints) {
51253	  var context = {
51254	    shape: shape,
51255	    newBounds: newBounds,
51256	    minBounds: minBounds,
51257	    hints: hints
51258	  };
51259
51260	  this._commandStack.execute('shape.resize', context);
51261	};
51262
51263	Modeling$1.prototype.createSpace = function(movingShapes, resizingShapes, delta, direction, start) {
51264	  var context = {
51265	    delta: delta,
51266	    direction: direction,
51267	    movingShapes: movingShapes,
51268	    resizingShapes: resizingShapes,
51269	    start: start
51270	  };
51271
51272	  this._commandStack.execute('spaceTool', context);
51273	};
51274
51275	Modeling$1.prototype.updateWaypoints = function(connection, newWaypoints, hints) {
51276	  var context = {
51277	    connection: connection,
51278	    newWaypoints: newWaypoints,
51279	    hints: hints || {}
51280	  };
51281
51282	  this._commandStack.execute('connection.updateWaypoints', context);
51283	};
51284
51285	Modeling$1.prototype.reconnect = function(connection, source, target, dockingOrPoints, hints) {
51286	  var context = {
51287	    connection: connection,
51288	    newSource: source,
51289	    newTarget: target,
51290	    dockingOrPoints: dockingOrPoints,
51291	    hints: hints || {}
51292	  };
51293
51294	  this._commandStack.execute('connection.reconnect', context);
51295	};
51296
51297	Modeling$1.prototype.reconnectStart = function(connection, newSource, dockingOrPoints, hints) {
51298	  if (!hints) {
51299	    hints = {};
51300	  }
51301
51302	  this.reconnect(connection, newSource, connection.target, dockingOrPoints, assign(hints, {
51303	    docking: 'source'
51304	  }));
51305	};
51306
51307	Modeling$1.prototype.reconnectEnd = function(connection, newTarget, dockingOrPoints, hints) {
51308	  if (!hints) {
51309	    hints = {};
51310	  }
51311
51312	  this.reconnect(connection, connection.source, newTarget, dockingOrPoints, assign(hints, {
51313	    docking: 'target'
51314	  }));
51315	};
51316
51317	Modeling$1.prototype.connect = function(source, target, attrs, hints) {
51318	  return this.createConnection(source, target, attrs || {}, source.parent, hints);
51319	};
51320
51321	Modeling$1.prototype._create = function(type, attrs) {
51322	  if (attrs instanceof Base$1) {
51323	    return attrs;
51324	  } else {
51325	    return this._elementFactory.create(type, attrs);
51326	  }
51327	};
51328
51329	Modeling$1.prototype.toggleCollapse = function(shape, hints) {
51330	  var context = {
51331	    shape: shape,
51332	    hints: hints || {}
51333	  };
51334
51335	  this._commandStack.execute('shape.toggleCollapse', context);
51336	};
51337
51338	function UpdateModdlePropertiesHandler(elementRegistry) {
51339	  this._elementRegistry = elementRegistry;
51340	}
51341
51342	UpdateModdlePropertiesHandler.$inject = ['elementRegistry'];
51343
51344	UpdateModdlePropertiesHandler.prototype.execute = function(context) {
51345
51346	  var element = context.element,
51347	      moddleElement = context.moddleElement,
51348	      properties = context.properties;
51349
51350	  if (!moddleElement) {
51351	    throw new Error('<moddleElement> required');
51352	  }
51353
51354	  var changed = context.changed || this.getVisualReferences(moddleElement).concat(element);
51355	  var oldProperties = context.oldProperties || getModdleProperties(moddleElement, keys(properties));
51356
51357	  setModdleProperties(moddleElement, properties);
51358
51359	  context.oldProperties = oldProperties;
51360	  context.changed = changed;
51361
51362	  return changed;
51363	};
51364
51365	UpdateModdlePropertiesHandler.prototype.revert = function(context) {
51366	  var oldProperties = context.oldProperties,
51367	      moddleElement = context.moddleElement,
51368	      changed = context.changed;
51369
51370	  setModdleProperties(moddleElement, oldProperties);
51371
51372	  return changed;
51373	};
51374
51375	/**
51376	 * Return visual references of given moddle element within the diagram.
51377	 *
51378	 * @param {ModdleElement} moddleElement
51379	 *
51380	 * @return {Array<djs.model.Element>}
51381	 */
51382	UpdateModdlePropertiesHandler.prototype.getVisualReferences = function(moddleElement) {
51383
51384	  var elementRegistry = this._elementRegistry;
51385
51386	  if (is$1(moddleElement, 'bpmn:DataObject')) {
51387	    return getAllDataObjectReferences(moddleElement, elementRegistry);
51388	  }
51389
51390	  return [];
51391	};
51392
51393
51394	// helpers /////////////////
51395
51396	function getModdleProperties(moddleElement, propertyNames) {
51397	  return reduce(propertyNames, function(result, key) {
51398	    result[key] = moddleElement.get(key);
51399	    return result;
51400	  }, {});
51401	}
51402
51403	function setModdleProperties(moddleElement, properties) {
51404	  forEach(properties, function(value, key) {
51405	    moddleElement.set(key, value);
51406	  });
51407	}
51408
51409	function getAllDataObjectReferences(dataObject, elementRegistry) {
51410	  return elementRegistry.filter(function(element) {
51411	    return (
51412	      is$1(element, 'bpmn:DataObjectReference') &&
51413	          getBusinessObject(element).dataObjectRef === dataObject
51414	    );
51415	  });
51416	}
51417
51418	var DEFAULT_FLOW = 'default',
51419	    ID = 'id',
51420	    DI = 'di';
51421
51422	var NULL_DIMENSIONS$1 = {
51423	  width: 0,
51424	  height: 0
51425	};
51426
51427	/**
51428	 * A handler that implements a BPMN 2.0 property update.
51429	 *
51430	 * This should be used to set simple properties on elements with
51431	 * an underlying BPMN business object.
51432	 *
51433	 * Use respective diagram-js provided handlers if you would
51434	 * like to perform automated modeling.
51435	 */
51436	function UpdatePropertiesHandler(
51437	    elementRegistry, moddle, translate,
51438	    modeling, textRenderer) {
51439
51440	  this._elementRegistry = elementRegistry;
51441	  this._moddle = moddle;
51442	  this._translate = translate;
51443	  this._modeling = modeling;
51444	  this._textRenderer = textRenderer;
51445	}
51446
51447	UpdatePropertiesHandler.$inject = [
51448	  'elementRegistry',
51449	  'moddle',
51450	  'translate',
51451	  'modeling',
51452	  'textRenderer'
51453	];
51454
51455
51456	// api //////////////////////
51457
51458	/**
51459	 * Updates a BPMN element with a list of new properties
51460	 *
51461	 * @param {Object} context
51462	 * @param {djs.model.Base} context.element the element to update
51463	 * @param {Object} context.properties a list of properties to set on the element's
51464	 *                                    businessObject (the BPMN model element)
51465	 *
51466	 * @return {Array<djs.model.Base>} the updated element
51467	 */
51468	UpdatePropertiesHandler.prototype.execute = function(context) {
51469
51470	  var element = context.element,
51471	      changed = [ element ],
51472	      translate = this._translate;
51473
51474	  if (!element) {
51475	    throw new Error(translate('element required'));
51476	  }
51477
51478	  var elementRegistry = this._elementRegistry,
51479	      ids = this._moddle.ids;
51480
51481	  var businessObject = element.businessObject,
51482	      properties = unwrapBusinessObjects(context.properties),
51483	      oldProperties = context.oldProperties || getProperties(businessObject, properties);
51484
51485	  if (isIdChange(properties, businessObject)) {
51486	    ids.unclaim(businessObject[ID]);
51487
51488	    elementRegistry.updateId(element, properties[ID]);
51489
51490	    ids.claim(properties[ID], businessObject);
51491	  }
51492
51493	  // correctly indicate visual changes on default flow updates
51494	  if (DEFAULT_FLOW in properties) {
51495
51496	    if (properties[DEFAULT_FLOW]) {
51497	      changed.push(elementRegistry.get(properties[DEFAULT_FLOW].id));
51498	    }
51499
51500	    if (businessObject[DEFAULT_FLOW]) {
51501	      changed.push(elementRegistry.get(businessObject[DEFAULT_FLOW].id));
51502	    }
51503	  }
51504
51505	  // update properties
51506	  setProperties(businessObject, properties);
51507
51508	  // store old values
51509	  context.oldProperties = oldProperties;
51510	  context.changed = changed;
51511
51512	  // indicate changed on objects affected by the update
51513	  return changed;
51514	};
51515
51516
51517	UpdatePropertiesHandler.prototype.postExecute = function(context) {
51518	  var element = context.element,
51519	      label = element.label;
51520
51521	  var text = label && getBusinessObject(label).name;
51522
51523	  if (!text) {
51524	    return;
51525	  }
51526
51527	  // get layouted text bounds and resize external
51528	  // external label accordingly
51529	  var newLabelBounds = this._textRenderer.getExternalLabelBounds(label, text);
51530
51531	  this._modeling.resizeShape(label, newLabelBounds, NULL_DIMENSIONS$1);
51532	};
51533
51534	/**
51535	 * Reverts the update on a BPMN elements properties.
51536	 *
51537	 * @param  {Object} context
51538	 *
51539	 * @return {djs.model.Base} the updated element
51540	 */
51541	UpdatePropertiesHandler.prototype.revert = function(context) {
51542
51543	  var element = context.element,
51544	      properties = context.properties,
51545	      oldProperties = context.oldProperties,
51546	      businessObject = element.businessObject,
51547	      elementRegistry = this._elementRegistry,
51548	      ids = this._moddle.ids;
51549
51550	  // update properties
51551	  setProperties(businessObject, oldProperties);
51552
51553	  if (isIdChange(properties, businessObject)) {
51554	    ids.unclaim(properties[ID]);
51555
51556	    elementRegistry.updateId(element, oldProperties[ID]);
51557
51558	    ids.claim(oldProperties[ID], businessObject);
51559	  }
51560
51561	  return context.changed;
51562	};
51563
51564
51565	function isIdChange(properties, businessObject) {
51566	  return ID in properties && properties[ID] !== businessObject[ID];
51567	}
51568
51569
51570	function getProperties(businessObject, properties) {
51571	  var propertyNames = keys(properties);
51572
51573	  return reduce(propertyNames, function(result, key) {
51574
51575	    // handle DI separately
51576	    if (key !== DI) {
51577	      result[key] = businessObject.get(key);
51578	    } else {
51579	      result[key] = getDiProperties(businessObject.di, keys(properties.di));
51580	    }
51581
51582	    return result;
51583	  }, {});
51584	}
51585
51586
51587	function getDiProperties(di, propertyNames) {
51588	  return reduce(propertyNames, function(result, key) {
51589	    result[key] = di.get(key);
51590
51591	    return result;
51592	  }, {});
51593	}
51594
51595
51596	function setProperties(businessObject, properties) {
51597	  forEach(properties, function(value, key) {
51598
51599	    if (key !== DI) {
51600	      businessObject.set(key, value);
51601	    } else {
51602
51603	      // only update, if businessObject.di exists
51604	      if (businessObject.di) {
51605	        setDiProperties(businessObject.di, value);
51606	      }
51607	    }
51608	  });
51609	}
51610
51611
51612	function setDiProperties(di, properties) {
51613	  forEach(properties, function(value, key) {
51614	    di.set(key, value);
51615	  });
51616	}
51617
51618
51619	var referencePropertyNames = [ 'default' ];
51620
51621	/**
51622	 * Make sure we unwrap the actual business object
51623	 * behind diagram element that may have been
51624	 * passed as arguments.
51625	 *
51626	 * @param  {Object} properties
51627	 *
51628	 * @return {Object} unwrappedProps
51629	 */
51630	function unwrapBusinessObjects(properties) {
51631
51632	  var unwrappedProps = assign({}, properties);
51633
51634	  referencePropertyNames.forEach(function(name) {
51635	    if (name in properties) {
51636	      unwrappedProps[name] = getBusinessObject(unwrappedProps[name]);
51637	    }
51638	  });
51639
51640	  return unwrappedProps;
51641	}
51642
51643	function UpdateCanvasRootHandler(canvas, modeling) {
51644	  this._canvas = canvas;
51645	  this._modeling = modeling;
51646	}
51647
51648	UpdateCanvasRootHandler.$inject = [
51649	  'canvas',
51650	  'modeling'
51651	];
51652
51653
51654	UpdateCanvasRootHandler.prototype.execute = function(context) {
51655
51656	  var canvas = this._canvas;
51657
51658	  var newRoot = context.newRoot,
51659	      newRootBusinessObject = newRoot.businessObject,
51660	      oldRoot = canvas.getRootElement(),
51661	      oldRootBusinessObject = oldRoot.businessObject,
51662	      bpmnDefinitions = oldRootBusinessObject.$parent,
51663	      diPlane = oldRootBusinessObject.di;
51664
51665	  // (1) replace process old <> new root
51666	  canvas.setRootElement(newRoot, true);
51667
51668	  // (2) update root elements
51669	  add(bpmnDefinitions.rootElements, newRootBusinessObject);
51670	  newRootBusinessObject.$parent = bpmnDefinitions;
51671
51672	  remove(bpmnDefinitions.rootElements, oldRootBusinessObject);
51673	  oldRootBusinessObject.$parent = null;
51674
51675	  // (3) wire di
51676	  oldRootBusinessObject.di = null;
51677
51678	  diPlane.bpmnElement = newRootBusinessObject;
51679	  newRootBusinessObject.di = diPlane;
51680
51681	  context.oldRoot = oldRoot;
51682
51683	  // TODO(nikku): return changed elements?
51684	  // return [ newRoot, oldRoot ];
51685	};
51686
51687
51688	UpdateCanvasRootHandler.prototype.revert = function(context) {
51689
51690	  var canvas = this._canvas;
51691
51692	  var newRoot = context.newRoot,
51693	      newRootBusinessObject = newRoot.businessObject,
51694	      oldRoot = context.oldRoot,
51695	      oldRootBusinessObject = oldRoot.businessObject,
51696	      bpmnDefinitions = newRootBusinessObject.$parent,
51697	      diPlane = newRootBusinessObject.di;
51698
51699	  // (1) replace process old <> new root
51700	  canvas.setRootElement(oldRoot, true);
51701
51702	  // (2) update root elements
51703	  remove(bpmnDefinitions.rootElements, newRootBusinessObject);
51704	  newRootBusinessObject.$parent = null;
51705
51706	  add(bpmnDefinitions.rootElements, oldRootBusinessObject);
51707	  oldRootBusinessObject.$parent = bpmnDefinitions;
51708
51709	  // (3) wire di
51710	  newRootBusinessObject.di = null;
51711
51712	  diPlane.bpmnElement = oldRootBusinessObject;
51713	  oldRootBusinessObject.di = diPlane;
51714
51715	  // TODO(nikku): return changed elements?
51716	  // return [ newRoot, oldRoot ];
51717	};
51718
51719	/**
51720	 * A handler that allows us to add a new lane
51721	 * above or below an existing one.
51722	 *
51723	 * @param {Modeling} modeling
51724	 * @param {SpaceTool} spaceTool
51725	 */
51726	function AddLaneHandler(modeling, spaceTool) {
51727	  this._modeling = modeling;
51728	  this._spaceTool = spaceTool;
51729	}
51730
51731	AddLaneHandler.$inject = [
51732	  'modeling',
51733	  'spaceTool'
51734	];
51735
51736
51737	AddLaneHandler.prototype.preExecute = function(context) {
51738
51739	  var spaceTool = this._spaceTool,
51740	      modeling = this._modeling;
51741
51742	  var shape = context.shape,
51743	      location = context.location;
51744
51745	  var lanesRoot = getLanesRoot(shape);
51746
51747	  var isRoot = lanesRoot === shape,
51748	      laneParent = isRoot ? shape : shape.parent;
51749
51750	  var existingChildLanes = getChildLanes(laneParent);
51751
51752	  // (0) add a lane if we currently got none and are adding to root
51753	  if (!existingChildLanes.length) {
51754	    modeling.createShape({ type: 'bpmn:Lane' }, {
51755	      x: shape.x + LANE_INDENTATION,
51756	      y: shape.y,
51757	      width: shape.width - LANE_INDENTATION,
51758	      height: shape.height
51759	    }, laneParent);
51760	  }
51761
51762	  // (1) collect affected elements to create necessary space
51763	  var allAffected = [];
51764
51765	  eachElement(lanesRoot, function(element) {
51766	    allAffected.push(element);
51767
51768	    // handle element labels in the diagram root
51769	    if (element.label) {
51770	      allAffected.push(element.label);
51771	    }
51772
51773	    if (element === shape) {
51774	      return [];
51775	    }
51776
51777	    return filter(element.children, function(c) {
51778	      return c !== shape;
51779	    });
51780	  });
51781
51782	  var offset = location === 'top' ? -120 : 120,
51783	      lanePosition = location === 'top' ? shape.y : shape.y + shape.height,
51784	      spacePos = lanePosition + (location === 'top' ? 10 : -10),
51785	      direction = location === 'top' ? 'n' : 's';
51786
51787	  var adjustments = spaceTool.calculateAdjustments(allAffected, 'y', offset, spacePos);
51788
51789	  spaceTool.makeSpace(
51790	    adjustments.movingShapes,
51791	    adjustments.resizingShapes,
51792	    { x: 0, y: offset },
51793	    direction,
51794	    spacePos
51795	  );
51796
51797	  // (2) create new lane at open space
51798	  context.newLane = modeling.createShape({ type: 'bpmn:Lane' }, {
51799	    x: shape.x + (isRoot ? LANE_INDENTATION : 0),
51800	    y: lanePosition - (location === 'top' ? 120 : 0),
51801	    width: shape.width - (isRoot ? LANE_INDENTATION : 0),
51802	    height: 120
51803	  }, laneParent);
51804	};
51805
51806	/**
51807	 * A handler that splits a lane into a number of sub-lanes,
51808	 * creating new sub lanes, if necessary.
51809	 *
51810	 * @param {Modeling} modeling
51811	 */
51812	function SplitLaneHandler(modeling, translate) {
51813	  this._modeling = modeling;
51814	  this._translate = translate;
51815	}
51816
51817	SplitLaneHandler.$inject = [
51818	  'modeling',
51819	  'translate'
51820	];
51821
51822
51823	SplitLaneHandler.prototype.preExecute = function(context) {
51824
51825	  var modeling = this._modeling,
51826	      translate = this._translate;
51827
51828	  var shape = context.shape,
51829	      newLanesCount = context.count;
51830
51831	  var childLanes = getChildLanes(shape),
51832	      existingLanesCount = childLanes.length;
51833
51834	  if (existingLanesCount > newLanesCount) {
51835	    throw new Error(translate('more than {count} child lanes', { count: newLanesCount }));
51836	  }
51837
51838	  var newLanesHeight = Math.round(shape.height / newLanesCount);
51839
51840	  // Iterate from top to bottom in child lane order,
51841	  // resizing existing lanes and creating new ones
51842	  // so that they split the parent proportionally.
51843	  //
51844	  // Due to rounding related errors, the bottom lane
51845	  // needs to take up all the remaining space.
51846	  var laneY,
51847	      laneHeight,
51848	      laneBounds,
51849	      newLaneAttrs,
51850	      idx;
51851
51852	  for (idx = 0; idx < newLanesCount; idx++) {
51853
51854	    laneY = shape.y + idx * newLanesHeight;
51855
51856	    // if bottom lane
51857	    if (idx === newLanesCount - 1) {
51858	      laneHeight = shape.height - (newLanesHeight * idx);
51859	    } else {
51860	      laneHeight = newLanesHeight;
51861	    }
51862
51863	    laneBounds = {
51864	      x: shape.x + LANE_INDENTATION,
51865	      y: laneY,
51866	      width: shape.width - LANE_INDENTATION,
51867	      height: laneHeight
51868	    };
51869
51870	    if (idx < existingLanesCount) {
51871
51872	      // resize existing lane
51873	      modeling.resizeShape(childLanes[idx], laneBounds);
51874	    } else {
51875
51876	      // create a new lane at position
51877	      newLaneAttrs = {
51878	        type: 'bpmn:Lane'
51879	      };
51880
51881	      modeling.createShape(newLaneAttrs, laneBounds, shape);
51882	    }
51883	  }
51884	};
51885
51886	/**
51887	 * A handler that resizes a lane.
51888	 *
51889	 * @param {Modeling} modeling
51890	 */
51891	function ResizeLaneHandler(modeling, spaceTool) {
51892	  this._modeling = modeling;
51893	  this._spaceTool = spaceTool;
51894	}
51895
51896	ResizeLaneHandler.$inject = [
51897	  'modeling',
51898	  'spaceTool'
51899	];
51900
51901
51902	ResizeLaneHandler.prototype.preExecute = function(context) {
51903
51904	  var shape = context.shape,
51905	      newBounds = context.newBounds,
51906	      balanced = context.balanced;
51907
51908	  if (balanced !== false) {
51909	    this.resizeBalanced(shape, newBounds);
51910	  } else {
51911	    this.resizeSpace(shape, newBounds);
51912	  }
51913	};
51914
51915
51916	/**
51917	 * Resize balanced, adjusting next / previous lane sizes.
51918	 *
51919	 * @param {djs.model.Shape} shape
51920	 * @param {Bounds} newBounds
51921	 */
51922	ResizeLaneHandler.prototype.resizeBalanced = function(shape, newBounds) {
51923
51924	  var modeling = this._modeling;
51925
51926	  var resizeNeeded = computeLanesResize(shape, newBounds);
51927
51928	  // resize the lane
51929	  modeling.resizeShape(shape, newBounds);
51930
51931	  // resize other lanes as needed
51932	  resizeNeeded.forEach(function(r) {
51933	    modeling.resizeShape(r.shape, r.newBounds);
51934	  });
51935	};
51936
51937
51938	/**
51939	 * Resize, making actual space and moving below / above elements.
51940	 *
51941	 * @param {djs.model.Shape} shape
51942	 * @param {Bounds} newBounds
51943	 */
51944	ResizeLaneHandler.prototype.resizeSpace = function(shape, newBounds) {
51945	  var spaceTool = this._spaceTool;
51946
51947	  var shapeTrbl = asTRBL(shape),
51948	      newTrbl = asTRBL(newBounds);
51949
51950	  var trblDiff = substractTRBL(newTrbl, shapeTrbl);
51951
51952	  var lanesRoot = getLanesRoot(shape);
51953
51954	  var allAffected = [],
51955	      allLanes = [];
51956
51957	  eachElement(lanesRoot, function(element) {
51958	    allAffected.push(element);
51959
51960	    if (is$1(element, 'bpmn:Lane') || is$1(element, 'bpmn:Participant')) {
51961	      allLanes.push(element);
51962	    }
51963
51964	    return element.children;
51965	  });
51966
51967	  var change,
51968	      spacePos,
51969	      direction,
51970	      offset,
51971	      adjustments;
51972
51973	  if (trblDiff.bottom || trblDiff.top) {
51974
51975	    change = trblDiff.bottom || trblDiff.top;
51976	    spacePos = shape.y + (trblDiff.bottom ? shape.height : 0) + (trblDiff.bottom ? -10 : 10);
51977	    direction = trblDiff.bottom ? 's' : 'n';
51978
51979	    offset = trblDiff.top > 0 || trblDiff.bottom < 0 ? -change : change;
51980
51981	    adjustments = spaceTool.calculateAdjustments(allAffected, 'y', offset, spacePos);
51982
51983	    spaceTool.makeSpace(adjustments.movingShapes, adjustments.resizingShapes, { x: 0, y: change }, direction);
51984	  }
51985
51986
51987	  if (trblDiff.left || trblDiff.right) {
51988
51989	    change = trblDiff.right || trblDiff.left;
51990	    spacePos = shape.x + (trblDiff.right ? shape.width : 0) + (trblDiff.right ? -10 : 100);
51991	    direction = trblDiff.right ? 'e' : 'w';
51992
51993	    offset = trblDiff.left > 0 || trblDiff.right < 0 ? -change : change;
51994
51995	    adjustments = spaceTool.calculateAdjustments(allLanes, 'x', offset, spacePos);
51996
51997	    spaceTool.makeSpace(adjustments.movingShapes, adjustments.resizingShapes, { x: change, y: 0 }, direction);
51998	  }
51999	};
52000
52001	var FLOW_NODE_REFS_ATTR = 'flowNodeRef',
52002	    LANES_ATTR = 'lanes';
52003
52004
52005	/**
52006	 * A handler that updates lane refs on changed elements
52007	 */
52008	function UpdateFlowNodeRefsHandler(elementRegistry) {
52009	  this._elementRegistry = elementRegistry;
52010	}
52011
52012	UpdateFlowNodeRefsHandler.$inject = [
52013	  'elementRegistry'
52014	];
52015
52016
52017	UpdateFlowNodeRefsHandler.prototype.computeUpdates = function(flowNodeShapes, laneShapes) {
52018
52019	  var handledNodes = [];
52020
52021	  var updates = [];
52022
52023	  var participantCache = {};
52024
52025	  var allFlowNodeShapes = [];
52026
52027	  function isInLaneShape(element, laneShape) {
52028
52029	    var laneTrbl = asTRBL(laneShape);
52030
52031	    var elementMid = {
52032	      x: element.x + element.width / 2,
52033	      y: element.y + element.height / 2
52034	    };
52035
52036	    return elementMid.x > laneTrbl.left &&
52037	           elementMid.x < laneTrbl.right &&
52038	           elementMid.y > laneTrbl.top &&
52039	           elementMid.y < laneTrbl.bottom;
52040	  }
52041
52042	  function addFlowNodeShape(flowNodeShape) {
52043	    if (handledNodes.indexOf(flowNodeShape) === -1) {
52044	      allFlowNodeShapes.push(flowNodeShape);
52045	      handledNodes.push(flowNodeShape);
52046	    }
52047	  }
52048
52049	  function getAllLaneShapes(flowNodeShape) {
52050
52051	    var root = getLanesRoot(flowNodeShape);
52052
52053	    if (!participantCache[root.id]) {
52054	      participantCache[root.id] = collectLanes(root);
52055	    }
52056
52057	    return participantCache[root.id];
52058	  }
52059
52060	  function getNewLanes(flowNodeShape) {
52061	    if (!flowNodeShape.parent) {
52062	      return [];
52063	    }
52064
52065	    var allLaneShapes = getAllLaneShapes(flowNodeShape);
52066
52067	    return allLaneShapes.filter(function(l) {
52068	      return isInLaneShape(flowNodeShape, l);
52069	    }).map(function(shape) {
52070	      return shape.businessObject;
52071	    });
52072	  }
52073
52074	  laneShapes.forEach(function(laneShape) {
52075	    var root = getLanesRoot(laneShape);
52076
52077	    if (!root || handledNodes.indexOf(root) !== -1) {
52078	      return;
52079	    }
52080
52081	    var children = root.children.filter(function(c) {
52082	      return is$1(c, 'bpmn:FlowNode');
52083	    });
52084
52085	    children.forEach(addFlowNodeShape);
52086
52087	    handledNodes.push(root);
52088	  });
52089
52090	  flowNodeShapes.forEach(addFlowNodeShape);
52091
52092
52093	  allFlowNodeShapes.forEach(function(flowNodeShape) {
52094
52095	    var flowNode = flowNodeShape.businessObject;
52096
52097	    var lanes = flowNode.get(LANES_ATTR),
52098	        remove = lanes.slice(),
52099	        add = getNewLanes(flowNodeShape);
52100
52101	    updates.push({ flowNode: flowNode, remove: remove, add: add });
52102	  });
52103
52104	  laneShapes.forEach(function(laneShape) {
52105
52106	    var lane = laneShape.businessObject;
52107
52108	    // lane got removed XX-)
52109	    if (!laneShape.parent) {
52110	      lane.get(FLOW_NODE_REFS_ATTR).forEach(function(flowNode) {
52111	        updates.push({ flowNode: flowNode, remove: [ lane ], add: [] });
52112	      });
52113	    }
52114	  });
52115
52116	  return updates;
52117	};
52118
52119	UpdateFlowNodeRefsHandler.prototype.execute = function(context) {
52120
52121	  var updates = context.updates;
52122
52123	  if (!updates) {
52124	    updates = context.updates = this.computeUpdates(context.flowNodeShapes, context.laneShapes);
52125	  }
52126
52127
52128	  updates.forEach(function(update) {
52129
52130	    var flowNode = update.flowNode,
52131	        lanes = flowNode.get(LANES_ATTR);
52132
52133	    // unwire old
52134	    update.remove.forEach(function(oldLane) {
52135	      remove(lanes, oldLane);
52136	      remove(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
52137	    });
52138
52139	    // wire new
52140	    update.add.forEach(function(newLane) {
52141	      add(lanes, newLane);
52142	      add(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
52143	    });
52144	  });
52145
52146	  // TODO(nikku): return changed elements
52147	  // return [ ... ];
52148	};
52149
52150
52151	UpdateFlowNodeRefsHandler.prototype.revert = function(context) {
52152
52153	  var updates = context.updates;
52154
52155	  updates.forEach(function(update) {
52156
52157	    var flowNode = update.flowNode,
52158	        lanes = flowNode.get(LANES_ATTR);
52159
52160	    // unwire new
52161	    update.add.forEach(function(newLane) {
52162	      remove(lanes, newLane);
52163	      remove(newLane.get(FLOW_NODE_REFS_ATTR), flowNode);
52164	    });
52165
52166	    // wire old
52167	    update.remove.forEach(function(oldLane) {
52168	      add(lanes, oldLane);
52169	      add(oldLane.get(FLOW_NODE_REFS_ATTR), flowNode);
52170	    });
52171	  });
52172
52173	  // TODO(nikku): return changed elements
52174	  // return [ ... ];
52175	};
52176
52177	function IdClaimHandler(moddle) {
52178	  this._moddle = moddle;
52179	}
52180
52181	IdClaimHandler.$inject = [ 'moddle' ];
52182
52183
52184	IdClaimHandler.prototype.execute = function(context) {
52185	  var ids = this._moddle.ids,
52186	      id = context.id,
52187	      element = context.element,
52188	      claiming = context.claiming;
52189
52190	  if (claiming) {
52191	    ids.claim(id, element);
52192	  } else {
52193	    ids.unclaim(id);
52194	  }
52195	};
52196
52197	/**
52198	 * Command revert implementation.
52199	 */
52200	IdClaimHandler.prototype.revert = function(context) {
52201	  var ids = this._moddle.ids,
52202	      id = context.id,
52203	      element = context.element,
52204	      claiming = context.claiming;
52205
52206	  if (claiming) {
52207	    ids.unclaim(id);
52208	  } else {
52209	    ids.claim(id, element);
52210	  }
52211	};
52212
52213	var DEFAULT_COLORS = {
52214	  fill: undefined,
52215	  stroke: undefined
52216	};
52217
52218
52219	function SetColorHandler(commandStack) {
52220	  this._commandStack = commandStack;
52221
52222	  this._normalizeColor = function(color) {
52223
52224	    // Remove color for falsy values.
52225	    if (!color) {
52226	      return undefined;
52227	    }
52228
52229	    if (isString(color)) {
52230	      var hexColor = colorToHex(color);
52231
52232	      if (hexColor) {
52233	        return hexColor;
52234	      }
52235	    }
52236
52237	    throw new Error('invalid color value: ' + color);
52238	  };
52239	}
52240
52241	SetColorHandler.$inject = [
52242	  'commandStack'
52243	];
52244
52245
52246	SetColorHandler.prototype.postExecute = function(context) {
52247	  var elements = context.elements,
52248	      colors = context.colors || DEFAULT_COLORS;
52249
52250	  var self = this;
52251
52252	  var di = {};
52253
52254	  if ('fill' in colors) {
52255	    assign(di, {
52256	      'background-color': this._normalizeColor(colors.fill) });
52257	  }
52258
52259	  if ('stroke' in colors) {
52260	    assign(di, {
52261	      'border-color': this._normalizeColor(colors.stroke) });
52262	  }
52263
52264	  forEach(elements, function(element) {
52265	    var assignedDi = isConnection$3(element) ? pick(di, [ 'border-color' ]) : di;
52266
52267	    // TODO @barmac: remove once we drop bpmn.io properties
52268	    ensureLegacySupport(assignedDi);
52269
52270	    self._commandStack.execute('element.updateProperties', {
52271	      element: element,
52272	      properties: {
52273	        di: assignedDi
52274	      }
52275	    });
52276	  });
52277
52278	};
52279
52280	/**
52281	 * Convert color from rgb(a)/hsl to hex. Returns `null` for unknown color names and for colors
52282	 * with alpha less than 1.0. This depends on `<canvas>` serialization of the `context.fillStyle`.
52283	 * Cf. https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fillstyle
52284	 *
52285	 * @example
52286	 * ```js
52287	 * var color = 'fuchsia';
52288	 * console.log(colorToHex(color));
52289	 * // "#ff00ff"
52290	 * color = 'rgba(1,2,3,0.4)';
52291	 * console.log(colorToHex(color));
52292	 * // null
52293	 * ```
52294	 *
52295	 * @param {string} color
52296	 * @returns {string|null}
52297	 */
52298	function colorToHex(color) {
52299	  var context = document.createElement('canvas').getContext('2d');
52300
52301	  // (0) Start with transparent to account for browser default values.
52302	  context.fillStyle = 'transparent';
52303
52304	  // (1) Assign color so that it's serialized.
52305	  context.fillStyle = color;
52306
52307	  // (2) Return null for non-hex serialization result.
52308	  return /^#[0-9a-fA-F]{6}$/.test(context.fillStyle) ? context.fillStyle : null;
52309	}
52310
52311	function isConnection$3(element) {
52312	  return !!element.waypoints;
52313	}
52314
52315	/**
52316	 * Add legacy properties if required.
52317	 * @param {{ 'border-color': string?, 'background-color': string? }} di
52318	 */
52319	function ensureLegacySupport(di) {
52320	  if ('border-color' in di) {
52321	    di.stroke = di['border-color'];
52322	  }
52323
52324	  if ('background-color' in di) {
52325	    di.fill = di['background-color'];
52326	  }
52327	}
52328
52329	var NULL_DIMENSIONS = {
52330	  width: 0,
52331	  height: 0
52332	};
52333
52334
52335	/**
52336	 * A handler that updates the text of a BPMN element.
52337	 */
52338	function UpdateLabelHandler(modeling, textRenderer) {
52339
52340	  /**
52341	   * Set the label and return the changed elements.
52342	   *
52343	   * Element parameter can be label itself or connection (i.e. sequence flow).
52344	   *
52345	   * @param {djs.model.Base} element
52346	   * @param {string} text
52347	   */
52348	  function setText(element, text) {
52349
52350	    // external label if present
52351	    var label = element.label || element;
52352
52353	    var labelTarget = element.labelTarget || element;
52354
52355	    setLabel(label, text);
52356
52357	    return [ label, labelTarget ];
52358	  }
52359
52360	  function preExecute(ctx) {
52361	    var element = ctx.element,
52362	        businessObject = element.businessObject,
52363	        newLabel = ctx.newLabel;
52364
52365	    if (!isLabel$6(element)
52366	        && isLabelExternal(element)
52367	        && !hasExternalLabel(element)
52368	        && !isEmptyText(newLabel)) {
52369
52370	      // create label
52371	      var paddingTop = 7;
52372
52373	      var labelCenter = getExternalLabelMid(element);
52374
52375	      labelCenter = {
52376	        x: labelCenter.x,
52377	        y: labelCenter.y + paddingTop
52378	      };
52379
52380	      modeling.createLabel(element, labelCenter, {
52381	        id: businessObject.id + '_label',
52382	        businessObject: businessObject
52383	      });
52384	    }
52385	  }
52386
52387	  function execute(ctx) {
52388	    ctx.oldLabel = getLabel(ctx.element);
52389	    return setText(ctx.element, ctx.newLabel);
52390	  }
52391
52392	  function revert(ctx) {
52393	    return setText(ctx.element, ctx.oldLabel);
52394	  }
52395
52396	  function postExecute(ctx) {
52397	    var element = ctx.element,
52398	        label = element.label || element,
52399	        newLabel = ctx.newLabel,
52400	        newBounds = ctx.newBounds,
52401	        hints = ctx.hints || {};
52402
52403	    // ignore internal labels for elements except text annotations
52404	    if (!isLabel$6(label) && !is$1(label, 'bpmn:TextAnnotation')) {
52405	      return;
52406	    }
52407
52408	    if (isLabel$6(label) && isEmptyText(newLabel)) {
52409
52410	      if (hints.removeShape !== false) {
52411	        modeling.removeShape(label, { unsetLabel: false });
52412	      }
52413
52414	      return;
52415	    }
52416
52417	    var text = getLabel(label);
52418
52419	    // resize element based on label _or_ pre-defined bounds
52420	    if (typeof newBounds === 'undefined') {
52421	      newBounds = textRenderer.getExternalLabelBounds(label, text);
52422	    }
52423
52424	    // setting newBounds to false or _null_ will
52425	    // disable the postExecute resize operation
52426	    if (newBounds) {
52427	      modeling.resizeShape(label, newBounds, NULL_DIMENSIONS);
52428	    }
52429	  }
52430
52431	  // API
52432
52433	  this.preExecute = preExecute;
52434	  this.execute = execute;
52435	  this.revert = revert;
52436	  this.postExecute = postExecute;
52437	}
52438
52439	UpdateLabelHandler.$inject = [
52440	  'modeling',
52441	  'textRenderer'
52442	];
52443
52444
52445	// helpers ///////////////////////
52446
52447	function isEmptyText(label) {
52448	  return !label || !label.trim();
52449	}
52450
52451	/**
52452	 * BPMN 2.0 modeling features activator
52453	 *
52454	 * @param {EventBus} eventBus
52455	 * @param {ElementFactory} elementFactory
52456	 * @param {CommandStack} commandStack
52457	 * @param {BpmnRules} bpmnRules
52458	 */
52459	function Modeling(
52460	    eventBus, elementFactory, commandStack,
52461	    bpmnRules) {
52462
52463	  Modeling$1.call(this, eventBus, elementFactory, commandStack);
52464
52465	  this._bpmnRules = bpmnRules;
52466	}
52467
52468	inherits$1(Modeling, Modeling$1);
52469
52470	Modeling.$inject = [
52471	  'eventBus',
52472	  'elementFactory',
52473	  'commandStack',
52474	  'bpmnRules'
52475	];
52476
52477
52478	Modeling.prototype.getHandlers = function() {
52479	  var handlers = Modeling$1.prototype.getHandlers.call(this);
52480
52481	  handlers['element.updateModdleProperties'] = UpdateModdlePropertiesHandler;
52482	  handlers['element.updateProperties'] = UpdatePropertiesHandler;
52483	  handlers['canvas.updateRoot'] = UpdateCanvasRootHandler;
52484	  handlers['lane.add'] = AddLaneHandler;
52485	  handlers['lane.resize'] = ResizeLaneHandler;
52486	  handlers['lane.split'] = SplitLaneHandler;
52487	  handlers['lane.updateRefs'] = UpdateFlowNodeRefsHandler;
52488	  handlers['id.updateClaim'] = IdClaimHandler;
52489	  handlers['element.setColor'] = SetColorHandler;
52490	  handlers['element.updateLabel'] = UpdateLabelHandler;
52491
52492	  return handlers;
52493	};
52494
52495
52496	Modeling.prototype.updateLabel = function(element, newLabel, newBounds, hints) {
52497	  this._commandStack.execute('element.updateLabel', {
52498	    element: element,
52499	    newLabel: newLabel,
52500	    newBounds: newBounds,
52501	    hints: hints || {}
52502	  });
52503	};
52504
52505
52506	Modeling.prototype.connect = function(source, target, attrs, hints) {
52507
52508	  var bpmnRules = this._bpmnRules;
52509
52510	  if (!attrs) {
52511	    attrs = bpmnRules.canConnect(source, target);
52512	  }
52513
52514	  if (!attrs) {
52515	    return;
52516	  }
52517
52518	  return this.createConnection(source, target, attrs, source.parent, hints);
52519	};
52520
52521
52522	Modeling.prototype.updateModdleProperties = function(element, moddleElement, properties) {
52523	  this._commandStack.execute('element.updateModdleProperties', {
52524	    element: element,
52525	    moddleElement: moddleElement,
52526	    properties: properties
52527	  });
52528	};
52529
52530	Modeling.prototype.updateProperties = function(element, properties) {
52531	  this._commandStack.execute('element.updateProperties', {
52532	    element: element,
52533	    properties: properties
52534	  });
52535	};
52536
52537	Modeling.prototype.resizeLane = function(laneShape, newBounds, balanced) {
52538	  this._commandStack.execute('lane.resize', {
52539	    shape: laneShape,
52540	    newBounds: newBounds,
52541	    balanced: balanced
52542	  });
52543	};
52544
52545	Modeling.prototype.addLane = function(targetLaneShape, location) {
52546	  var context = {
52547	    shape: targetLaneShape,
52548	    location: location
52549	  };
52550
52551	  this._commandStack.execute('lane.add', context);
52552
52553	  return context.newLane;
52554	};
52555
52556	Modeling.prototype.splitLane = function(targetLane, count) {
52557	  this._commandStack.execute('lane.split', {
52558	    shape: targetLane,
52559	    count: count
52560	  });
52561	};
52562
52563	/**
52564	 * Transform the current diagram into a collaboration.
52565	 *
52566	 * @return {djs.model.Root} the new root element
52567	 */
52568	Modeling.prototype.makeCollaboration = function() {
52569
52570	  var collaborationElement = this._create('root', {
52571	    type: 'bpmn:Collaboration'
52572	  });
52573
52574	  var context = {
52575	    newRoot: collaborationElement
52576	  };
52577
52578	  this._commandStack.execute('canvas.updateRoot', context);
52579
52580	  return collaborationElement;
52581	};
52582
52583	Modeling.prototype.updateLaneRefs = function(flowNodeShapes, laneShapes) {
52584
52585	  this._commandStack.execute('lane.updateRefs', {
52586	    flowNodeShapes: flowNodeShapes,
52587	    laneShapes: laneShapes
52588	  });
52589	};
52590
52591	/**
52592	 * Transform the current diagram into a process.
52593	 *
52594	 * @return {djs.model.Root} the new root element
52595	 */
52596	Modeling.prototype.makeProcess = function() {
52597
52598	  var processElement = this._create('root', {
52599	    type: 'bpmn:Process'
52600	  });
52601
52602	  var context = {
52603	    newRoot: processElement
52604	  };
52605
52606	  this._commandStack.execute('canvas.updateRoot', context);
52607	};
52608
52609
52610	Modeling.prototype.claimId = function(id, moddleElement) {
52611	  this._commandStack.execute('id.updateClaim', {
52612	    id: id,
52613	    element: moddleElement,
52614	    claiming: true
52615	  });
52616	};
52617
52618
52619	Modeling.prototype.unclaimId = function(id, moddleElement) {
52620	  this._commandStack.execute('id.updateClaim', {
52621	    id: id,
52622	    element: moddleElement
52623	  });
52624	};
52625
52626	Modeling.prototype.setColor = function(elements, colors) {
52627	  if (!elements.length) {
52628	    elements = [ elements ];
52629	  }
52630
52631	  this._commandStack.execute('element.setColor', {
52632	    elements: elements,
52633	    colors: colors
52634	  });
52635	};
52636
52637	/**
52638	 * A base connection layouter implementation
52639	 * that layouts the connection by directly connecting
52640	 * mid(source) + mid(target).
52641	 */
52642	function BaseLayouter() {}
52643
52644
52645	/**
52646	 * Return the new layouted waypoints for the given connection.
52647	 *
52648	 * The connection passed is still unchanged; you may figure out about
52649	 * the new connection start / end via the layout hints provided.
52650	 *
52651	 * @param {djs.model.Connection} connection
52652	 * @param {Object} [hints]
52653	 * @param {Point} [hints.connectionStart]
52654	 * @param {Point} [hints.connectionEnd]
52655	 * @param {Point} [hints.source]
52656	 * @param {Point} [hints.target]
52657	 *
52658	 * @return {Array<Point>} the layouted connection waypoints
52659	 */
52660	BaseLayouter.prototype.layoutConnection = function(connection, hints) {
52661
52662	  hints = hints || {};
52663
52664	  return [
52665	    hints.connectionStart || getMid(hints.source || connection.source),
52666	    hints.connectionEnd || getMid(hints.target || connection.target)
52667	  ];
52668	};
52669
52670	var MIN_SEGMENT_LENGTH = 20,
52671	    POINT_ORIENTATION_PADDING = 5;
52672
52673	var round$1 = Math.round;
52674
52675	var INTERSECTION_THRESHOLD = 20,
52676	    ORIENTATION_THRESHOLD = {
52677	      'h:h': 20,
52678	      'v:v': 20,
52679	      'h:v': -10,
52680	      'v:h': -10
52681	    };
52682
52683	function needsTurn(orientation, startDirection) {
52684	  return !{
52685	    t: /top/,
52686	    r: /right/,
52687	    b: /bottom/,
52688	    l: /left/,
52689	    h: /./,
52690	    v: /./
52691	  }[startDirection].test(orientation);
52692	}
52693
52694	function canLayoutStraight(direction, targetOrientation) {
52695	  return {
52696	    t: /top/,
52697	    r: /right/,
52698	    b: /bottom/,
52699	    l: /left/,
52700	    h: /left|right/,
52701	    v: /top|bottom/
52702	  }[direction].test(targetOrientation);
52703	}
52704
52705	function getSegmentBendpoints(a, b, directions) {
52706	  var orientation = getOrientation(b, a, POINT_ORIENTATION_PADDING);
52707
52708	  var startDirection = directions.split(':')[0];
52709
52710	  var xmid = round$1((b.x - a.x) / 2 + a.x),
52711	      ymid = round$1((b.y - a.y) / 2 + a.y);
52712
52713	  var segmentEnd, segmentDirections;
52714
52715	  var layoutStraight = canLayoutStraight(startDirection, orientation),
52716	      layoutHorizontal = /h|r|l/.test(startDirection),
52717	      layoutTurn = false;
52718
52719	  var turnNextDirections = false;
52720
52721	  if (layoutStraight) {
52722	    segmentEnd = layoutHorizontal ? { x: xmid, y: a.y } : { x: a.x, y: ymid };
52723
52724	    segmentDirections = layoutHorizontal ? 'h:h' : 'v:v';
52725	  } else {
52726	    layoutTurn = needsTurn(orientation, startDirection);
52727
52728	    segmentDirections = layoutHorizontal ? 'h:v' : 'v:h';
52729
52730	    if (layoutTurn) {
52731
52732	      if (layoutHorizontal) {
52733	        turnNextDirections = ymid === a.y;
52734
52735	        segmentEnd = {
52736	          x: a.x + MIN_SEGMENT_LENGTH * (/l/.test(startDirection) ? -1 : 1),
52737	          y: turnNextDirections ? ymid + MIN_SEGMENT_LENGTH : ymid
52738	        };
52739	      } else {
52740	        turnNextDirections = xmid === a.x;
52741
52742	        segmentEnd = {
52743	          x: turnNextDirections ? xmid + MIN_SEGMENT_LENGTH : xmid,
52744	          y: a.y + MIN_SEGMENT_LENGTH * (/t/.test(startDirection) ? -1 : 1)
52745	        };
52746	      }
52747
52748	    } else {
52749	      segmentEnd = {
52750	        x: xmid,
52751	        y: ymid
52752	      };
52753	    }
52754	  }
52755
52756	  return {
52757	    waypoints: getBendpoints(a, segmentEnd, segmentDirections).concat(segmentEnd),
52758	    directions:  segmentDirections,
52759	    turnNextDirections: turnNextDirections
52760	  };
52761	}
52762
52763	function getStartSegment(a, b, directions) {
52764	  return getSegmentBendpoints(a, b, directions);
52765	}
52766
52767	function getEndSegment(a, b, directions) {
52768	  var invertedSegment = getSegmentBendpoints(b, a, invertDirections(directions));
52769
52770	  return {
52771	    waypoints: invertedSegment.waypoints.slice().reverse(),
52772	    directions: invertDirections(invertedSegment.directions),
52773	    turnNextDirections: invertedSegment.turnNextDirections
52774	  };
52775	}
52776
52777	function getMidSegment(startSegment, endSegment) {
52778
52779	  var startDirection = startSegment.directions.split(':')[1],
52780	      endDirection = endSegment.directions.split(':')[0];
52781
52782	  if (startSegment.turnNextDirections) {
52783	    startDirection = startDirection == 'h' ? 'v' : 'h';
52784	  }
52785
52786	  if (endSegment.turnNextDirections) {
52787	    endDirection = endDirection == 'h' ? 'v' : 'h';
52788	  }
52789
52790	  var directions = startDirection + ':' + endDirection;
52791
52792	  var bendpoints = getBendpoints(
52793	    startSegment.waypoints[startSegment.waypoints.length - 1],
52794	    endSegment.waypoints[0],
52795	    directions
52796	  );
52797
52798	  return {
52799	    waypoints: bendpoints,
52800	    directions: directions
52801	  };
52802	}
52803
52804	function invertDirections(directions) {
52805	  return directions.split(':').reverse().join(':');
52806	}
52807
52808	/**
52809	 * Handle simple layouts with maximum two bendpoints.
52810	 */
52811	function getSimpleBendpoints(a, b, directions) {
52812
52813	  var xmid = round$1((b.x - a.x) / 2 + a.x),
52814	      ymid = round$1((b.y - a.y) / 2 + a.y);
52815
52816	  // one point, right or left from a
52817	  if (directions === 'h:v') {
52818	    return [ { x: b.x, y: a.y } ];
52819	  }
52820
52821	  // one point, above or below a
52822	  if (directions === 'v:h') {
52823	    return [ { x: a.x, y: b.y } ];
52824	  }
52825
52826	  // vertical segment between a and b
52827	  if (directions === 'h:h') {
52828	    return [
52829	      { x: xmid, y: a.y },
52830	      { x: xmid, y: b.y }
52831	    ];
52832	  }
52833
52834	  // horizontal segment between a and b
52835	  if (directions === 'v:v') {
52836	    return [
52837	      { x: a.x, y: ymid },
52838	      { x: b.x, y: ymid }
52839	    ];
52840	  }
52841
52842	  throw new Error('invalid directions: can only handle varians of [hv]:[hv]');
52843	}
52844
52845
52846	/**
52847	 * Returns the mid points for a manhattan connection between two points.
52848	 *
52849	 * @example h:h (horizontal:horizontal)
52850	 *
52851	 * [a]----[x]
52852	 *         |
52853	 *        [x]----[b]
52854	 *
52855	 * @example h:v (horizontal:vertical)
52856	 *
52857	 * [a]----[x]
52858	 *         |
52859	 *        [b]
52860	 *
52861	 * @example h:r (horizontal:right)
52862	 *
52863	 * [a]----[x]
52864	 *         |
52865	 *    [b]-[x]
52866	 *
52867	 * @param  {Point} a
52868	 * @param  {Point} b
52869	 * @param  {string} directions
52870	 *
52871	 * @return {Array<Point>}
52872	 */
52873	function getBendpoints(a, b, directions) {
52874	  directions = directions || 'h:h';
52875
52876	  if (!isValidDirections(directions)) {
52877	    throw new Error(
52878	      'unknown directions: <' + directions + '>: ' +
52879	      'must be specified as <start>:<end> ' +
52880	      'with start/end in { h,v,t,r,b,l }'
52881	    );
52882	  }
52883
52884	  // compute explicit directions, involving trbl dockings
52885	  // using a three segmented layouting algorithm
52886	  if (isExplicitDirections(directions)) {
52887	    var startSegment = getStartSegment(a, b, directions),
52888	        endSegment = getEndSegment(a, b, directions),
52889	        midSegment = getMidSegment(startSegment, endSegment);
52890
52891	    return [].concat(
52892	      startSegment.waypoints,
52893	      midSegment.waypoints,
52894	      endSegment.waypoints
52895	    );
52896	  }
52897
52898	  // handle simple [hv]:[hv] cases that can be easily computed
52899	  return getSimpleBendpoints(a, b, directions);
52900	}
52901
52902	/**
52903	 * Create a connection between the two points according
52904	 * to the manhattan layout (only horizontal and vertical) edges.
52905	 *
52906	 * @param {Point} a
52907	 * @param {Point} b
52908	 *
52909	 * @param {string} [directions='h:h'] specifies manhattan directions for each point as {adirection}:{bdirection}.
52910	                   A directionfor a point is either `h` (horizontal) or `v` (vertical)
52911	 *
52912	 * @return {Array<Point>}
52913	 */
52914	function connectPoints(a, b, directions) {
52915
52916	  var points = getBendpoints(a, b, directions);
52917
52918	  points.unshift(a);
52919	  points.push(b);
52920
52921	  return withoutRedundantPoints(points);
52922	}
52923
52924
52925	/**
52926	 * Connect two rectangles using a manhattan layouted connection.
52927	 *
52928	 * @param {Bounds} source source rectangle
52929	 * @param {Bounds} target target rectangle
52930	 * @param {Point} [start] source docking
52931	 * @param {Point} [end] target docking
52932	 *
52933	 * @param {Object} [hints]
52934	 * @param {string} [hints.preserveDocking=source] preserve docking on selected side
52935	 * @param {Array<string>} [hints.preferredLayouts]
52936	 * @param {Point|boolean} [hints.connectionStart] whether the start changed
52937	 * @param {Point|boolean} [hints.connectionEnd] whether the end changed
52938	 *
52939	 * @return {Array<Point>} connection points
52940	 */
52941	function connectRectangles(source, target, start, end, hints) {
52942
52943	  var preferredLayouts = hints && hints.preferredLayouts || [];
52944
52945	  var preferredLayout = without(preferredLayouts, 'straight')[0] || 'h:h';
52946
52947	  var threshold = ORIENTATION_THRESHOLD[preferredLayout] || 0;
52948
52949	  var orientation = getOrientation(source, target, threshold);
52950
52951	  var directions = getDirections(orientation, preferredLayout);
52952
52953	  start = start || getMid(source);
52954	  end = end || getMid(target);
52955
52956	  var directionSplit = directions.split(':');
52957
52958	  // compute actual docking points for start / end
52959	  // this ensures we properly layout only parts of the
52960	  // connection that lies in between the two rectangles
52961	  var startDocking = getDockingPoint(start, source, directionSplit[0], invertOrientation(orientation)),
52962	      endDocking = getDockingPoint(end, target, directionSplit[1], orientation);
52963
52964	  return connectPoints(startDocking, endDocking, directions);
52965	}
52966
52967
52968	/**
52969	 * Repair the connection between two rectangles, of which one has been updated.
52970	 *
52971	 * @param {Bounds} source
52972	 * @param {Bounds} target
52973	 * @param {Point} [start]
52974	 * @param {Point} [end]
52975	 * @param {Array<Point>} [waypoints]
52976	 * @param {Object} [hints]
52977	 * @param {Array<string>} [hints.preferredLayouts] list of preferred layouts
52978	 * @param {boolean} [hints.connectionStart]
52979	 * @param {boolean} [hints.connectionEnd]
52980	 *
52981	 * @return {Array<Point>} repaired waypoints
52982	 */
52983	function repairConnection(source, target, start, end, waypoints, hints) {
52984
52985	  if (isArray$2(start)) {
52986	    waypoints = start;
52987	    hints = end;
52988
52989	    start = getMid(source);
52990	    end = getMid(target);
52991	  }
52992
52993	  hints = assign({ preferredLayouts: [] }, hints);
52994	  waypoints = waypoints || [];
52995
52996	  var preferredLayouts = hints.preferredLayouts,
52997	      preferStraight = preferredLayouts.indexOf('straight') !== -1,
52998	      repairedWaypoints;
52999
53000	  // just layout non-existing or simple connections
53001	  // attempt to render straight lines, if required
53002
53003	  // attempt to layout a straight line
53004	  repairedWaypoints = preferStraight && tryLayoutStraight(source, target, start, end, hints);
53005
53006	  if (repairedWaypoints) {
53007	    return repairedWaypoints;
53008	  }
53009
53010	  // try to layout from end
53011	  repairedWaypoints = hints.connectionEnd && tryRepairConnectionEnd(target, source, end, waypoints);
53012
53013	  if (repairedWaypoints) {
53014	    return repairedWaypoints;
53015	  }
53016
53017	  // try to layout from start
53018	  repairedWaypoints = hints.connectionStart && tryRepairConnectionStart(source, target, start, waypoints);
53019
53020	  if (repairedWaypoints) {
53021	    return repairedWaypoints;
53022	  }
53023
53024	  // or whether nothing seems to have changed
53025	  if (!hints.connectionStart && !hints.connectionEnd && waypoints && waypoints.length) {
53026	    return waypoints;
53027	  }
53028
53029	  // simply reconnect if nothing else worked
53030	  return connectRectangles(source, target, start, end, hints);
53031	}
53032
53033
53034	function inRange(a, start, end) {
53035	  return a >= start && a <= end;
53036	}
53037
53038	function isInRange(axis, a, b) {
53039	  var size = {
53040	    x: 'width',
53041	    y: 'height'
53042	  };
53043
53044	  return inRange(a[axis], b[axis], b[axis] + b[size[axis]]);
53045	}
53046
53047	/**
53048	 * Layout a straight connection
53049	 *
53050	 * @param {Bounds} source
53051	 * @param {Bounds} target
53052	 * @param {Point} start
53053	 * @param {Point} end
53054	 * @param {Object} [hints]
53055	 *
53056	 * @return {Array<Point>|null} waypoints if straight layout worked
53057	 */
53058	function tryLayoutStraight(source, target, start, end, hints) {
53059	  var axis = {},
53060	      primaryAxis,
53061	      orientation;
53062
53063	  orientation = getOrientation(source, target);
53064
53065	  // only layout a straight connection if shapes are
53066	  // horizontally or vertically aligned
53067	  if (!/^(top|bottom|left|right)$/.test(orientation)) {
53068	    return null;
53069	  }
53070
53071	  if (/top|bottom/.test(orientation)) {
53072	    primaryAxis = 'x';
53073	  }
53074
53075	  if (/left|right/.test(orientation)) {
53076	    primaryAxis = 'y';
53077	  }
53078
53079	  if (hints.preserveDocking === 'target') {
53080
53081	    if (!isInRange(primaryAxis, end, source)) {
53082	      return null;
53083	    }
53084
53085	    axis[primaryAxis] = end[primaryAxis];
53086
53087	    return [
53088	      {
53089	        x: axis.x !== undefined ? axis.x : start.x,
53090	        y: axis.y !== undefined ? axis.y : start.y,
53091	        original: {
53092	          x: axis.x !== undefined ? axis.x : start.x,
53093	          y: axis.y !== undefined ? axis.y : start.y
53094	        }
53095	      },
53096	      {
53097	        x: end.x,
53098	        y: end.y
53099	      }
53100	    ];
53101
53102	  } else {
53103
53104	    if (!isInRange(primaryAxis, start, target)) {
53105	      return null;
53106	    }
53107
53108	    axis[primaryAxis] = start[primaryAxis];
53109
53110	    return [
53111	      {
53112	        x: start.x,
53113	        y: start.y
53114	      },
53115	      {
53116	        x: axis.x !== undefined ? axis.x : end.x,
53117	        y: axis.y !== undefined ? axis.y : end.y,
53118	        original: {
53119	          x: axis.x !== undefined ? axis.x : end.x,
53120	          y: axis.y !== undefined ? axis.y : end.y
53121	        }
53122	      }
53123	    ];
53124	  }
53125
53126	}
53127
53128	/**
53129	 * Repair a connection from start.
53130	 *
53131	 * @param {Bounds} moved
53132	 * @param {Bounds} other
53133	 * @param {Point} newDocking
53134	 * @param {Array<Point>} points originalPoints from moved to other
53135	 *
53136	 * @return {Array<Point>|null} the repaired points between the two rectangles
53137	 */
53138	function tryRepairConnectionStart(moved, other, newDocking, points) {
53139	  return _tryRepairConnectionSide(moved, other, newDocking, points);
53140	}
53141
53142	/**
53143	 * Repair a connection from end.
53144	 *
53145	 * @param {Bounds} moved
53146	 * @param {Bounds} other
53147	 * @param {Point} newDocking
53148	 * @param {Array<Point>} points originalPoints from moved to other
53149	 *
53150	 * @return {Array<Point>|null} the repaired points between the two rectangles
53151	 */
53152	function tryRepairConnectionEnd(moved, other, newDocking, points) {
53153	  var waypoints = points.slice().reverse();
53154
53155	  waypoints = _tryRepairConnectionSide(moved, other, newDocking, waypoints);
53156
53157	  return waypoints ? waypoints.reverse() : null;
53158	}
53159
53160	/**
53161	 * Repair a connection from one side that moved.
53162	 *
53163	 * @param {Bounds} moved
53164	 * @param {Bounds} other
53165	 * @param {Point} newDocking
53166	 * @param {Array<Point>} points originalPoints from moved to other
53167	 *
53168	 * @return {Array<Point>} the repaired points between the two rectangles
53169	 */
53170	function _tryRepairConnectionSide(moved, other, newDocking, points) {
53171
53172	  function needsRelayout(points) {
53173	    if (points.length < 3) {
53174	      return true;
53175	    }
53176
53177	    if (points.length > 4) {
53178	      return false;
53179	    }
53180
53181	    // relayout if two points overlap
53182	    // this is most likely due to
53183	    return !!find(points, function(p, idx) {
53184	      var q = points[idx - 1];
53185
53186	      return q && pointDistance(p, q) < 3;
53187	    });
53188	  }
53189
53190	  function repairBendpoint(candidate, oldPeer, newPeer) {
53191
53192	    var alignment = pointsAligned(oldPeer, candidate);
53193
53194	    switch (alignment) {
53195	    case 'v':
53196
53197	      // repair horizontal alignment
53198	      return { x: newPeer.x, y: candidate.y };
53199	    case 'h':
53200
53201	      // repair vertical alignment
53202	      return { x: candidate.x, y: newPeer.y };
53203	    }
53204
53205	    return { x: candidate.x, y: candidate. y };
53206	  }
53207
53208	  function removeOverlapping(points, a, b) {
53209	    var i;
53210
53211	    for (i = points.length - 2; i !== 0; i--) {
53212
53213	      // intersects (?) break, remove all bendpoints up to this one and relayout
53214	      if (pointInRect(points[i], a, INTERSECTION_THRESHOLD) ||
53215	          pointInRect(points[i], b, INTERSECTION_THRESHOLD)) {
53216
53217	        // return sliced old connection
53218	        return points.slice(i);
53219	      }
53220	    }
53221
53222	    return points;
53223	  }
53224
53225	  // (0) only repair what has layoutable bendpoints
53226
53227	  // (1) if only one bendpoint and on shape moved onto other shapes axis
53228	  //     (horizontally / vertically), relayout
53229
53230	  if (needsRelayout(points)) {
53231	    return null;
53232	  }
53233
53234	  var oldDocking = points[0],
53235	      newPoints = points.slice(),
53236	      slicedPoints;
53237
53238	  // (2) repair only last line segment and only if it was layouted before
53239
53240	  newPoints[0] = newDocking;
53241	  newPoints[1] = repairBendpoint(newPoints[1], oldDocking, newDocking);
53242
53243
53244	  // (3) if shape intersects with any bendpoint after repair,
53245	  //     remove all segments up to this bendpoint and repair from there
53246	  slicedPoints = removeOverlapping(newPoints, moved, other);
53247
53248	  if (slicedPoints !== newPoints) {
53249	    newPoints = _tryRepairConnectionSide(moved, other, newDocking, slicedPoints);
53250	  }
53251
53252	  // (4) do NOT repair if repaired bendpoints are aligned
53253	  if (newPoints && pointsAligned(newPoints)) {
53254	    return null;
53255	  }
53256
53257	  return newPoints;
53258	}
53259
53260
53261	/**
53262	 * Returns the manhattan directions connecting two rectangles
53263	 * with the given orientation.
53264	 *
53265	 * Will always return the default layout, if it is specific
53266	 * regarding sides already (trbl).
53267	 *
53268	 * @example
53269	 *
53270	 * getDirections('top'); // -> 'v:v'
53271	 * getDirections('intersect'); // -> 't:t'
53272	 *
53273	 * getDirections('top-right', 'v:h'); // -> 'v:h'
53274	 * getDirections('top-right', 'h:h'); // -> 'h:h'
53275	 *
53276	 *
53277	 * @param {string} orientation
53278	 * @param {string} defaultLayout
53279	 *
53280	 * @return {string}
53281	 */
53282	function getDirections(orientation, defaultLayout) {
53283
53284	  // don't override specific trbl directions
53285	  if (isExplicitDirections(defaultLayout)) {
53286	    return defaultLayout;
53287	  }
53288
53289	  switch (orientation) {
53290	  case 'intersect':
53291	    return 't:t';
53292
53293	  case 'top':
53294	  case 'bottom':
53295	    return 'v:v';
53296
53297	  case 'left':
53298	  case 'right':
53299	    return 'h:h';
53300
53301	  // 'top-left'
53302	  // 'top-right'
53303	  // 'bottom-left'
53304	  // 'bottom-right'
53305	  default:
53306	    return defaultLayout;
53307	  }
53308	}
53309
53310	function isValidDirections(directions) {
53311	  return directions && /^h|v|t|r|b|l:h|v|t|r|b|l$/.test(directions);
53312	}
53313
53314	function isExplicitDirections(directions) {
53315	  return directions && /t|r|b|l/.test(directions);
53316	}
53317
53318	function invertOrientation(orientation) {
53319	  return {
53320	    'top': 'bottom',
53321	    'bottom': 'top',
53322	    'left': 'right',
53323	    'right': 'left',
53324	    'top-left': 'bottom-right',
53325	    'bottom-right': 'top-left',
53326	    'top-right': 'bottom-left',
53327	    'bottom-left': 'top-right',
53328	  }[orientation];
53329	}
53330
53331	function getDockingPoint(point, rectangle, dockingDirection, targetOrientation) {
53332
53333	  // ensure we end up with a specific docking direction
53334	  // based on the targetOrientation, if <h|v> is being passed
53335
53336	  if (dockingDirection === 'h') {
53337	    dockingDirection = /left/.test(targetOrientation) ? 'l' : 'r';
53338	  }
53339
53340	  if (dockingDirection === 'v') {
53341	    dockingDirection = /top/.test(targetOrientation) ? 't' : 'b';
53342	  }
53343
53344	  if (dockingDirection === 't') {
53345	    return { original: point, x: point.x, y: rectangle.y };
53346	  }
53347
53348	  if (dockingDirection === 'r') {
53349	    return { original: point, x: rectangle.x + rectangle.width, y: point.y };
53350	  }
53351
53352	  if (dockingDirection === 'b') {
53353	    return { original: point, x: point.x, y: rectangle.y + rectangle.height };
53354	  }
53355
53356	  if (dockingDirection === 'l') {
53357	    return { original: point, x: rectangle.x, y: point.y };
53358	  }
53359
53360	  throw new Error('unexpected dockingDirection: <' + dockingDirection + '>');
53361	}
53362
53363
53364	/**
53365	 * Return list of waypoints with redundant ones filtered out.
53366	 *
53367	 * @example
53368	 *
53369	 * Original points:
53370	 *
53371	 *   [x] ----- [x] ------ [x]
53372	 *                         |
53373	 *                        [x] ----- [x] - [x]
53374	 *
53375	 * Filtered:
53376	 *
53377	 *   [x] ---------------- [x]
53378	 *                         |
53379	 *                        [x] ----------- [x]
53380	 *
53381	 * @param  {Array<Point>} waypoints
53382	 *
53383	 * @return {Array<Point>}
53384	 */
53385	function withoutRedundantPoints(waypoints) {
53386	  return waypoints.reduce(function(points, p, idx) {
53387
53388	    var previous = points[points.length - 1],
53389	        next = waypoints[idx + 1];
53390
53391	    if (!pointsOnLine(previous, next, p, 0)) {
53392	      points.push(p);
53393	    }
53394
53395	    return points;
53396	  }, []);
53397	}
53398
53399	var ATTACH_ORIENTATION_PADDING = -10,
53400	    BOUNDARY_TO_HOST_THRESHOLD$1 = 40;
53401
53402	var oppositeOrientationMapping = {
53403	  'top': 'bottom',
53404	  'top-right': 'bottom-left',
53405	  'top-left': 'bottom-right',
53406	  'right': 'left',
53407	  'bottom': 'top',
53408	  'bottom-right': 'top-left',
53409	  'bottom-left': 'top-right',
53410	  'left': 'right'
53411	};
53412
53413	var orientationDirectionMapping = {
53414	  top: 't',
53415	  right: 'r',
53416	  bottom: 'b',
53417	  left: 'l'
53418	};
53419
53420
53421	function BpmnLayouter() {}
53422
53423	inherits$1(BpmnLayouter, BaseLayouter);
53424
53425
53426	BpmnLayouter.prototype.layoutConnection = function(connection, hints) {
53427	  if (!hints) {
53428	    hints = {};
53429	  }
53430
53431	  var source = hints.source || connection.source,
53432	      target = hints.target || connection.target,
53433	      waypoints = hints.waypoints || connection.waypoints,
53434	      connectionStart = hints.connectionStart,
53435	      connectionEnd = hints.connectionEnd;
53436
53437	  var manhattanOptions,
53438	      updatedWaypoints;
53439
53440	  if (!connectionStart) {
53441	    connectionStart = getConnectionDocking(waypoints && waypoints[ 0 ], source);
53442	  }
53443
53444	  if (!connectionEnd) {
53445	    connectionEnd = getConnectionDocking(waypoints && waypoints[ waypoints.length - 1 ], target);
53446	  }
53447
53448	  // TODO(nikku): support vertical modeling
53449	  // and invert preferredLayouts accordingly
53450
53451	  if (is$1(connection, 'bpmn:Association') ||
53452	      is$1(connection, 'bpmn:DataAssociation')) {
53453
53454	    if (waypoints && !isCompensationAssociation(source, target)) {
53455	      return [].concat([ connectionStart ], waypoints.slice(1, -1), [ connectionEnd ]);
53456	    }
53457	  }
53458
53459	  if (is$1(connection, 'bpmn:MessageFlow')) {
53460	    manhattanOptions = getMessageFlowManhattanOptions(source, target);
53461	  } else if (is$1(connection, 'bpmn:SequenceFlow') || isCompensationAssociation(source, target)) {
53462
53463	    // layout all connection between flow elements h:h, except for
53464	    // (1) outgoing of boundary events -> layout based on attach orientation and target orientation
53465	    // (2) incoming/outgoing of gateways -> v:h for outgoing, h:v for incoming
53466	    // (3) loops
53467	    if (source === target) {
53468	      manhattanOptions = {
53469	        preferredLayouts: getLoopPreferredLayout(source, connection)
53470	      };
53471	    } else if (is$1(source, 'bpmn:BoundaryEvent')) {
53472	      manhattanOptions = {
53473	        preferredLayouts: getBoundaryEventPreferredLayouts(source, target, connectionEnd)
53474	      };
53475	    } else if (isExpandedSubProcess(source) || isExpandedSubProcess(target)) {
53476	      manhattanOptions = getSubProcessManhattanOptions(source);
53477	    } else if (is$1(source, 'bpmn:Gateway')) {
53478	      manhattanOptions = {
53479	        preferredLayouts: [ 'v:h' ]
53480	      };
53481	    } else if (is$1(target, 'bpmn:Gateway')) {
53482	      manhattanOptions = {
53483	        preferredLayouts: [ 'h:v' ]
53484	      };
53485	    } else {
53486	      manhattanOptions = {
53487	        preferredLayouts: [ 'h:h' ]
53488	      };
53489	    }
53490	  }
53491
53492	  if (manhattanOptions) {
53493	    manhattanOptions = assign(manhattanOptions, hints);
53494
53495	    updatedWaypoints = withoutRedundantPoints(repairConnection(
53496	      source,
53497	      target,
53498	      connectionStart,
53499	      connectionEnd,
53500	      waypoints,
53501	      manhattanOptions
53502	    ));
53503	  }
53504
53505	  return updatedWaypoints || [ connectionStart, connectionEnd ];
53506	};
53507
53508
53509	// helpers //////////
53510
53511	function getAttachOrientation(attachedElement) {
53512	  var hostElement = attachedElement.host;
53513
53514	  return getOrientation(getMid(attachedElement), hostElement, ATTACH_ORIENTATION_PADDING);
53515	}
53516
53517	function getMessageFlowManhattanOptions(source, target) {
53518	  return {
53519	    preferredLayouts: [ 'straight', 'v:v' ],
53520	    preserveDocking: getMessageFlowPreserveDocking(source, target)
53521	  };
53522	}
53523
53524	function getMessageFlowPreserveDocking(source, target) {
53525
53526	  // (1) docking element connected to participant has precedence
53527	  if (is$1(target, 'bpmn:Participant')) {
53528	    return 'source';
53529	  }
53530
53531	  if (is$1(source, 'bpmn:Participant')) {
53532	    return 'target';
53533	  }
53534
53535	  // (2) docking element connected to expanded sub-process has precedence
53536	  if (isExpandedSubProcess(target)) {
53537	    return 'source';
53538	  }
53539
53540	  if (isExpandedSubProcess(source)) {
53541	    return 'target';
53542	  }
53543
53544	  // (3) docking event has precedence
53545	  if (is$1(target, 'bpmn:Event')) {
53546	    return 'target';
53547	  }
53548
53549	  if (is$1(source, 'bpmn:Event')) {
53550	    return 'source';
53551	  }
53552
53553	  return null;
53554	}
53555
53556	function getSubProcessManhattanOptions(source) {
53557	  return {
53558	    preferredLayouts: [ 'straight', 'h:h' ],
53559	    preserveDocking: getSubProcessPreserveDocking(source)
53560	  };
53561	}
53562
53563	function getSubProcessPreserveDocking(source) {
53564	  return isExpandedSubProcess(source) ? 'target' : 'source';
53565	}
53566
53567	function getConnectionDocking(point, shape) {
53568	  return point ? (point.original || point) : getMid(shape);
53569	}
53570
53571	function isCompensationAssociation(source, target) {
53572	  return is$1(target, 'bpmn:Activity') &&
53573	    is$1(source, 'bpmn:BoundaryEvent') &&
53574	    target.businessObject.isForCompensation;
53575	}
53576
53577	function isExpandedSubProcess(element) {
53578	  return is$1(element, 'bpmn:SubProcess') && isExpanded(element);
53579	}
53580
53581	function isSame(a, b) {
53582	  return a === b;
53583	}
53584
53585	function isAnyOrientation(orientation, orientations) {
53586	  return orientations.indexOf(orientation) !== -1;
53587	}
53588
53589	function getHorizontalOrientation(orientation) {
53590	  var matches = /right|left/.exec(orientation);
53591
53592	  return matches && matches[0];
53593	}
53594
53595	function getVerticalOrientation(orientation) {
53596	  var matches = /top|bottom/.exec(orientation);
53597
53598	  return matches && matches[0];
53599	}
53600
53601	function isOppositeOrientation(a, b) {
53602	  return oppositeOrientationMapping[a] === b;
53603	}
53604
53605	function isOppositeHorizontalOrientation(a, b) {
53606	  var horizontalOrientation = getHorizontalOrientation(a);
53607
53608	  var oppositeHorizontalOrientation = oppositeOrientationMapping[horizontalOrientation];
53609
53610	  return b.indexOf(oppositeHorizontalOrientation) !== -1;
53611	}
53612
53613	function isOppositeVerticalOrientation(a, b) {
53614	  var verticalOrientation = getVerticalOrientation(a);
53615
53616	  var oppositeVerticalOrientation = oppositeOrientationMapping[verticalOrientation];
53617
53618	  return b.indexOf(oppositeVerticalOrientation) !== -1;
53619	}
53620
53621	function isHorizontalOrientation(orientation) {
53622	  return orientation === 'right' || orientation === 'left';
53623	}
53624
53625	function getLoopPreferredLayout(source, connection) {
53626	  var waypoints = connection.waypoints;
53627
53628	  var orientation = waypoints && waypoints.length && getOrientation(waypoints[0], source);
53629
53630	  if (orientation === 'top') {
53631	    return [ 't:r' ];
53632	  } else if (orientation === 'right') {
53633	    return [ 'r:b' ];
53634	  } else if (orientation === 'left') {
53635	    return [ 'l:t' ];
53636	  }
53637
53638	  return [ 'b:l' ];
53639	}
53640
53641	function getBoundaryEventPreferredLayouts(source, target, end) {
53642	  var sourceMid = getMid(source),
53643	      targetMid = getMid(target),
53644	      attachOrientation = getAttachOrientation(source),
53645	      sourceLayout,
53646	      targetLayout;
53647
53648	  var isLoop = isSame(source.host, target);
53649
53650	  var attachedToSide = isAnyOrientation(attachOrientation, [ 'top', 'right', 'bottom', 'left' ]);
53651
53652	  var targetOrientation = getOrientation(targetMid, sourceMid, {
53653	    x: source.width / 2 + target.width / 2,
53654	    y: source.height / 2 + target.height / 2
53655	  });
53656
53657	  if (isLoop) {
53658	    return getBoundaryEventLoopLayout(attachOrientation, attachedToSide, source, target, end);
53659	  }
53660
53661	  // source layout
53662	  sourceLayout = getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide);
53663
53664	  // target layout
53665	  targetLayout = getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide);
53666
53667	  return [ sourceLayout + ':' + targetLayout ];
53668	}
53669
53670	function getBoundaryEventLoopLayout(attachOrientation, attachedToSide, source, target, end) {
53671	  var orientation = attachedToSide ? attachOrientation : getVerticalOrientation(attachOrientation),
53672	      sourceLayout = orientationDirectionMapping[ orientation ],
53673	      targetLayout;
53674
53675	  if (attachedToSide) {
53676	    if (isHorizontalOrientation(attachOrientation)) {
53677	      targetLayout = shouldConnectToSameSide('y', source, target, end) ? 'h' : 'b';
53678	    } else {
53679	      targetLayout = shouldConnectToSameSide('x', source, target, end) ? 'v' : 'l';
53680	    }
53681	  } else {
53682	    targetLayout = 'v';
53683	  }
53684
53685	  return [ sourceLayout + ':' + targetLayout ];
53686	}
53687
53688	function shouldConnectToSameSide(axis, source, target, end) {
53689	  var threshold = BOUNDARY_TO_HOST_THRESHOLD$1;
53690
53691	  return !(
53692	    areCloseOnAxis(axis, end, target, threshold) ||
53693	    areCloseOnAxis(axis, end, {
53694	      x: target.x + target.width,
53695	      y: target.y + target.height
53696	    }, threshold) ||
53697	    areCloseOnAxis(axis, end, getMid(source), threshold)
53698	  );
53699	}
53700
53701	function areCloseOnAxis(axis, a, b, threshold) {
53702	  return Math.abs(a[ axis ] - b[ axis ]) < threshold;
53703	}
53704
53705	function getBoundaryEventSourceLayout(attachOrientation, targetOrientation, attachedToSide) {
53706
53707	  // attached to either top, right, bottom or left side
53708	  if (attachedToSide) {
53709	    return orientationDirectionMapping[ attachOrientation ];
53710	  }
53711
53712	  // attached to either top-right, top-left, bottom-right or bottom-left corner
53713
53714	  // same vertical or opposite horizontal orientation
53715	  if (isSame(
53716	    getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)
53717	  ) || isOppositeOrientation(
53718	    getHorizontalOrientation(attachOrientation), getHorizontalOrientation(targetOrientation)
53719	  )) {
53720	    return orientationDirectionMapping[ getVerticalOrientation(attachOrientation) ];
53721	  }
53722
53723	  // fallback
53724	  return orientationDirectionMapping[ getHorizontalOrientation(attachOrientation) ];
53725	}
53726
53727	function getBoundaryEventTargetLayout(attachOrientation, targetOrientation, attachedToSide) {
53728
53729	  // attached to either top, right, bottom or left side
53730	  if (attachedToSide) {
53731	    if (isHorizontalOrientation(attachOrientation)) {
53732
53733	      // orientation is right or left
53734
53735	      // opposite horizontal orientation or same orientation
53736	      if (
53737	        isOppositeHorizontalOrientation(attachOrientation, targetOrientation) ||
53738	        isSame(attachOrientation, targetOrientation)
53739	      ) {
53740	        return 'h';
53741	      }
53742
53743	      // fallback
53744	      return 'v';
53745	    } else {
53746
53747	      // orientation is top or bottom
53748
53749	      // opposite vertical orientation or same orientation
53750	      if (
53751	        isOppositeVerticalOrientation(attachOrientation, targetOrientation) ||
53752	        isSame(attachOrientation, targetOrientation)
53753	      ) {
53754	        return 'v';
53755	      }
53756
53757	      // fallback
53758	      return 'h';
53759	    }
53760	  }
53761
53762	  // attached to either top-right, top-left, bottom-right or bottom-left corner
53763
53764	  // orientation is right, left
53765	  // or same vertical orientation but also right or left
53766	  if (isHorizontalOrientation(targetOrientation) ||
53767	    (isSame(getVerticalOrientation(attachOrientation), getVerticalOrientation(targetOrientation)) &&
53768	      getHorizontalOrientation(targetOrientation))) {
53769	    return 'h';
53770	  } else {
53771	    return 'v';
53772	  }
53773	}
53774
53775	function dockingToPoint(docking) {
53776
53777	  // use the dockings actual point and
53778	  // retain the original docking
53779	  return assign({ original: docking.point.original || docking.point }, docking.actual);
53780	}
53781
53782
53783	/**
53784	 * A {@link ConnectionDocking} that crops connection waypoints based on
53785	 * the path(s) of the connection source and target.
53786	 *
53787	 * @param {djs.core.ElementRegistry} elementRegistry
53788	 */
53789	function CroppingConnectionDocking(elementRegistry, graphicsFactory) {
53790	  this._elementRegistry = elementRegistry;
53791	  this._graphicsFactory = graphicsFactory;
53792	}
53793
53794	CroppingConnectionDocking.$inject = [ 'elementRegistry', 'graphicsFactory' ];
53795
53796
53797	/**
53798	 * @inheritDoc ConnectionDocking#getCroppedWaypoints
53799	 */
53800	CroppingConnectionDocking.prototype.getCroppedWaypoints = function(connection, source, target) {
53801
53802	  source = source || connection.source;
53803	  target = target || connection.target;
53804
53805	  var sourceDocking = this.getDockingPoint(connection, source, true),
53806	      targetDocking = this.getDockingPoint(connection, target);
53807
53808	  var croppedWaypoints = connection.waypoints.slice(sourceDocking.idx + 1, targetDocking.idx);
53809
53810	  croppedWaypoints.unshift(dockingToPoint(sourceDocking));
53811	  croppedWaypoints.push(dockingToPoint(targetDocking));
53812
53813	  return croppedWaypoints;
53814	};
53815
53816	/**
53817	 * Return the connection docking point on the specified shape
53818	 *
53819	 * @inheritDoc ConnectionDocking#getDockingPoint
53820	 */
53821	CroppingConnectionDocking.prototype.getDockingPoint = function(connection, shape, dockStart) {
53822
53823	  var waypoints = connection.waypoints,
53824	      dockingIdx,
53825	      dockingPoint,
53826	      croppedPoint;
53827
53828	  dockingIdx = dockStart ? 0 : waypoints.length - 1;
53829	  dockingPoint = waypoints[dockingIdx];
53830
53831	  croppedPoint = this._getIntersection(shape, connection, dockStart);
53832
53833	  return {
53834	    point: dockingPoint,
53835	    actual: croppedPoint || dockingPoint,
53836	    idx: dockingIdx
53837	  };
53838	};
53839
53840
53841	// helpers //////////////////////
53842
53843	CroppingConnectionDocking.prototype._getIntersection = function(shape, connection, takeFirst) {
53844
53845	  var shapePath = this._getShapePath(shape),
53846	      connectionPath = this._getConnectionPath(connection);
53847
53848	  return getElementLineIntersection(shapePath, connectionPath, takeFirst);
53849	};
53850
53851	CroppingConnectionDocking.prototype._getConnectionPath = function(connection) {
53852	  return this._graphicsFactory.getConnectionPath(connection);
53853	};
53854
53855	CroppingConnectionDocking.prototype._getShapePath = function(shape) {
53856	  return this._graphicsFactory.getShapePath(shape);
53857	};
53858
53859	CroppingConnectionDocking.prototype._getGfx = function(element) {
53860	  return this._elementRegistry.getGraphics(element);
53861	};
53862
53863	var ModelingModule = {
53864	  __init__: [
53865	    'modeling',
53866	    'bpmnUpdater'
53867	  ],
53868	  __depends__: [
53869	    BehaviorModule,
53870	    RulesModule,
53871	    DiOrderingModule,
53872	    OrderingModule,
53873	    ReplaceModule,
53874	    CommandModule,
53875	    TooltipsModule,
53876	    LabelSupportModule,
53877	    AttachSupportModule,
53878	    SelectionModule,
53879	    ChangeSupportModule,
53880	    SpaceToolModule
53881	  ],
53882	  bpmnFactory: [ 'type', BpmnFactory ],
53883	  bpmnUpdater: [ 'type', BpmnUpdater ],
53884	  elementFactory: [ 'type', ElementFactory ],
53885	  modeling: [ 'type', Modeling ],
53886	  layouter: [ 'type', BpmnLayouter ],
53887	  connectionDocking: [ 'type', CroppingConnectionDocking ]
53888	};
53889
53890	var LOW_PRIORITY$2 = 500,
53891	    MEDIUM_PRIORITY = 1250,
53892	    HIGH_PRIORITY$2 = 1500;
53893
53894	var round = Math.round;
53895
53896	function mid(element) {
53897	  return {
53898	    x: element.x + round(element.width / 2),
53899	    y: element.y + round(element.height / 2)
53900	  };
53901	}
53902
53903	/**
53904	 * A plugin that makes shapes draggable / droppable.
53905	 *
53906	 * @param {EventBus} eventBus
53907	 * @param {Dragging} dragging
53908	 * @param {Modeling} modeling
53909	 * @param {Selection} selection
53910	 * @param {Rules} rules
53911	 */
53912	function MoveEvents(
53913	    eventBus, dragging, modeling,
53914	    selection, rules) {
53915
53916	  // rules
53917
53918	  function canMove(shapes, delta, position, target) {
53919
53920	    return rules.allowed('elements.move', {
53921	      shapes: shapes,
53922	      delta: delta,
53923	      position: position,
53924	      target: target
53925	    });
53926	  }
53927
53928
53929	  // move events
53930
53931	  // assign a high priority to this handler to setup the environment
53932	  // others may hook up later, e.g. at default priority and modify
53933	  // the move environment.
53934	  //
53935	  // This sets up the context with
53936	  //
53937	  // * shape: the primary shape being moved
53938	  // * shapes: a list of shapes to be moved
53939	  // * validatedShapes: a list of shapes that are being checked
53940	  //                    against the rules before and during move
53941	  //
53942	  eventBus.on('shape.move.start', HIGH_PRIORITY$2, function(event) {
53943
53944	    var context = event.context,
53945	        shape = event.shape,
53946	        shapes = selection.get().slice();
53947
53948	    // move only single shape if the dragged element
53949	    // is not part of the current selection
53950	    if (shapes.indexOf(shape) === -1) {
53951	      shapes = [ shape ];
53952	    }
53953
53954	    // ensure we remove nested elements in the collection
53955	    // and add attachers for a proper dragger
53956	    shapes = removeNested(shapes);
53957
53958	    // attach shapes to drag context
53959	    assign(context, {
53960	      shapes: shapes,
53961	      validatedShapes: shapes,
53962	      shape: shape
53963	    });
53964	  });
53965
53966
53967	  // assign a high priority to this handler to setup the environment
53968	  // others may hook up later, e.g. at default priority and modify
53969	  // the move environment
53970	  //
53971	  eventBus.on('shape.move.start', MEDIUM_PRIORITY, function(event) {
53972
53973	    var context = event.context,
53974	        validatedShapes = context.validatedShapes,
53975	        canExecute;
53976
53977	    canExecute = context.canExecute = canMove(validatedShapes);
53978
53979	    // check if we can move the elements
53980	    if (!canExecute) {
53981	      return false;
53982	    }
53983	  });
53984
53985	  // assign a low priority to this handler
53986	  // to let others modify the move event before we update
53987	  // the context
53988	  //
53989	  eventBus.on('shape.move.move', LOW_PRIORITY$2, function(event) {
53990
53991	    var context = event.context,
53992	        validatedShapes = context.validatedShapes,
53993	        hover = event.hover,
53994	        delta = { x: event.dx, y: event.dy },
53995	        position = { x: event.x, y: event.y },
53996	        canExecute;
53997
53998	    // check if we can move the elements
53999	    canExecute = canMove(validatedShapes, delta, position, hover);
54000
54001	    context.delta = delta;
54002	    context.canExecute = canExecute;
54003
54004	    // simply ignore move over
54005	    if (canExecute === null) {
54006	      context.target = null;
54007
54008	      return;
54009	    }
54010
54011	    context.target = hover;
54012	  });
54013
54014	  eventBus.on('shape.move.end', function(event) {
54015
54016	    var context = event.context;
54017
54018	    var delta = context.delta,
54019	        canExecute = context.canExecute,
54020	        isAttach = canExecute === 'attach',
54021	        shapes = context.shapes;
54022
54023	    if (canExecute === false) {
54024	      return false;
54025	    }
54026
54027	    // ensure we have actual pixel values deltas
54028	    // (important when zoom level was > 1 during move)
54029	    delta.x = round(delta.x);
54030	    delta.y = round(delta.y);
54031
54032	    if (delta.x === 0 && delta.y === 0) {
54033
54034	      // didn't move
54035	      return;
54036	    }
54037
54038	    modeling.moveElements(shapes, delta, context.target, {
54039	      primaryShape: context.shape,
54040	      attach: isAttach
54041	    });
54042	  });
54043
54044
54045	  // move activation
54046
54047	  eventBus.on('element.mousedown', function(event) {
54048
54049	    if (!isPrimaryButton(event)) {
54050	      return;
54051	    }
54052
54053	    var originalEvent = getOriginal$1(event);
54054
54055	    if (!originalEvent) {
54056	      throw new Error('must supply DOM mousedown event');
54057	    }
54058
54059	    return start(originalEvent, event.element);
54060	  });
54061
54062	  /**
54063	   * Start move.
54064	   *
54065	   * @param {MouseEvent} event
54066	   * @param {djs.model.Shape} shape
54067	   * @param {boolean} [activate]
54068	   * @param {Object} [context]
54069	   */
54070	  function start(event, element, activate, context) {
54071	    if (isObject(activate)) {
54072	      context = activate;
54073	      activate = false;
54074	    }
54075
54076	    // do not move connections or the root element
54077	    if (element.waypoints || !element.parent) {
54078	      return;
54079	    }
54080
54081	    var referencePoint = mid(element);
54082
54083	    dragging.init(event, referencePoint, 'shape.move', {
54084	      cursor: 'grabbing',
54085	      autoActivate: activate,
54086	      data: {
54087	        shape: element,
54088	        context: context || {}
54089	      }
54090	    });
54091
54092	    // we've handled the event
54093	    return true;
54094	  }
54095
54096	  // API
54097
54098	  this.start = start;
54099	}
54100
54101	MoveEvents.$inject = [
54102	  'eventBus',
54103	  'dragging',
54104	  'modeling',
54105	  'selection',
54106	  'rules'
54107	];
54108
54109
54110	/**
54111	 * Return a filtered list of elements that do not contain
54112	 * those nested into others.
54113	 *
54114	 * @param  {Array<djs.model.Base>} elements
54115	 *
54116	 * @return {Array<djs.model.Base>} filtered
54117	 */
54118	function removeNested(elements) {
54119
54120	  var ids = groupBy(elements, 'id');
54121
54122	  return filter(elements, function(element) {
54123	    while ((element = element.parent)) {
54124
54125	      // parent in selection
54126	      if (ids[element.id]) {
54127	        return false;
54128	      }
54129	    }
54130
54131	    return true;
54132	  });
54133	}
54134
54135	var LOW_PRIORITY$1 = 499;
54136
54137	var MARKER_DRAGGING = 'djs-dragging',
54138	    MARKER_OK$1 = 'drop-ok',
54139	    MARKER_NOT_OK$1 = 'drop-not-ok',
54140	    MARKER_NEW_PARENT = 'new-parent',
54141	    MARKER_ATTACH = 'attach-ok';
54142
54143
54144	/**
54145	 * Provides previews for moving shapes when moving.
54146	 *
54147	 * @param {EventBus} eventBus
54148	 * @param {ElementRegistry} elementRegistry
54149	 * @param {Canvas} canvas
54150	 * @param {Styles} styles
54151	 */
54152	function MovePreview(
54153	    eventBus, canvas, styles, previewSupport) {
54154
54155	  function getVisualDragShapes(shapes) {
54156	    var elements = getAllDraggedElements(shapes);
54157
54158	    var filteredElements = removeEdges(elements);
54159
54160	    return filteredElements;
54161	  }
54162
54163	  function getAllDraggedElements(shapes) {
54164	    var allShapes = selfAndAllChildren(shapes, true);
54165
54166	    var allConnections = map$1(allShapes, function(shape) {
54167	      return (shape.incoming || []).concat(shape.outgoing || []);
54168	    });
54169
54170	    return flatten(allShapes.concat(allConnections));
54171	  }
54172
54173	  /**
54174	   * Sets drop marker on an element.
54175	   */
54176	  function setMarker(element, marker) {
54177
54178	    [ MARKER_ATTACH, MARKER_OK$1, MARKER_NOT_OK$1, MARKER_NEW_PARENT ].forEach(function(m) {
54179
54180	      if (m === marker) {
54181	        canvas.addMarker(element, m);
54182	      } else {
54183	        canvas.removeMarker(element, m);
54184	      }
54185	    });
54186	  }
54187
54188	  /**
54189	   * Make an element draggable.
54190	   *
54191	   * @param {Object} context
54192	   * @param {djs.model.Base} element
54193	   * @param {boolean} addMarker
54194	   */
54195	  function makeDraggable(context, element, addMarker) {
54196
54197	    previewSupport.addDragger(element, context.dragGroup);
54198
54199	    if (addMarker) {
54200	      canvas.addMarker(element, MARKER_DRAGGING);
54201	    }
54202
54203	    if (context.allDraggedElements) {
54204	      context.allDraggedElements.push(element);
54205	    } else {
54206	      context.allDraggedElements = [ element ];
54207	    }
54208	  }
54209
54210	  // assign a low priority to this handler
54211	  // to let others modify the move context before
54212	  // we draw things
54213	  eventBus.on('shape.move.start', LOW_PRIORITY$1, function(event) {
54214	    var context = event.context,
54215	        dragShapes = context.shapes,
54216	        allDraggedElements = context.allDraggedElements;
54217
54218	    var visuallyDraggedShapes = getVisualDragShapes(dragShapes);
54219
54220	    if (!context.dragGroup) {
54221	      var dragGroup = create$1('g');
54222
54223	      attr(dragGroup, styles.cls('djs-drag-group', [ 'no-events' ]));
54224
54225	      var activeLayer = canvas.getActiveLayer();
54226
54227	      append(activeLayer, dragGroup);
54228
54229	      context.dragGroup = dragGroup;
54230	    }
54231
54232	    // add previews
54233	    visuallyDraggedShapes.forEach(function(shape) {
54234	      previewSupport.addDragger(shape, context.dragGroup);
54235	    });
54236
54237	    // cache all dragged elements / gfx
54238	    // so that we can quickly undo their state changes later
54239	    if (!allDraggedElements) {
54240	      allDraggedElements = getAllDraggedElements(dragShapes);
54241	    } else {
54242	      allDraggedElements = flatten([
54243	        allDraggedElements,
54244	        getAllDraggedElements(dragShapes)
54245	      ]);
54246	    }
54247
54248	    // add dragging marker
54249	    forEach(allDraggedElements, function(e) {
54250	      canvas.addMarker(e, MARKER_DRAGGING);
54251	    });
54252
54253	    context.allDraggedElements = allDraggedElements;
54254
54255	    // determine, if any of the dragged elements have different parents
54256	    context.differentParents = haveDifferentParents(dragShapes);
54257	  });
54258
54259	  // update previews
54260	  eventBus.on('shape.move.move', LOW_PRIORITY$1, function(event) {
54261
54262	    var context = event.context,
54263	        dragGroup = context.dragGroup,
54264	        target = context.target,
54265	        parent = context.shape.parent,
54266	        canExecute = context.canExecute;
54267
54268	    if (target) {
54269	      if (canExecute === 'attach') {
54270	        setMarker(target, MARKER_ATTACH);
54271	      } else if (context.canExecute && target && target.id !== parent.id) {
54272	        setMarker(target, MARKER_NEW_PARENT);
54273	      } else {
54274	        setMarker(target, context.canExecute ? MARKER_OK$1 : MARKER_NOT_OK$1);
54275	      }
54276	    }
54277
54278	    translate$2(dragGroup, event.dx, event.dy);
54279	  });
54280
54281	  eventBus.on([ 'shape.move.out', 'shape.move.cleanup' ], function(event) {
54282	    var context = event.context,
54283	        target = context.target;
54284
54285	    if (target) {
54286	      setMarker(target, null);
54287	    }
54288	  });
54289
54290	  // remove previews
54291	  eventBus.on('shape.move.cleanup', function(event) {
54292
54293	    var context = event.context,
54294	        allDraggedElements = context.allDraggedElements,
54295	        dragGroup = context.dragGroup;
54296
54297
54298	    // remove dragging marker
54299	    forEach(allDraggedElements, function(e) {
54300	      canvas.removeMarker(e, MARKER_DRAGGING);
54301	    });
54302
54303	    if (dragGroup) {
54304	      remove$1(dragGroup);
54305	    }
54306	  });
54307
54308
54309	  // API //////////////////////
54310
54311	  /**
54312	   * Make an element draggable.
54313	   *
54314	   * @param {Object} context
54315	   * @param {djs.model.Base} element
54316	   * @param {boolean} addMarker
54317	   */
54318	  this.makeDraggable = makeDraggable;
54319	}
54320
54321	MovePreview.$inject = [
54322	  'eventBus',
54323	  'canvas',
54324	  'styles',
54325	  'previewSupport'
54326	];
54327
54328
54329	// helpers //////////////////////
54330
54331	/**
54332	 * returns elements minus all connections
54333	 * where source or target is not elements
54334	 */
54335	function removeEdges(elements) {
54336
54337	  var filteredElements = filter(elements, function(element) {
54338
54339	    if (!isConnection$2(element)) {
54340	      return true;
54341	    } else {
54342
54343	      return (
54344	        find(elements, matchPattern({ id: element.source.id })) &&
54345	        find(elements, matchPattern({ id: element.target.id }))
54346	      );
54347	    }
54348	  });
54349
54350	  return filteredElements;
54351	}
54352
54353	function haveDifferentParents(elements) {
54354	  return size(groupBy(elements, function(e) { return e.parent && e.parent.id; })) !== 1;
54355	}
54356
54357	/**
54358	 * Checks if an element is a connection.
54359	 */
54360	function isConnection$2(element) {
54361	  return element.waypoints;
54362	}
54363
54364	var MoveModule = {
54365	  __depends__: [
54366	    InteractionEventsModule$1,
54367	    SelectionModule,
54368	    OutlineModule,
54369	    RulesModule$1,
54370	    DraggingModule,
54371	    PreviewSupportModule
54372	  ],
54373	  __init__: [
54374	    'move',
54375	    'movePreview'
54376	  ],
54377	  move: [ 'type', MoveEvents ],
54378	  movePreview: [ 'type', MovePreview ]
54379	};
54380
54381	var TOGGLE_SELECTOR = '.djs-palette-toggle',
54382	    ENTRY_SELECTOR = '.entry',
54383	    ELEMENT_SELECTOR = TOGGLE_SELECTOR + ', ' + ENTRY_SELECTOR;
54384
54385	var PALETTE_OPEN_CLS = 'open',
54386	    PALETTE_TWO_COLUMN_CLS = 'two-column';
54387
54388	var DEFAULT_PRIORITY = 1000;
54389
54390
54391	/**
54392	 * A palette containing modeling elements.
54393	 */
54394	function Palette(eventBus, canvas) {
54395
54396	  this._eventBus = eventBus;
54397	  this._canvas = canvas;
54398
54399	  var self = this;
54400
54401	  eventBus.on('tool-manager.update', function(event) {
54402	    var tool = event.tool;
54403
54404	    self.updateToolHighlight(tool);
54405	  });
54406
54407	  eventBus.on('i18n.changed', function() {
54408	    self._update();
54409	  });
54410
54411	  eventBus.on('diagram.init', function() {
54412
54413	    self._diagramInitialized = true;
54414
54415	    self._rebuild();
54416	  });
54417	}
54418
54419	Palette.$inject = [ 'eventBus', 'canvas' ];
54420
54421
54422	/**
54423	 * Register a provider with the palette
54424	 *
54425	 * @param  {number} [priority=1000]
54426	 * @param  {PaletteProvider} provider
54427	 *
54428	 * @example
54429	 * const paletteProvider = {
54430	 *   getPaletteEntries: function() {
54431	 *     return function(entries) {
54432	 *       return {
54433	 *         ...entries,
54434	 *         'entry-1': {
54435	 *           label: 'My Entry',
54436	 *           action: function() { alert("I have been clicked!"); }
54437	 *         }
54438	 *       };
54439	 *     }
54440	 *   }
54441	 * };
54442	 *
54443	 * palette.registerProvider(800, paletteProvider);
54444	 */
54445	Palette.prototype.registerProvider = function(priority, provider) {
54446	  if (!provider) {
54447	    provider = priority;
54448	    priority = DEFAULT_PRIORITY;
54449	  }
54450
54451	  this._eventBus.on('palette.getProviders', priority, function(event) {
54452	    event.providers.push(provider);
54453	  });
54454
54455	  this._rebuild();
54456	};
54457
54458
54459	/**
54460	 * Returns the palette entries
54461	 *
54462	 * @return {Object<string, PaletteEntryDescriptor>} map of entries
54463	 */
54464	Palette.prototype.getEntries = function() {
54465	  var providers = this._getProviders();
54466
54467	  return providers.reduce(addPaletteEntries, {});
54468	};
54469
54470	Palette.prototype._rebuild = function() {
54471
54472	  if (!this._diagramInitialized) {
54473	    return;
54474	  }
54475
54476	  var providers = this._getProviders();
54477
54478	  if (!providers.length) {
54479	    return;
54480	  }
54481
54482	  if (!this._container) {
54483	    this._init();
54484	  }
54485
54486	  this._update();
54487	};
54488
54489	/**
54490	 * Initialize
54491	 */
54492	Palette.prototype._init = function() {
54493
54494	  var self = this;
54495
54496	  var eventBus = this._eventBus;
54497
54498	  var parentContainer = this._getParentContainer();
54499
54500	  var container = this._container = domify(Palette.HTML_MARKUP);
54501
54502	  parentContainer.appendChild(container);
54503
54504	  delegate.bind(container, ELEMENT_SELECTOR, 'click', function(event) {
54505
54506	    var target = event.delegateTarget;
54507
54508	    if (matchesSelector(target, TOGGLE_SELECTOR)) {
54509	      return self.toggle();
54510	    }
54511
54512	    self.trigger('click', event);
54513	  });
54514
54515	  // prevent drag propagation
54516	  componentEvent.bind(container, 'mousedown', function(event) {
54517	    event.stopPropagation();
54518	  });
54519
54520	  // prevent drag propagation
54521	  delegate.bind(container, ENTRY_SELECTOR, 'dragstart', function(event) {
54522	    self.trigger('dragstart', event);
54523	  });
54524
54525	  eventBus.on('canvas.resized', this._layoutChanged, this);
54526
54527	  eventBus.fire('palette.create', {
54528	    container: container
54529	  });
54530	};
54531
54532	Palette.prototype._getProviders = function(id) {
54533
54534	  var event = this._eventBus.createEvent({
54535	    type: 'palette.getProviders',
54536	    providers: []
54537	  });
54538
54539	  this._eventBus.fire(event);
54540
54541	  return event.providers;
54542	};
54543
54544	/**
54545	 * Update palette state.
54546	 *
54547	 * @param  {Object} [state] { open, twoColumn }
54548	 */
54549	Palette.prototype._toggleState = function(state) {
54550
54551	  state = state || {};
54552
54553	  var parent = this._getParentContainer(),
54554	      container = this._container;
54555
54556	  var eventBus = this._eventBus;
54557
54558	  var twoColumn;
54559
54560	  var cls = classes$1(container);
54561
54562	  if ('twoColumn' in state) {
54563	    twoColumn = state.twoColumn;
54564	  } else {
54565	    twoColumn = this._needsCollapse(parent.clientHeight, this._entries || {});
54566	  }
54567
54568	  // always update two column
54569	  cls.toggle(PALETTE_TWO_COLUMN_CLS, twoColumn);
54570
54571	  if ('open' in state) {
54572	    cls.toggle(PALETTE_OPEN_CLS, state.open);
54573	  }
54574
54575	  eventBus.fire('palette.changed', {
54576	    twoColumn: twoColumn,
54577	    open: this.isOpen()
54578	  });
54579	};
54580
54581	Palette.prototype._update = function() {
54582
54583	  var entriesContainer = query('.djs-palette-entries', this._container),
54584	      entries = this._entries = this.getEntries();
54585
54586	  clear$1(entriesContainer);
54587
54588	  forEach(entries, function(entry, id) {
54589
54590	    var grouping = entry.group || 'default';
54591
54592	    var container = query('[data-group=' + grouping + ']', entriesContainer);
54593	    if (!container) {
54594	      container = domify('<div class="group" data-group="' + grouping + '"></div>');
54595	      entriesContainer.appendChild(container);
54596	    }
54597
54598	    var html = entry.html || (
54599	      entry.separator ?
54600	        '<hr class="separator" />' :
54601	        '<div class="entry" draggable="true"></div>');
54602
54603
54604	    var control = domify(html);
54605	    container.appendChild(control);
54606
54607	    if (!entry.separator) {
54608	      attr$1(control, 'data-action', id);
54609
54610	      if (entry.title) {
54611	        attr$1(control, 'title', entry.title);
54612	      }
54613
54614	      if (entry.className) {
54615	        addClasses(control, entry.className);
54616	      }
54617
54618	      if (entry.imageUrl) {
54619	        control.appendChild(domify('<img src="' + entry.imageUrl + '">'));
54620	      }
54621	    }
54622	  });
54623
54624	  // open after update
54625	  this.open();
54626	};
54627
54628
54629	/**
54630	 * Trigger an action available on the palette
54631	 *
54632	 * @param  {string} action
54633	 * @param  {Event} event
54634	 */
54635	Palette.prototype.trigger = function(action, event, autoActivate) {
54636	  var entries = this._entries,
54637	      entry,
54638	      handler,
54639	      originalEvent,
54640	      button = event.delegateTarget || event.target;
54641
54642	  if (!button) {
54643	    return event.preventDefault();
54644	  }
54645
54646	  entry = entries[attr$1(button, 'data-action')];
54647
54648	  // when user clicks on the palette and not on an action
54649	  if (!entry) {
54650	    return;
54651	  }
54652
54653	  handler = entry.action;
54654
54655	  originalEvent = event.originalEvent || event;
54656
54657	  // simple action (via callback function)
54658	  if (isFunction(handler)) {
54659	    if (action === 'click') {
54660	      handler(originalEvent, autoActivate);
54661	    }
54662	  } else {
54663	    if (handler[action]) {
54664	      handler[action](originalEvent, autoActivate);
54665	    }
54666	  }
54667
54668	  // silence other actions
54669	  event.preventDefault();
54670	};
54671
54672	Palette.prototype._layoutChanged = function() {
54673	  this._toggleState({});
54674	};
54675
54676	/**
54677	 * Do we need to collapse to two columns?
54678	 *
54679	 * @param {number} availableHeight
54680	 * @param {Object} entries
54681	 *
54682	 * @return {boolean}
54683	 */
54684	Palette.prototype._needsCollapse = function(availableHeight, entries) {
54685
54686	  // top margin + bottom toggle + bottom margin
54687	  // implementors must override this method if they
54688	  // change the palette styles
54689	  var margin = 20 + 10 + 20;
54690
54691	  var entriesHeight = Object.keys(entries).length * 46;
54692
54693	  return availableHeight < entriesHeight + margin;
54694	};
54695
54696	/**
54697	 * Close the palette
54698	 */
54699	Palette.prototype.close = function() {
54700
54701	  this._toggleState({
54702	    open: false,
54703	    twoColumn: false
54704	  });
54705	};
54706
54707
54708	/**
54709	 * Open the palette
54710	 */
54711	Palette.prototype.open = function() {
54712	  this._toggleState({ open: true });
54713	};
54714
54715
54716	Palette.prototype.toggle = function(open) {
54717	  if (this.isOpen()) {
54718	    this.close();
54719	  } else {
54720	    this.open();
54721	  }
54722	};
54723
54724	Palette.prototype.isActiveTool = function(tool) {
54725	  return tool && this._activeTool === tool;
54726	};
54727
54728	Palette.prototype.updateToolHighlight = function(name) {
54729	  var entriesContainer,
54730	      toolsContainer;
54731
54732	  if (!this._toolsContainer) {
54733	    entriesContainer = query('.djs-palette-entries', this._container);
54734
54735	    this._toolsContainer = query('[data-group=tools]', entriesContainer);
54736	  }
54737
54738	  toolsContainer = this._toolsContainer;
54739
54740	  forEach(toolsContainer.children, function(tool) {
54741	    var actionName = tool.getAttribute('data-action');
54742
54743	    if (!actionName) {
54744	      return;
54745	    }
54746
54747	    var toolClasses = classes$1(tool);
54748
54749	    actionName = actionName.replace('-tool', '');
54750
54751	    if (toolClasses.contains('entry') && actionName === name) {
54752	      toolClasses.add('highlighted-entry');
54753	    } else {
54754	      toolClasses.remove('highlighted-entry');
54755	    }
54756	  });
54757	};
54758
54759
54760	/**
54761	 * Return true if the palette is opened.
54762	 *
54763	 * @example
54764	 *
54765	 * palette.open();
54766	 *
54767	 * if (palette.isOpen()) {
54768	 *   // yes, we are open
54769	 * }
54770	 *
54771	 * @return {boolean} true if palette is opened
54772	 */
54773	Palette.prototype.isOpen = function() {
54774	  return classes$1(this._container).has(PALETTE_OPEN_CLS);
54775	};
54776
54777	/**
54778	 * Get container the palette lives in.
54779	 *
54780	 * @return {Element}
54781	 */
54782	Palette.prototype._getParentContainer = function() {
54783	  return this._canvas.getContainer();
54784	};
54785
54786
54787	/* markup definition */
54788
54789	Palette.HTML_MARKUP =
54790	  '<div class="djs-palette">' +
54791	    '<div class="djs-palette-entries"></div>' +
54792	    '<div class="djs-palette-toggle"></div>' +
54793	  '</div>';
54794
54795
54796	// helpers //////////////////////
54797
54798	function addClasses(element, classNames) {
54799
54800	  var classes = classes$1(element);
54801
54802	  var actualClassNames = isArray$2(classNames) ? classNames : classNames.split(/\s+/g);
54803	  actualClassNames.forEach(function(cls) {
54804	    classes.add(cls);
54805	  });
54806	}
54807
54808	function addPaletteEntries(entries, provider) {
54809
54810	  var entriesOrUpdater = provider.getPaletteEntries();
54811
54812	  if (isFunction(entriesOrUpdater)) {
54813	    return entriesOrUpdater(entries);
54814	  }
54815
54816	  forEach(entriesOrUpdater, function(entry, id) {
54817	    entries[id] = entry;
54818	  });
54819
54820	  return entries;
54821	}
54822
54823	var PaletteModule$1 = {
54824	  __init__: [ 'palette' ],
54825	  palette: [ 'type', Palette ]
54826	};
54827
54828	var LASSO_TOOL_CURSOR = 'crosshair';
54829
54830
54831	function LassoTool(
54832	    eventBus, canvas, dragging,
54833	    elementRegistry, selection, toolManager,
54834	    mouse) {
54835
54836	  this._selection = selection;
54837	  this._dragging = dragging;
54838	  this._mouse = mouse;
54839
54840	  var self = this;
54841
54842	  // lasso visuals implementation
54843
54844	  /**
54845	  * A helper that realizes the selection box visual
54846	  */
54847	  var visuals = {
54848
54849	    create: function(context) {
54850	      var container = canvas.getActiveLayer(),
54851	          frame;
54852
54853	      frame = context.frame = create$1('rect');
54854	      attr(frame, {
54855	        class: 'djs-lasso-overlay',
54856	        width:  1,
54857	        height: 1,
54858	        x: 0,
54859	        y: 0
54860	      });
54861
54862	      append(container, frame);
54863	    },
54864
54865	    update: function(context) {
54866	      var frame = context.frame,
54867	          bbox = context.bbox;
54868
54869	      attr(frame, {
54870	        x: bbox.x,
54871	        y: bbox.y,
54872	        width: bbox.width,
54873	        height: bbox.height
54874	      });
54875	    },
54876
54877	    remove: function(context) {
54878
54879	      if (context.frame) {
54880	        remove$1(context.frame);
54881	      }
54882	    }
54883	  };
54884
54885	  toolManager.registerTool('lasso', {
54886	    tool: 'lasso.selection',
54887	    dragging: 'lasso'
54888	  });
54889
54890	  eventBus.on('lasso.selection.end', function(event) {
54891	    var target = event.originalEvent.target;
54892
54893	    // only reactive on diagram click
54894	    // on some occasions, event.hover is not set and we have to check if the target is an svg
54895	    if (!event.hover && !(target instanceof SVGElement)) {
54896	      return;
54897	    }
54898
54899	    eventBus.once('lasso.selection.ended', function() {
54900	      self.activateLasso(event.originalEvent, true);
54901	    });
54902	  });
54903
54904	  // lasso interaction implementation
54905
54906	  eventBus.on('lasso.end', function(event) {
54907
54908	    var bbox = toBBox(event);
54909
54910	    var elements = elementRegistry.filter(function(element) {
54911	      return element;
54912	    });
54913
54914	    self.select(elements, bbox);
54915	  });
54916
54917	  eventBus.on('lasso.start', function(event) {
54918
54919	    var context = event.context;
54920
54921	    context.bbox = toBBox(event);
54922	    visuals.create(context);
54923	  });
54924
54925	  eventBus.on('lasso.move', function(event) {
54926
54927	    var context = event.context;
54928
54929	    context.bbox = toBBox(event);
54930	    visuals.update(context);
54931	  });
54932
54933	  eventBus.on('lasso.cleanup', function(event) {
54934
54935	    var context = event.context;
54936
54937	    visuals.remove(context);
54938	  });
54939
54940
54941	  // event integration
54942
54943	  eventBus.on('element.mousedown', 1500, function(event) {
54944
54945	    if (!hasSecondaryModifier(event)) {
54946	      return;
54947	    }
54948
54949	    self.activateLasso(event.originalEvent);
54950
54951	    // we've handled the event
54952	    return true;
54953	  });
54954	}
54955
54956	LassoTool.$inject = [
54957	  'eventBus',
54958	  'canvas',
54959	  'dragging',
54960	  'elementRegistry',
54961	  'selection',
54962	  'toolManager',
54963	  'mouse'
54964	];
54965
54966
54967	LassoTool.prototype.activateLasso = function(event, autoActivate) {
54968
54969	  this._dragging.init(event, 'lasso', {
54970	    autoActivate: autoActivate,
54971	    cursor: LASSO_TOOL_CURSOR,
54972	    data: {
54973	      context: {}
54974	    }
54975	  });
54976	};
54977
54978	LassoTool.prototype.activateSelection = function(event, autoActivate) {
54979
54980	  this._dragging.init(event, 'lasso.selection', {
54981	    trapClick: false,
54982	    autoActivate: autoActivate,
54983	    cursor: LASSO_TOOL_CURSOR,
54984	    data: {
54985	      context: {}
54986	    }
54987	  });
54988	};
54989
54990	LassoTool.prototype.select = function(elements, bbox) {
54991	  var selectedElements = getEnclosedElements(elements, bbox);
54992
54993	  this._selection.select(values(selectedElements));
54994	};
54995
54996	LassoTool.prototype.toggle = function() {
54997	  if (this.isActive()) {
54998	    return this._dragging.cancel();
54999	  }
55000
55001	  var mouseEvent = this._mouse.getLastMoveEvent();
55002
55003	  this.activateSelection(mouseEvent, !!mouseEvent);
55004	};
55005
55006	LassoTool.prototype.isActive = function() {
55007	  var context = this._dragging.context();
55008
55009	  return context && /^lasso/.test(context.prefix);
55010	};
55011
55012
55013
55014	function toBBox(event) {
55015
55016	  var start = {
55017
55018	    x: event.x - event.dx,
55019	    y: event.y - event.dy
55020	  };
55021
55022	  var end = {
55023	    x: event.x,
55024	    y: event.y
55025	  };
55026
55027	  var bbox;
55028
55029	  if ((start.x <= end.x && start.y < end.y) ||
55030	      (start.x < end.x && start.y <= end.y)) {
55031
55032	    bbox = {
55033	      x: start.x,
55034	      y: start.y,
55035	      width:  end.x - start.x,
55036	      height: end.y - start.y
55037	    };
55038	  } else if ((start.x >= end.x && start.y < end.y) ||
55039	             (start.x > end.x && start.y <= end.y)) {
55040
55041	    bbox = {
55042	      x: end.x,
55043	      y: start.y,
55044	      width:  start.x - end.x,
55045	      height: end.y - start.y
55046	    };
55047	  } else if ((start.x <= end.x && start.y > end.y) ||
55048	             (start.x < end.x && start.y >= end.y)) {
55049
55050	    bbox = {
55051	      x: start.x,
55052	      y: end.y,
55053	      width:  end.x - start.x,
55054	      height: start.y - end.y
55055	    };
55056	  } else if ((start.x >= end.x && start.y > end.y) ||
55057	             (start.x > end.x && start.y >= end.y)) {
55058
55059	    bbox = {
55060	      x: end.x,
55061	      y: end.y,
55062	      width:  start.x - end.x,
55063	      height: start.y - end.y
55064	    };
55065	  } else {
55066
55067	    bbox = {
55068	      x: end.x,
55069	      y: end.y,
55070	      width:  0,
55071	      height: 0
55072	    };
55073	  }
55074	  return bbox;
55075	}
55076
55077	var LassoToolModule = {
55078	  __depends__: [
55079	    ToolManagerModule,
55080	    MouseModule
55081	  ],
55082	  __init__: [ 'lassoTool' ],
55083	  lassoTool: [ 'type', LassoTool ]
55084	};
55085
55086	var HIGH_PRIORITY$1 = 1500;
55087	var HAND_CURSOR = 'grab';
55088
55089
55090	function HandTool(
55091	    eventBus, canvas, dragging,
55092	    injector, toolManager, mouse) {
55093
55094	  this._dragging = dragging;
55095	  this._mouse = mouse;
55096
55097	  var self = this,
55098	      keyboard = injector.get('keyboard', false);
55099
55100	  toolManager.registerTool('hand', {
55101	    tool: 'hand',
55102	    dragging: 'hand.move'
55103	  });
55104
55105	  eventBus.on('element.mousedown', HIGH_PRIORITY$1, function(event) {
55106
55107	    if (!hasPrimaryModifier(event)) {
55108	      return;
55109	    }
55110
55111	    self.activateMove(event.originalEvent, true);
55112
55113	    return false;
55114	  });
55115
55116	  keyboard && keyboard.addListener(HIGH_PRIORITY$1, function(e) {
55117	    if (!isSpace(e.keyEvent) || self.isActive()) {
55118	      return;
55119	    }
55120
55121	    var mouseEvent = self._mouse.getLastMoveEvent();
55122
55123	    self.activateMove(mouseEvent, !!mouseEvent);
55124	  }, 'keyboard.keydown');
55125
55126	  keyboard && keyboard.addListener(HIGH_PRIORITY$1, function(e) {
55127	    if (!isSpace(e.keyEvent) || !self.isActive()) {
55128	      return;
55129	    }
55130
55131	    self.toggle();
55132	  }, 'keyboard.keyup');
55133
55134	  eventBus.on('hand.end', function(event) {
55135	    var target = event.originalEvent.target;
55136
55137	    // only reactive on diagram click
55138	    // on some occasions, event.hover is not set and we have to check if the target is an svg
55139	    if (!event.hover && !(target instanceof SVGElement)) {
55140	      return false;
55141	    }
55142
55143	    eventBus.once('hand.ended', function() {
55144	      self.activateMove(event.originalEvent, { reactivate: true });
55145	    });
55146
55147	  });
55148
55149	  eventBus.on('hand.move.move', function(event) {
55150	    var scale = canvas.viewbox().scale;
55151
55152	    canvas.scroll({
55153	      dx: event.dx * scale,
55154	      dy: event.dy * scale
55155	    });
55156	  });
55157
55158	  eventBus.on('hand.move.end', function(event) {
55159	    var context = event.context,
55160	        reactivate = context.reactivate;
55161
55162	    // Don't reactivate if the user is using the keyboard keybinding
55163	    if (!hasPrimaryModifier(event) && reactivate) {
55164
55165	      eventBus.once('hand.move.ended', function(event) {
55166	        self.activateHand(event.originalEvent, true, true);
55167	      });
55168
55169	    }
55170
55171	    return false;
55172	  });
55173
55174	}
55175
55176	HandTool.$inject = [
55177	  'eventBus',
55178	  'canvas',
55179	  'dragging',
55180	  'injector',
55181	  'toolManager',
55182	  'mouse'
55183	];
55184
55185
55186	HandTool.prototype.activateMove = function(event, autoActivate, context) {
55187	  if (typeof autoActivate === 'object') {
55188	    context = autoActivate;
55189	    autoActivate = false;
55190	  }
55191
55192	  this._dragging.init(event, 'hand.move', {
55193	    autoActivate: autoActivate,
55194	    cursor: HAND_CURSOR,
55195	    data: {
55196	      context: context || {}
55197	    }
55198	  });
55199	};
55200
55201	HandTool.prototype.activateHand = function(event, autoActivate, reactivate) {
55202	  this._dragging.init(event, 'hand', {
55203	    trapClick: false,
55204	    autoActivate: autoActivate,
55205	    cursor: HAND_CURSOR,
55206	    data: {
55207	      context: {
55208	        reactivate: reactivate
55209	      }
55210	    }
55211	  });
55212	};
55213
55214	HandTool.prototype.toggle = function() {
55215	  if (this.isActive()) {
55216	    return this._dragging.cancel();
55217	  }
55218
55219	  var mouseEvent = this._mouse.getLastMoveEvent();
55220
55221	  this.activateHand(mouseEvent, !!mouseEvent);
55222	};
55223
55224	HandTool.prototype.isActive = function() {
55225	  var context = this._dragging.context();
55226
55227	  if (context) {
55228	    return /^(hand|hand\.move)$/.test(context.prefix);
55229	  }
55230
55231	  return false;
55232	};
55233
55234	// helpers //////////
55235
55236	function isSpace(keyEvent) {
55237	  return isKey(' ', keyEvent);
55238	}
55239
55240	var HandToolModule = {
55241	  __depends__: [
55242	    ToolManagerModule,
55243	    MouseModule
55244	  ],
55245	  __init__: [ 'handTool' ],
55246	  handTool: [ 'type', HandTool ]
55247	};
55248
55249	var MARKER_OK = 'connect-ok',
55250	    MARKER_NOT_OK = 'connect-not-ok';
55251
55252	/**
55253	 * @class
55254	 * @constructor
55255	 *
55256	 * @param {EventBus} eventBus
55257	 * @param {Dragging} dragging
55258	 * @param {Connect} connect
55259	 * @param {Canvas} canvas
55260	 * @param {ToolManager} toolManager
55261	 * @param {Rules} rules
55262	 * @param {Mouse} mouse
55263	 */
55264	function GlobalConnect(
55265	    eventBus, dragging, connect,
55266	    canvas, toolManager, rules,
55267	    mouse) {
55268
55269	  var self = this;
55270
55271	  this._dragging = dragging;
55272	  this._rules = rules;
55273	  this._mouse = mouse;
55274
55275	  toolManager.registerTool('global-connect', {
55276	    tool: 'global-connect',
55277	    dragging: 'global-connect.drag'
55278	  });
55279
55280	  eventBus.on('global-connect.hover', function(event) {
55281	    var context = event.context,
55282	        startTarget = event.hover;
55283
55284	    var canStartConnect = context.canStartConnect = self.canStartConnect(startTarget);
55285
55286	    // simply ignore hover
55287	    if (canStartConnect === null) {
55288	      return;
55289	    }
55290
55291	    context.startTarget = startTarget;
55292
55293	    canvas.addMarker(startTarget, canStartConnect ? MARKER_OK : MARKER_NOT_OK);
55294	  });
55295
55296
55297	  eventBus.on([ 'global-connect.out', 'global-connect.cleanup' ], function(event) {
55298	    var startTarget = event.context.startTarget,
55299	        canStartConnect = event.context.canStartConnect;
55300
55301	    if (startTarget) {
55302	      canvas.removeMarker(startTarget, canStartConnect ? MARKER_OK : MARKER_NOT_OK);
55303	    }
55304	  });
55305
55306
55307	  eventBus.on([ 'global-connect.ended' ], function(event) {
55308	    var context = event.context,
55309	        startTarget = context.startTarget,
55310	        startPosition = {
55311	          x: event.x,
55312	          y: event.y
55313	        };
55314
55315	    var canStartConnect = self.canStartConnect(startTarget);
55316
55317	    if (!canStartConnect) {
55318	      return;
55319	    }
55320
55321	    eventBus.once('element.out', function() {
55322	      eventBus.once([ 'connect.ended', 'connect.canceled' ], function() {
55323	        eventBus.fire('global-connect.drag.ended');
55324	      });
55325
55326	      connect.start(null, startTarget, startPosition);
55327	    });
55328
55329	    return false;
55330	  });
55331	}
55332
55333	GlobalConnect.$inject = [
55334	  'eventBus',
55335	  'dragging',
55336	  'connect',
55337	  'canvas',
55338	  'toolManager',
55339	  'rules',
55340	  'mouse'
55341	];
55342
55343	/**
55344	 * Initiates tool activity.
55345	 */
55346	GlobalConnect.prototype.start = function(event, autoActivate) {
55347	  this._dragging.init(event, 'global-connect', {
55348	    autoActivate: autoActivate,
55349	    trapClick: false,
55350	    data: {
55351	      context: {}
55352	    }
55353	  });
55354	};
55355
55356	GlobalConnect.prototype.toggle = function() {
55357
55358	  if (this.isActive()) {
55359	    return this._dragging.cancel();
55360	  }
55361
55362	  var mouseEvent = this._mouse.getLastMoveEvent();
55363
55364	  return this.start(mouseEvent, !!mouseEvent);
55365	};
55366
55367	GlobalConnect.prototype.isActive = function() {
55368	  var context = this._dragging.context();
55369
55370	  return context && /^global-connect/.test(context.prefix);
55371	};
55372
55373	/**
55374	 * Check if source shape can initiate connection.
55375	 *
55376	 * @param  {Shape} startTarget
55377	 * @return {boolean}
55378	 */
55379	GlobalConnect.prototype.canStartConnect = function(startTarget) {
55380	  return this._rules.allowed('connection.start', { source: startTarget });
55381	};
55382
55383	var GlobalConnectModule = {
55384	  __depends__: [
55385	    ConnectModule,
55386	    RulesModule$1,
55387	    DraggingModule,
55388	    ToolManagerModule,
55389	    MouseModule
55390	  ],
55391	  globalConnect: [ 'type', GlobalConnect ]
55392	};
55393
55394	/**
55395	 * A palette provider for BPMN 2.0 elements.
55396	 */
55397	function PaletteProvider(
55398	    palette, create, elementFactory,
55399	    spaceTool, lassoTool, handTool,
55400	    globalConnect, translate) {
55401
55402	  this._palette = palette;
55403	  this._create = create;
55404	  this._elementFactory = elementFactory;
55405	  this._spaceTool = spaceTool;
55406	  this._lassoTool = lassoTool;
55407	  this._handTool = handTool;
55408	  this._globalConnect = globalConnect;
55409	  this._translate = translate;
55410
55411	  palette.registerProvider(this);
55412	}
55413
55414	PaletteProvider.$inject = [
55415	  'palette',
55416	  'create',
55417	  'elementFactory',
55418	  'spaceTool',
55419	  'lassoTool',
55420	  'handTool',
55421	  'globalConnect',
55422	  'translate'
55423	];
55424
55425
55426	PaletteProvider.prototype.getPaletteEntries = function(element) {
55427
55428	  var actions = {},
55429	      create = this._create,
55430	      elementFactory = this._elementFactory,
55431	      spaceTool = this._spaceTool,
55432	      lassoTool = this._lassoTool,
55433	      handTool = this._handTool,
55434	      globalConnect = this._globalConnect,
55435	      translate = this._translate;
55436
55437	  function createAction(type, group, className, title, options) {
55438
55439	    function createListener(event) {
55440	      var shape = elementFactory.createShape(assign({ type: type }, options));
55441
55442	      if (options) {
55443	        shape.businessObject.di.isExpanded = options.isExpanded;
55444	      }
55445
55446	      create.start(event, shape);
55447	    }
55448
55449	    var shortType = type.replace(/^bpmn:/, '');
55450
55451	    return {
55452	      group: group,
55453	      className: className,
55454	      title: title || translate('Create {type}', { type: shortType }),
55455	      action: {
55456	        dragstart: createListener,
55457	        click: createListener
55458	      }
55459	    };
55460	  }
55461
55462	  function createSubprocess(event) {
55463	    var subProcess = elementFactory.createShape({
55464	      type: 'bpmn:SubProcess',
55465	      x: 0,
55466	      y: 0,
55467	      isExpanded: true
55468	    });
55469
55470	    var startEvent = elementFactory.createShape({
55471	      type: 'bpmn:StartEvent',
55472	      x: 40,
55473	      y: 82,
55474	      parent: subProcess
55475	    });
55476
55477	    create.start(event, [ subProcess, startEvent ], {
55478	      hints: {
55479	        autoSelect: [ startEvent ]
55480	      }
55481	    });
55482	  }
55483
55484	  function createParticipant(event) {
55485	    create.start(event, elementFactory.createParticipantShape());
55486	  }
55487
55488	  assign(actions, {
55489	    'hand-tool': {
55490	      group: 'tools',
55491	      className: 'bpmn-icon-hand-tool',
55492	      title: translate('Activate the hand tool'),
55493	      action: {
55494	        click: function(event) {
55495	          handTool.activateHand(event);
55496	        }
55497	      }
55498	    },
55499	    'lasso-tool': {
55500	      group: 'tools',
55501	      className: 'bpmn-icon-lasso-tool',
55502	      title: translate('Activate the lasso tool'),
55503	      action: {
55504	        click: function(event) {
55505	          lassoTool.activateSelection(event);
55506	        }
55507	      }
55508	    },
55509	    'space-tool': {
55510	      group: 'tools',
55511	      className: 'bpmn-icon-space-tool',
55512	      title: translate('Activate the create/remove space tool'),
55513	      action: {
55514	        click: function(event) {
55515	          spaceTool.activateSelection(event);
55516	        }
55517	      }
55518	    },
55519	    'global-connect-tool': {
55520	      group: 'tools',
55521	      className: 'bpmn-icon-connection-multi',
55522	      title: translate('Activate the global connect tool'),
55523	      action: {
55524	        click: function(event) {
55525	          globalConnect.start(event);
55526	        }
55527	      }
55528	    },
55529	    'tool-separator': {
55530	      group: 'tools',
55531	      separator: true
55532	    },
55533	    'create.start-event': createAction(
55534	      'bpmn:StartEvent', 'event', 'bpmn-icon-start-event-none',
55535	      translate('Create StartEvent')
55536	    ),
55537	    'create.intermediate-event': createAction(
55538	      'bpmn:IntermediateThrowEvent', 'event', 'bpmn-icon-intermediate-event-none',
55539	      translate('Create Intermediate/Boundary Event')
55540	    ),
55541	    'create.end-event': createAction(
55542	      'bpmn:EndEvent', 'event', 'bpmn-icon-end-event-none',
55543	      translate('Create EndEvent')
55544	    ),
55545	    'create.exclusive-gateway': createAction(
55546	      'bpmn:ExclusiveGateway', 'gateway', 'bpmn-icon-gateway-none',
55547	      translate('Create Gateway')
55548	    ),
55549	    'create.task': createAction(
55550	      'bpmn:Task', 'activity', 'bpmn-icon-task',
55551	      translate('Create Task')
55552	    ),
55553	    'create.data-object': createAction(
55554	      'bpmn:DataObjectReference', 'data-object', 'bpmn-icon-data-object',
55555	      translate('Create DataObjectReference')
55556	    ),
55557	    'create.data-store': createAction(
55558	      'bpmn:DataStoreReference', 'data-store', 'bpmn-icon-data-store',
55559	      translate('Create DataStoreReference')
55560	    ),
55561	    'create.subprocess-expanded': {
55562	      group: 'activity',
55563	      className: 'bpmn-icon-subprocess-expanded',
55564	      title: translate('Create expanded SubProcess'),
55565	      action: {
55566	        dragstart: createSubprocess,
55567	        click: createSubprocess
55568	      }
55569	    },
55570	    'create.participant-expanded': {
55571	      group: 'collaboration',
55572	      className: 'bpmn-icon-participant',
55573	      title: translate('Create Pool/Participant'),
55574	      action: {
55575	        dragstart: createParticipant,
55576	        click: createParticipant
55577	      }
55578	    },
55579	    'create.group': createAction(
55580	      'bpmn:Group', 'artifact', 'bpmn-icon-group',
55581	      translate('Create Group')
55582	    ),
55583	  });
55584
55585	  return actions;
55586	};
55587
55588	var PaletteModule = {
55589	  __depends__: [
55590	    PaletteModule$1,
55591	    CreateModule,
55592	    SpaceToolModule,
55593	    LassoToolModule,
55594	    HandToolModule,
55595	    GlobalConnectModule,
55596	    translate
55597	  ],
55598	  __init__: [ 'paletteProvider' ],
55599	  paletteProvider: [ 'type', PaletteProvider ]
55600	};
55601
55602	var LOW_PRIORITY = 250;
55603
55604
55605	function BpmnReplacePreview(
55606	    eventBus, elementRegistry, elementFactory,
55607	    canvas, previewSupport) {
55608
55609	  CommandInterceptor.call(this, eventBus);
55610
55611	  /**
55612	   * Replace the visuals of all elements in the context which can be replaced
55613	   *
55614	   * @param  {Object} context
55615	   */
55616	  function replaceVisual(context) {
55617
55618	    var replacements = context.canExecute.replacements;
55619
55620	    forEach(replacements, function(replacement) {
55621
55622	      var id = replacement.oldElementId;
55623
55624	      var newElement = {
55625	        type: replacement.newElementType
55626	      };
55627
55628	      // if the visual of the element is already replaced
55629	      if (context.visualReplacements[id]) {
55630	        return;
55631	      }
55632
55633	      var element = elementRegistry.get(id);
55634
55635	      assign(newElement, { x: element.x, y: element.y });
55636
55637	      // create a temporary shape
55638	      var tempShape = elementFactory.createShape(newElement);
55639
55640	      canvas.addShape(tempShape, element.parent);
55641
55642	      // select the original SVG element related to the element and hide it
55643	      var gfx = query('[data-element-id="' + cssEscape(element.id) + '"]', context.dragGroup);
55644
55645	      if (gfx) {
55646	        attr(gfx, { display: 'none' });
55647	      }
55648
55649	      // clone the gfx of the temporary shape and add it to the drag group
55650	      var dragger = previewSupport.addDragger(tempShape, context.dragGroup);
55651
55652	      context.visualReplacements[id] = dragger;
55653
55654	      canvas.removeShape(tempShape);
55655	    });
55656	  }
55657
55658	  /**
55659	   * Restore the original visuals of the previously replaced elements
55660	   *
55661	   * @param  {Object} context
55662	   */
55663	  function restoreVisual(context) {
55664
55665	    var visualReplacements = context.visualReplacements;
55666
55667	    forEach(visualReplacements, function(dragger, id) {
55668
55669	      var originalGfx = query('[data-element-id="' + cssEscape(id) + '"]', context.dragGroup);
55670
55671	      if (originalGfx) {
55672	        attr(originalGfx, { display: 'inline' });
55673	      }
55674
55675	      dragger.remove();
55676
55677	      if (visualReplacements[id]) {
55678	        delete visualReplacements[id];
55679	      }
55680	    });
55681	  }
55682
55683	  eventBus.on('shape.move.move', LOW_PRIORITY, function(event) {
55684
55685	    var context = event.context,
55686	        canExecute = context.canExecute;
55687
55688	    if (!context.visualReplacements) {
55689	      context.visualReplacements = {};
55690	    }
55691
55692	    if (canExecute && canExecute.replacements) {
55693	      replaceVisual(context);
55694	    } else {
55695	      restoreVisual(context);
55696	    }
55697	  });
55698	}
55699
55700	BpmnReplacePreview.$inject = [
55701	  'eventBus',
55702	  'elementRegistry',
55703	  'elementFactory',
55704	  'canvas',
55705	  'previewSupport'
55706	];
55707
55708	inherits$1(BpmnReplacePreview, CommandInterceptor);
55709
55710	var ReplacePreviewModule = {
55711	  __depends__: [
55712	    PreviewSupportModule
55713	  ],
55714	  __init__: [ 'bpmnReplacePreview' ],
55715	  bpmnReplacePreview: [ 'type', BpmnReplacePreview ]
55716	};
55717
55718	var HIGHER_PRIORITY$2 = 1250;
55719
55720	var BOUNDARY_TO_HOST_THRESHOLD = 40;
55721
55722	var TARGET_BOUNDS_PADDING = 20,
55723	    TASK_BOUNDS_PADDING = 10;
55724
55725	var TARGET_CENTER_PADDING = 20;
55726
55727	var AXES = [ 'x', 'y' ];
55728
55729	var abs = Math.abs;
55730
55731	/**
55732	 * Snap during connect.
55733	 *
55734	 * @param {EventBus} eventBus
55735	 */
55736	function BpmnConnectSnapping(eventBus) {
55737	  eventBus.on([
55738	    'connect.hover',
55739	    'connect.move',
55740	    'connect.end',
55741	  ], HIGHER_PRIORITY$2, function(event) {
55742	    var context = event.context,
55743	        canExecute = context.canExecute,
55744	        start = context.start,
55745	        hover = context.hover,
55746	        source = context.source,
55747	        target = context.target;
55748
55749	    // do NOT snap on CMD
55750	    if (event.originalEvent && isCmd(event.originalEvent)) {
55751	      return;
55752	    }
55753
55754	    if (!context.initialConnectionStart) {
55755	      context.initialConnectionStart = context.connectionStart;
55756	    }
55757
55758	    // snap hover
55759	    if (canExecute && hover) {
55760	      snapToShape(event, hover, getTargetBoundsPadding(hover));
55761	    }
55762
55763	    if (hover && isAnyType(canExecute, [
55764	      'bpmn:Association',
55765	      'bpmn:DataInputAssociation',
55766	      'bpmn:DataOutputAssociation',
55767	      'bpmn:SequenceFlow'
55768	    ])) {
55769	      context.connectionStart = mid$2(start);
55770
55771	      // snap hover
55772	      if (isAny(hover, [ 'bpmn:Event', 'bpmn:Gateway' ])) {
55773	        snapToPosition(event, mid$2(hover));
55774	      }
55775
55776	      // snap hover
55777	      if (isAny(hover, [ 'bpmn:Task', 'bpmn:SubProcess' ])) {
55778	        snapToTargetMid(event, hover);
55779	      }
55780
55781	      // snap source and target
55782	      if (is$1(source, 'bpmn:BoundaryEvent') && target === source.host) {
55783	        snapBoundaryEventLoop(event);
55784	      }
55785
55786	    } else if (isType(canExecute, 'bpmn:MessageFlow')) {
55787
55788	      if (is$1(start, 'bpmn:Event')) {
55789
55790	        // snap start
55791	        context.connectionStart = mid$2(start);
55792	      }
55793
55794	      if (is$1(hover, 'bpmn:Event')) {
55795
55796	        // snap hover
55797	        snapToPosition(event, mid$2(hover));
55798	      }
55799
55800	    } else {
55801
55802	      // un-snap source
55803	      context.connectionStart = context.initialConnectionStart;
55804	    }
55805	  });
55806	}
55807
55808	BpmnConnectSnapping.$inject = [ 'eventBus' ];
55809
55810
55811	// helpers //////////
55812
55813	// snap to target if event in target
55814	function snapToShape(event, target, padding) {
55815	  AXES.forEach(function(axis) {
55816	    var dimensionForAxis = getDimensionForAxis(axis, target);
55817
55818	    if (event[ axis ] < target[ axis ] + padding) {
55819	      setSnapped(event, axis, target[ axis ] + padding);
55820	    } else if (event[ axis ] > target[ axis ] + dimensionForAxis - padding) {
55821	      setSnapped(event, axis, target[ axis ] + dimensionForAxis - padding);
55822	    }
55823	  });
55824	}
55825
55826	// snap to target mid if event in target mid
55827	function snapToTargetMid(event, target) {
55828	  var targetMid = mid$2(target);
55829
55830	  AXES.forEach(function(axis) {
55831	    if (isMid(event, target, axis)) {
55832	      setSnapped(event, axis, targetMid[ axis ]);
55833	    }
55834	  });
55835	}
55836
55837	// snap to prevent loop overlapping boundary event
55838	function snapBoundaryEventLoop(event) {
55839	  var context = event.context,
55840	      source = context.source,
55841	      target = context.target;
55842
55843	  if (isReverse(context)) {
55844	    return;
55845	  }
55846
55847	  var sourceMid = mid$2(source),
55848	      orientation = getOrientation(sourceMid, target, -10),
55849	      axes = [];
55850
55851	  if (/top|bottom/.test(orientation)) {
55852	    axes.push('x');
55853	  }
55854
55855	  if (/left|right/.test(orientation)) {
55856	    axes.push('y');
55857	  }
55858
55859	  axes.forEach(function(axis) {
55860	    var coordinate = event[ axis ], newCoordinate;
55861
55862	    if (abs(coordinate - sourceMid[ axis ]) < BOUNDARY_TO_HOST_THRESHOLD) {
55863	      if (coordinate > sourceMid[ axis ]) {
55864	        newCoordinate = sourceMid[ axis ] + BOUNDARY_TO_HOST_THRESHOLD;
55865	      }
55866	      else {
55867	        newCoordinate = sourceMid[ axis ] - BOUNDARY_TO_HOST_THRESHOLD;
55868	      }
55869
55870	      setSnapped(event, axis, newCoordinate);
55871	    }
55872	  });
55873	}
55874
55875	function snapToPosition(event, position) {
55876	  setSnapped(event, 'x', position.x);
55877	  setSnapped(event, 'y', position.y);
55878	}
55879
55880	function isType(attrs, type) {
55881	  return attrs && attrs.type === type;
55882	}
55883
55884	function isAnyType(attrs, types) {
55885	  return some(types, function(type) {
55886	    return isType(attrs, type);
55887	  });
55888	}
55889
55890	function getDimensionForAxis(axis, element) {
55891	  return axis === 'x' ? element.width : element.height;
55892	}
55893
55894	function getTargetBoundsPadding(target) {
55895	  if (is$1(target, 'bpmn:Task')) {
55896	    return TASK_BOUNDS_PADDING;
55897	  } else {
55898	    return TARGET_BOUNDS_PADDING;
55899	  }
55900	}
55901
55902	function isMid(event, target, axis) {
55903	  return event[ axis ] > target[ axis ] + TARGET_CENTER_PADDING
55904	    && event[ axis ] < target[ axis ] + getDimensionForAxis(axis, target) - TARGET_CENTER_PADDING;
55905	}
55906
55907	function isReverse(context) {
55908	  var hover = context.hover,
55909	      source = context.source;
55910
55911	  return hover && source && hover === source;
55912	}
55913
55914	/**
55915	 * A snap context, containing the (possibly incomplete)
55916	 * mappings of drop targets (to identify the snapping)
55917	 * to computed snap points.
55918	 */
55919	function SnapContext() {
55920
55921	  /**
55922	   * Map<String, SnapPoints> mapping drop targets to
55923	   * a list of possible snappings.
55924	   *
55925	   * @type {Object}
55926	   */
55927	  this._targets = {};
55928
55929	  /**
55930	   * Map<String, Point> initial positioning of element
55931	   * regarding various snap directions.
55932	   *
55933	   * @type {Object}
55934	   */
55935	  this._snapOrigins = {};
55936
55937	  /**
55938	   * List of snap locations
55939	   *
55940	   * @type {Array<string>}
55941	   */
55942	  this._snapLocations = [];
55943
55944	  /**
55945	   * Map<String, Array<Point>> of default snapping locations
55946	   *
55947	   * @type {Object}
55948	   */
55949	  this._defaultSnaps = {};
55950	}
55951
55952
55953	SnapContext.prototype.getSnapOrigin = function(snapLocation) {
55954	  return this._snapOrigins[snapLocation];
55955	};
55956
55957
55958	SnapContext.prototype.setSnapOrigin = function(snapLocation, initialValue) {
55959	  this._snapOrigins[snapLocation] = initialValue;
55960
55961	  if (this._snapLocations.indexOf(snapLocation) === -1) {
55962	    this._snapLocations.push(snapLocation);
55963	  }
55964	};
55965
55966
55967	SnapContext.prototype.addDefaultSnap = function(type, point) {
55968
55969	  var snapValues = this._defaultSnaps[type];
55970
55971	  if (!snapValues) {
55972	    snapValues = this._defaultSnaps[type] = [];
55973	  }
55974
55975	  snapValues.push(point);
55976	};
55977
55978	/**
55979	 * Return a number of initialized snaps, i.e. snap locations such as
55980	 * top-left, mid, bottom-right and so forth.
55981	 *
55982	 * @return {Array<string>} snapLocations
55983	 */
55984	SnapContext.prototype.getSnapLocations = function() {
55985	  return this._snapLocations;
55986	};
55987
55988	/**
55989	 * Set the snap locations for this context.
55990	 *
55991	 * The order of locations determines precedence.
55992	 *
55993	 * @param {Array<string>} snapLocations
55994	 */
55995	SnapContext.prototype.setSnapLocations = function(snapLocations) {
55996	  this._snapLocations = snapLocations;
55997	};
55998
55999	/**
56000	 * Get snap points for a given target
56001	 *
56002	 * @param {Element|string} target
56003	 */
56004	SnapContext.prototype.pointsForTarget = function(target) {
56005
56006	  var targetId = target.id || target;
56007
56008	  var snapPoints = this._targets[targetId];
56009
56010	  if (!snapPoints) {
56011	    snapPoints = this._targets[targetId] = new SnapPoints();
56012	    snapPoints.initDefaults(this._defaultSnaps);
56013	  }
56014
56015	  return snapPoints;
56016	};
56017
56018
56019	/**
56020	 * Creates the snap points and initializes them with the
56021	 * given default values.
56022	 *
56023	 * @param {Object<string, Array<Point>>} [defaultPoints]
56024	 */
56025	function SnapPoints(defaultSnaps) {
56026
56027	  /**
56028	   * Map<String, Map<(x|y), Array<number>>> mapping snap locations,
56029	   * i.e. top-left, bottom-right, center to actual snap values.
56030	   *
56031	   * @type {Object}
56032	   */
56033	  this._snapValues = {};
56034	}
56035
56036	SnapPoints.prototype.add = function(snapLocation, point) {
56037
56038	  var snapValues = this._snapValues[snapLocation];
56039
56040	  if (!snapValues) {
56041	    snapValues = this._snapValues[snapLocation] = { x: [], y: [] };
56042	  }
56043
56044	  if (snapValues.x.indexOf(point.x) === -1) {
56045	    snapValues.x.push(point.x);
56046	  }
56047
56048	  if (snapValues.y.indexOf(point.y) === -1) {
56049	    snapValues.y.push(point.y);
56050	  }
56051	};
56052
56053
56054	SnapPoints.prototype.snap = function(point, snapLocation, axis, tolerance) {
56055	  var snappingValues = this._snapValues[snapLocation];
56056
56057	  return snappingValues && snapTo(point[axis], snappingValues[axis], tolerance);
56058	};
56059
56060	/**
56061	 * Initialize a number of default snapping points.
56062	 *
56063	 * @param  {Object} defaultSnaps
56064	 */
56065	SnapPoints.prototype.initDefaults = function(defaultSnaps) {
56066
56067	  var self = this;
56068
56069	  forEach(defaultSnaps || {}, function(snapPoints, snapLocation) {
56070	    forEach(snapPoints, function(point) {
56071	      self.add(snapLocation, point);
56072	    });
56073	  });
56074	};
56075
56076	var HIGHER_PRIORITY$1 = 1250;
56077
56078
56079	/**
56080	 * Snap during create and move.
56081	 *
56082	 * @param {EventBus} elementRegistry
56083	 * @param {EventBus} eventBus
56084	 * @param {Snapping} snapping
56085	 */
56086	function CreateMoveSnapping(elementRegistry, eventBus, snapping) {
56087	  var self = this;
56088
56089	  this._elementRegistry = elementRegistry;
56090
56091	  eventBus.on([
56092	    'create.start',
56093	    'shape.move.start'
56094	  ], function(event) {
56095	    self.initSnap(event);
56096	  });
56097
56098	  eventBus.on([
56099	    'create.move',
56100	    'create.end',
56101	    'shape.move.move',
56102	    'shape.move.end'
56103	  ], HIGHER_PRIORITY$1, function(event) {
56104	    var context = event.context,
56105	        shape = context.shape,
56106	        snapContext = context.snapContext,
56107	        target = context.target;
56108
56109	    if (event.originalEvent && isCmd(event.originalEvent)) {
56110	      return;
56111	    }
56112
56113	    if (isSnapped(event) || !target) {
56114	      return;
56115	    }
56116
56117	    var snapPoints = snapContext.pointsForTarget(target);
56118
56119	    if (!snapPoints.initialized) {
56120	      snapPoints = self.addSnapTargetPoints(snapPoints, shape, target);
56121
56122	      snapPoints.initialized = true;
56123	    }
56124
56125	    snapping.snap(event, snapPoints);
56126	  });
56127
56128	  eventBus.on([
56129	    'create.cleanup',
56130	    'shape.move.cleanup'
56131	  ], function() {
56132	    snapping.hide();
56133	  });
56134	}
56135
56136	CreateMoveSnapping.$inject = [
56137	  'elementRegistry',
56138	  'eventBus',
56139	  'snapping'
56140	];
56141
56142	CreateMoveSnapping.prototype.initSnap = function(event) {
56143	  var elementRegistry = this._elementRegistry;
56144
56145	  var context = event.context,
56146	      shape = context.shape,
56147	      snapContext = context.snapContext;
56148
56149	  if (!snapContext) {
56150	    snapContext = context.snapContext = new SnapContext();
56151	  }
56152
56153	  var shapeMid;
56154
56155	  if (elementRegistry.get(shape.id)) {
56156
56157	    // move
56158	    shapeMid = mid$2(shape, event);
56159	  } else {
56160
56161	    // create
56162	    shapeMid = {
56163	      x: event.x + mid$2(shape).x,
56164	      y: event.y + mid$2(shape).y
56165	    };
56166	  }
56167
56168	  var shapeTopLeft = {
56169	        x: shapeMid.x - shape.width / 2,
56170	        y: shapeMid.y - shape.height / 2
56171	      },
56172	      shapeBottomRight = {
56173	        x: shapeMid.x + shape.width / 2,
56174	        y: shapeMid.y + shape.height / 2
56175	      };
56176
56177	  snapContext.setSnapOrigin('mid', {
56178	    x: shapeMid.x - event.x,
56179	    y: shapeMid.y - event.y
56180	  });
56181
56182	  // snap labels to mid only
56183	  if (isLabel$1(shape)) {
56184	    return snapContext;
56185	  }
56186
56187	  snapContext.setSnapOrigin('top-left', {
56188	    x: shapeTopLeft.x - event.x,
56189	    y: shapeTopLeft.y - event.y
56190	  });
56191
56192	  snapContext.setSnapOrigin('bottom-right', {
56193	    x: shapeBottomRight.x - event.x,
56194	    y: shapeBottomRight.y - event.y
56195	  });
56196
56197	  return snapContext;
56198	};
56199
56200	CreateMoveSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target) {
56201	  var snapTargets = this.getSnapTargets(shape, target);
56202
56203	  forEach(snapTargets, function(snapTarget) {
56204
56205	    // handle labels
56206	    if (isLabel$1(snapTarget)) {
56207
56208	      if (isLabel$1(shape)) {
56209	        snapPoints.add('mid', mid$2(snapTarget));
56210	      }
56211
56212	      return;
56213	    }
56214
56215	    // handle connections
56216	    if (isConnection$1(snapTarget)) {
56217
56218	      // ignore single segment connections
56219	      if (snapTarget.waypoints.length < 3) {
56220	        return;
56221	      }
56222
56223	      // ignore first and last waypoint
56224	      var waypoints = snapTarget.waypoints.slice(1, -1);
56225
56226	      forEach(waypoints, function(waypoint) {
56227	        snapPoints.add('mid', waypoint);
56228	      });
56229
56230	      return;
56231	    }
56232
56233	    // handle shapes
56234	    snapPoints.add('mid', mid$2(snapTarget));
56235	  });
56236
56237	  if (!isNumber(shape.x) || !isNumber(shape.y)) {
56238	    return snapPoints;
56239	  }
56240
56241	  // snap to original position when moving
56242	  if (this._elementRegistry.get(shape.id)) {
56243	    snapPoints.add('mid', mid$2(shape));
56244	  }
56245
56246	  return snapPoints;
56247	};
56248
56249	CreateMoveSnapping.prototype.getSnapTargets = function(shape, target) {
56250	  return getChildren(target).filter(function(child) {
56251	    return !isHidden$1(child);
56252	  });
56253	};
56254
56255	// helpers //////////
56256
56257	function isConnection$1(element) {
56258	  return !!element.waypoints;
56259	}
56260
56261	function isHidden$1(element) {
56262	  return !!element.hidden;
56263	}
56264
56265	function isLabel$1(element) {
56266	  return !!element.labelTarget;
56267	}
56268
56269	var HIGH_PRIORITY = 1500;
56270
56271
56272	/**
56273	 * Snap during create and move.
56274	 *
56275	 * @param {EventBus} eventBus
56276	 * @param {Injector} injector
56277	 */
56278	function BpmnCreateMoveSnapping(eventBus, injector) {
56279	  injector.invoke(CreateMoveSnapping, this);
56280
56281	  // creating first participant
56282	  eventBus.on([ 'create.move', 'create.end' ], HIGH_PRIORITY, setSnappedIfConstrained);
56283
56284	  // snap boundary events
56285	  eventBus.on([
56286	    'create.move',
56287	    'create.end',
56288	    'shape.move.move',
56289	    'shape.move.end'
56290	  ], HIGH_PRIORITY, function(event) {
56291	    var context = event.context,
56292	        canExecute = context.canExecute,
56293	        target = context.target;
56294
56295	    var canAttach = canExecute && (canExecute === 'attach' || canExecute.attach);
56296
56297	    if (canAttach && !isSnapped(event)) {
56298	      snapBoundaryEvent(event, target);
56299	    }
56300	  });
56301	}
56302
56303	inherits$1(BpmnCreateMoveSnapping, CreateMoveSnapping);
56304
56305	BpmnCreateMoveSnapping.$inject = [
56306	  'eventBus',
56307	  'injector'
56308	];
56309
56310	BpmnCreateMoveSnapping.prototype.initSnap = function(event) {
56311	  var snapContext = CreateMoveSnapping.prototype.initSnap.call(this, event);
56312
56313	  var shape = event.shape;
56314
56315	  var isMove = !!this._elementRegistry.get(shape.id);
56316
56317	  // snap to docking points
56318	  forEach(shape.outgoing, function(connection) {
56319	    var docking = connection.waypoints[0];
56320
56321	    docking = docking.original || docking;
56322
56323	    snapContext.setSnapOrigin(connection.id + '-docking', getDockingSnapOrigin(docking, isMove, event));
56324	  });
56325
56326	  forEach(shape.incoming, function(connection) {
56327	    var docking = connection.waypoints[connection.waypoints.length - 1];
56328
56329	    docking = docking.original || docking;
56330
56331	    snapContext.setSnapOrigin(connection.id + '-docking', getDockingSnapOrigin(docking, isMove, event));
56332	  });
56333
56334	  if (is$1(shape, 'bpmn:Participant')) {
56335
56336	    // snap to borders with higher priority
56337	    snapContext.setSnapLocations([ 'top-left', 'bottom-right', 'mid' ]);
56338	  }
56339
56340	  return snapContext;
56341	};
56342
56343	BpmnCreateMoveSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target) {
56344	  CreateMoveSnapping.prototype.addSnapTargetPoints.call(this, snapPoints, shape, target);
56345
56346	  var snapTargets = this.getSnapTargets(shape, target);
56347
56348	  forEach(snapTargets, function(snapTarget) {
56349
56350	    // handle TRBL alignment
56351	    //
56352	    // * with container elements
56353	    // * with text annotations
56354	    if (isContainer(snapTarget) || areAll([ shape, snapTarget ], 'bpmn:TextAnnotation')) {
56355	      snapPoints.add('top-left', topLeft(snapTarget));
56356	      snapPoints.add('bottom-right', bottomRight(snapTarget));
56357	    }
56358	  });
56359
56360	  var elementRegistry = this._elementRegistry;
56361
56362	  // snap to docking points if not create mode
56363	  forEach(shape.incoming, function(connection) {
56364	    if (elementRegistry.get(shape.id)) {
56365
56366	      if (!includes(snapTargets, connection.source)) {
56367	        snapPoints.add('mid', getMid(connection.source));
56368	      }
56369
56370	      var docking = connection.waypoints[0];
56371	      snapPoints.add(connection.id + '-docking', docking.original || docking);
56372	    }
56373	  });
56374
56375	  forEach(shape.outgoing, function(connection) {
56376	    if (elementRegistry.get(shape.id)) {
56377
56378	      if (!includes(snapTargets, connection.target)) {
56379	        snapPoints.add('mid', getMid(connection.target));
56380	      }
56381
56382	      var docking = connection.waypoints[ connection.waypoints.length - 1 ];
56383
56384	      snapPoints.add(connection.id + '-docking', docking.original || docking);
56385	    }
56386	  });
56387
56388	  // add sequence flow parents as snap targets
56389	  if (is$1(target, 'bpmn:SequenceFlow')) {
56390	    snapPoints = this.addSnapTargetPoints(snapPoints, shape, target.parent);
56391	  }
56392
56393	  return snapPoints;
56394	};
56395
56396	BpmnCreateMoveSnapping.prototype.getSnapTargets = function(shape, target) {
56397	  return CreateMoveSnapping.prototype.getSnapTargets.call(this, shape, target)
56398	    .filter(function(snapTarget) {
56399
56400	      // do not snap to lanes
56401	      return !is$1(snapTarget, 'bpmn:Lane');
56402	    });
56403	};
56404
56405	// helpers //////////
56406
56407	function snapBoundaryEvent(event, target) {
56408	  var targetTRBL = asTRBL(target);
56409
56410	  var direction = getBoundaryAttachment(event, target);
56411
56412	  var context = event.context,
56413	      shape = context.shape;
56414
56415	  var offset;
56416
56417	  if (shape.parent) {
56418	    offset = { x: 0, y: 0 };
56419	  } else {
56420	    offset = getMid(shape);
56421	  }
56422
56423	  if (/top/.test(direction)) {
56424	    setSnapped(event, 'y', targetTRBL.top - offset.y);
56425	  } else if (/bottom/.test(direction)) {
56426	    setSnapped(event, 'y', targetTRBL.bottom - offset.y);
56427	  }
56428
56429	  if (/left/.test(direction)) {
56430	    setSnapped(event, 'x', targetTRBL.left - offset.x);
56431	  } else if (/right/.test(direction)) {
56432	    setSnapped(event, 'x', targetTRBL.right - offset.x);
56433	  }
56434	}
56435
56436	function areAll(elements, type) {
56437	  return elements.every(function(el) {
56438	    return is$1(el, type);
56439	  });
56440	}
56441
56442	function isContainer(element) {
56443	  if (is$1(element, 'bpmn:SubProcess') && isExpanded(element)) {
56444	    return true;
56445	  }
56446
56447	  return is$1(element, 'bpmn:Participant');
56448	}
56449
56450
56451	function setSnappedIfConstrained(event) {
56452	  var context = event.context,
56453	      createConstraints = context.createConstraints;
56454
56455	  if (!createConstraints) {
56456	    return;
56457	  }
56458
56459	  var top = createConstraints.top,
56460	      right = createConstraints.right,
56461	      bottom = createConstraints.bottom,
56462	      left = createConstraints.left;
56463
56464	  if ((left && left >= event.x) || (right && right <= event.x)) {
56465	    setSnapped(event, 'x', event.x);
56466	  }
56467
56468	  if ((top && top >= event.y) || (bottom && bottom <= event.y)) {
56469	    setSnapped(event, 'y', event.y);
56470	  }
56471	}
56472
56473	function includes(array, value) {
56474	  return array.indexOf(value) !== -1;
56475	}
56476
56477	function getDockingSnapOrigin(docking, isMove, event) {
56478	  return isMove ? (
56479	    {
56480	      x: docking.x - event.x,
56481	      y: docking.y - event.y
56482	    }
56483	  ) : {
56484	    x: docking.x,
56485	    y: docking.y
56486	  };
56487	}
56488
56489	var HIGHER_PRIORITY = 1250;
56490
56491
56492	/**
56493	 * Snap during resize.
56494	 *
56495	 * @param {EventBus} eventBus
56496	 * @param {Snapping} snapping
56497	 */
56498	function ResizeSnapping(eventBus, snapping) {
56499	  var self = this;
56500
56501	  eventBus.on([ 'resize.start' ], function(event) {
56502	    self.initSnap(event);
56503	  });
56504
56505	  eventBus.on([
56506	    'resize.move',
56507	    'resize.end',
56508	  ], HIGHER_PRIORITY, function(event) {
56509	    var context = event.context,
56510	        shape = context.shape,
56511	        parent = shape.parent,
56512	        direction = context.direction,
56513	        snapContext = context.snapContext;
56514
56515	    if (event.originalEvent && isCmd(event.originalEvent)) {
56516	      return;
56517	    }
56518
56519	    if (isSnapped(event)) {
56520	      return;
56521	    }
56522
56523	    var snapPoints = snapContext.pointsForTarget(parent);
56524
56525	    if (!snapPoints.initialized) {
56526	      snapPoints = self.addSnapTargetPoints(snapPoints, shape, parent, direction);
56527
56528	      snapPoints.initialized = true;
56529	    }
56530
56531	    if (isHorizontal(direction)) {
56532	      setSnapped(event, 'x', event.x);
56533	    }
56534
56535	    if (isVertical(direction)) {
56536	      setSnapped(event, 'y', event.y);
56537	    }
56538
56539	    snapping.snap(event, snapPoints);
56540	  });
56541
56542	  eventBus.on([ 'resize.cleanup' ], function() {
56543	    snapping.hide();
56544	  });
56545	}
56546
56547	ResizeSnapping.prototype.initSnap = function(event) {
56548	  var context = event.context,
56549	      shape = context.shape,
56550	      direction = context.direction,
56551	      snapContext = context.snapContext;
56552
56553	  if (!snapContext) {
56554	    snapContext = context.snapContext = new SnapContext();
56555	  }
56556
56557	  var snapOrigin = getSnapOrigin(shape, direction);
56558
56559	  snapContext.setSnapOrigin('corner', {
56560	    x: snapOrigin.x - event.x,
56561	    y: snapOrigin.y - event.y
56562	  });
56563
56564	  return snapContext;
56565	};
56566
56567	ResizeSnapping.prototype.addSnapTargetPoints = function(snapPoints, shape, target, direction) {
56568	  var snapTargets = this.getSnapTargets(shape, target);
56569
56570	  forEach(snapTargets, function(snapTarget) {
56571	    snapPoints.add('corner', bottomRight(snapTarget));
56572	    snapPoints.add('corner', topLeft(snapTarget));
56573	  });
56574
56575	  snapPoints.add('corner', getSnapOrigin(shape, direction));
56576
56577	  return snapPoints;
56578	};
56579
56580	ResizeSnapping.$inject = [
56581	  'eventBus',
56582	  'snapping'
56583	];
56584
56585	ResizeSnapping.prototype.getSnapTargets = function(shape, target) {
56586	  return getChildren(target).filter(function(child) {
56587	    return !isAttached(child, shape)
56588	      && !isConnection(child)
56589	      && !isHidden(child)
56590	      && !isLabel(child);
56591	  });
56592	};
56593
56594	// helpers //////////
56595
56596	function getSnapOrigin(shape, direction) {
56597	  var mid = getMid(shape),
56598	      trbl = asTRBL(shape);
56599
56600	  var snapOrigin = {
56601	    x: mid.x,
56602	    y: mid.y
56603	  };
56604
56605	  if (direction.indexOf('n') !== -1) {
56606	    snapOrigin.y = trbl.top;
56607	  } else if (direction.indexOf('s') !== -1) {
56608	    snapOrigin.y = trbl.bottom;
56609	  }
56610
56611	  if (direction.indexOf('e') !== -1) {
56612	    snapOrigin.x = trbl.right;
56613	  } else if (direction.indexOf('w') !== -1) {
56614	    snapOrigin.x = trbl.left;
56615	  }
56616
56617	  return snapOrigin;
56618	}
56619
56620	function isAttached(element, host) {
56621	  return element.host === host;
56622	}
56623
56624	function isConnection(element) {
56625	  return !!element.waypoints;
56626	}
56627
56628	function isHidden(element) {
56629	  return !!element.hidden;
56630	}
56631
56632	function isLabel(element) {
56633	  return !!element.labelTarget;
56634	}
56635
56636	function isHorizontal(direction) {
56637	  return direction === 'n' || direction === 's';
56638	}
56639
56640	function isVertical(direction) {
56641	  return direction === 'e' || direction === 'w';
56642	}
56643
56644	var SNAP_TOLERANCE = 7;
56645
56646	var SNAP_LINE_HIDE_DELAY = 1000;
56647
56648
56649	/**
56650	 * Generic snapping feature.
56651	 *
56652	 * @param {EventBus} eventBus
56653	 * @param {Canvas} canvas
56654	 */
56655	function Snapping(canvas) {
56656	  this._canvas = canvas;
56657
56658	  // delay hide by 1000 seconds since last snap
56659	  this._asyncHide = debounce(bind$2(this.hide, this), SNAP_LINE_HIDE_DELAY);
56660	}
56661
56662	Snapping.$inject = [ 'canvas' ];
56663
56664	/**
56665	 * Snap an event to given snap points.
56666	 *
56667	 * @param {Event} event
56668	 * @param {SnapPoints} snapPoints
56669	 */
56670	Snapping.prototype.snap = function(event, snapPoints) {
56671	  var context = event.context,
56672	      snapContext = context.snapContext,
56673	      snapLocations = snapContext.getSnapLocations();
56674
56675	  var snapping = {
56676	    x: isSnapped(event, 'x'),
56677	    y: isSnapped(event, 'y')
56678	  };
56679
56680	  forEach(snapLocations, function(location) {
56681	    var snapOrigin = snapContext.getSnapOrigin(location);
56682
56683	    var snapCurrent = {
56684	      x: event.x + snapOrigin.x,
56685	      y: event.y + snapOrigin.y
56686	    };
56687
56688	    // snap both axis if not snapped already
56689	    forEach([ 'x', 'y' ], function(axis) {
56690	      var locationSnapping;
56691
56692	      if (!snapping[axis]) {
56693	        locationSnapping = snapPoints.snap(snapCurrent, location, axis, SNAP_TOLERANCE);
56694
56695	        if (locationSnapping !== undefined) {
56696	          snapping[axis] = {
56697	            value: locationSnapping,
56698	            originValue: locationSnapping - snapOrigin[axis]
56699	          };
56700	        }
56701	      }
56702	    });
56703
56704	    // no need to continue snapping
56705	    if (snapping.x && snapping.y) {
56706	      return false;
56707	    }
56708	  });
56709
56710	  // show snap lines
56711	  this.showSnapLine('vertical', snapping.x && snapping.x.value);
56712	  this.showSnapLine('horizontal', snapping.y && snapping.y.value);
56713
56714	  // snap event
56715	  forEach([ 'x', 'y' ], function(axis) {
56716	    var axisSnapping = snapping[axis];
56717
56718	    if (isObject(axisSnapping)) {
56719	      setSnapped(event, axis, axisSnapping.originValue);
56720	    }
56721	  });
56722	};
56723
56724	Snapping.prototype._createLine = function(orientation) {
56725	  var root = this._canvas.getLayer('snap');
56726
56727	  var line = create$1('path');
56728
56729	  attr(line, { d: 'M0,0 L0,0' });
56730
56731	  classes(line).add('djs-snap-line');
56732
56733	  append(root, line);
56734
56735	  return {
56736	    update: function(position) {
56737
56738	      if (!isNumber(position)) {
56739	        attr(line, { display: 'none' });
56740	      } else {
56741	        if (orientation === 'horizontal') {
56742	          attr(line, {
56743	            d: 'M-100000,' + position + ' L+100000,' + position,
56744	            display: ''
56745	          });
56746	        } else {
56747	          attr(line, {
56748	            d: 'M ' + position + ',-100000 L ' + position + ', +100000',
56749	            display: ''
56750	          });
56751	        }
56752	      }
56753	    }
56754	  };
56755	};
56756
56757	Snapping.prototype._createSnapLines = function() {
56758	  this._snapLines = {
56759	    horizontal: this._createLine('horizontal'),
56760	    vertical: this._createLine('vertical')
56761	  };
56762	};
56763
56764	Snapping.prototype.showSnapLine = function(orientation, position) {
56765
56766	  var line = this.getSnapLine(orientation);
56767
56768	  if (line) {
56769	    line.update(position);
56770	  }
56771
56772	  this._asyncHide();
56773	};
56774
56775	Snapping.prototype.getSnapLine = function(orientation) {
56776	  if (!this._snapLines) {
56777	    this._createSnapLines();
56778	  }
56779
56780	  return this._snapLines[orientation];
56781	};
56782
56783	Snapping.prototype.hide = function() {
56784	  forEach(this._snapLines, function(snapLine) {
56785	    snapLine.update();
56786	  });
56787	};
56788
56789	var SnappingModule$1 = {
56790	  __init__: [
56791	    'createMoveSnapping',
56792	    'resizeSnapping',
56793	    'snapping'
56794	  ],
56795	  createMoveSnapping: [ 'type', CreateMoveSnapping ],
56796	  resizeSnapping: [ 'type', ResizeSnapping ],
56797	  snapping: [ 'type', Snapping ]
56798	};
56799
56800	var SnappingModule = {
56801	  __depends__: [ SnappingModule$1 ],
56802	  __init__: [
56803	    'connectSnapping',
56804	    'createMoveSnapping'
56805	  ],
56806	  connectSnapping: [ 'type', BpmnConnectSnapping ],
56807	  createMoveSnapping: [ 'type', BpmnCreateMoveSnapping ]
56808	};
56809
56810	/**
56811	 * Provides searching infrastructure
56812	 */
56813	function SearchPad(canvas, eventBus, overlays, selection) {
56814	  this._open = false;
56815	  this._results = [];
56816	  this._eventMaps = [];
56817
56818	  this._canvas = canvas;
56819	  this._eventBus = eventBus;
56820	  this._overlays = overlays;
56821	  this._selection = selection;
56822
56823	  // setup elements
56824	  this._container = domify(SearchPad.BOX_HTML);
56825	  this._searchInput = query(SearchPad.INPUT_SELECTOR, this._container);
56826	  this._resultsContainer = query(SearchPad.RESULTS_CONTAINER_SELECTOR, this._container);
56827
56828	  // attach search pad
56829	  this._canvas.getContainer().appendChild(this._container);
56830
56831	  // cleanup on destroy
56832	  eventBus.on([ 'canvas.destroy', 'diagram.destroy' ], this.close, this);
56833	}
56834
56835
56836	SearchPad.$inject = [
56837	  'canvas',
56838	  'eventBus',
56839	  'overlays',
56840	  'selection'
56841	];
56842
56843
56844	/**
56845	 * Binds and keeps track of all event listereners
56846	 */
56847	SearchPad.prototype._bindEvents = function() {
56848	  var self = this;
56849
56850	  function listen(el, selector, type, fn) {
56851	    self._eventMaps.push({
56852	      el: el,
56853	      type: type,
56854	      listener: delegate.bind(el, selector, type, fn)
56855	    });
56856	  }
56857
56858	  // close search on clicking anywhere outside
56859	  listen(document, 'html', 'click', function(e) {
56860	    self.close();
56861	  });
56862
56863	  // stop event from propagating and closing search
56864	  // focus on input
56865	  listen(this._container, SearchPad.INPUT_SELECTOR, 'click', function(e) {
56866	    e.stopPropagation();
56867	    e.delegateTarget.focus();
56868	  });
56869
56870	  // preselect result on hover
56871	  listen(this._container, SearchPad.RESULT_SELECTOR, 'mouseover', function(e) {
56872	    e.stopPropagation();
56873	    self._scrollToNode(e.delegateTarget);
56874	    self._preselect(e.delegateTarget);
56875	  });
56876
56877	  // selects desired result on mouse click
56878	  listen(this._container, SearchPad.RESULT_SELECTOR, 'click', function(e) {
56879	    e.stopPropagation();
56880	    self._select(e.delegateTarget);
56881	  });
56882
56883	  // prevent cursor in input from going left and right when using up/down to
56884	  // navigate results
56885	  listen(this._container, SearchPad.INPUT_SELECTOR, 'keydown', function(e) {
56886
56887	    // up
56888	    if (e.keyCode === 38) {
56889	      e.preventDefault();
56890	    }
56891
56892	    // down
56893	    if (e.keyCode === 40) {
56894	      e.preventDefault();
56895	    }
56896	  });
56897
56898	  // handle keyboard input
56899	  listen(this._container, SearchPad.INPUT_SELECTOR, 'keyup', function(e) {
56900
56901	    // escape
56902	    if (e.keyCode === 27) {
56903	      return self.close();
56904	    }
56905
56906	    // enter
56907	    if (e.keyCode === 13) {
56908	      var selected = self._getCurrentResult();
56909
56910	      return selected ? self._select(selected) : self.close();
56911	    }
56912
56913	    // up
56914	    if (e.keyCode === 38) {
56915	      return self._scrollToDirection(true);
56916	    }
56917
56918	    // down
56919	    if (e.keyCode === 40) {
56920	      return self._scrollToDirection();
56921	    }
56922
56923	    // left && right
56924	    // do not search while navigating text input
56925	    if (e.keyCode === 37 || e.keyCode === 39) {
56926	      return;
56927	    }
56928
56929	    // anything else
56930	    self._search(e.delegateTarget.value);
56931	  });
56932	};
56933
56934
56935	/**
56936	 * Unbinds all previously established listeners
56937	 */
56938	SearchPad.prototype._unbindEvents = function() {
56939	  this._eventMaps.forEach(function(m) {
56940	    delegate.unbind(m.el, m.type, m.listener);
56941	  });
56942	};
56943
56944
56945	/**
56946	 * Performs a search for the given pattern.
56947	 *
56948	 * @param  {string} pattern
56949	 */
56950	SearchPad.prototype._search = function(pattern) {
56951	  var self = this;
56952
56953	  this._clearResults();
56954
56955	  // do not search on empty query
56956	  if (!pattern || pattern === '') {
56957	    return;
56958	  }
56959
56960	  var searchResults = this._searchProvider.find(pattern);
56961
56962	  if (!searchResults.length) {
56963	    return;
56964	  }
56965
56966	  // append new results
56967	  searchResults.forEach(function(result) {
56968	    var id = result.element.id;
56969	    var node = self._createResultNode(result, id);
56970	    self._results[id] = {
56971	      element: result.element,
56972	      node: node
56973	    };
56974	  });
56975
56976	  // preselect first result
56977	  var node = query(SearchPad.RESULT_SELECTOR, this._resultsContainer);
56978	  this._scrollToNode(node);
56979	  this._preselect(node);
56980	};
56981
56982
56983	/**
56984	 * Navigate to the previous/next result. Defaults to next result.
56985	 * @param  {boolean} previous
56986	 */
56987	SearchPad.prototype._scrollToDirection = function(previous) {
56988	  var selected = this._getCurrentResult();
56989	  if (!selected) {
56990	    return;
56991	  }
56992
56993	  var node = previous ? selected.previousElementSibling : selected.nextElementSibling;
56994	  if (node) {
56995	    this._scrollToNode(node);
56996	    this._preselect(node);
56997	  }
56998	};
56999
57000
57001	/**
57002	 * Scroll to the node if it is not visible.
57003	 *
57004	 * @param  {Element} node
57005	 */
57006	SearchPad.prototype._scrollToNode = function(node) {
57007	  if (!node || node === this._getCurrentResult()) {
57008	    return;
57009	  }
57010
57011	  var nodeOffset = node.offsetTop;
57012	  var containerScroll = this._resultsContainer.scrollTop;
57013
57014	  var bottomScroll = nodeOffset - this._resultsContainer.clientHeight + node.clientHeight;
57015
57016	  if (nodeOffset < containerScroll) {
57017	    this._resultsContainer.scrollTop = nodeOffset;
57018	  } else if (containerScroll < bottomScroll) {
57019	    this._resultsContainer.scrollTop = bottomScroll;
57020	  }
57021	};
57022
57023
57024	/**
57025	 * Clears all results data.
57026	 */
57027	SearchPad.prototype._clearResults = function() {
57028	  clear$1(this._resultsContainer);
57029
57030	  this._results = [];
57031
57032	  this._resetOverlay();
57033
57034	  this._eventBus.fire('searchPad.cleared');
57035	};
57036
57037
57038	/**
57039	 * Get currently selected result.
57040	 *
57041	 * @return {Element}
57042	 */
57043	SearchPad.prototype._getCurrentResult = function() {
57044	  return query(SearchPad.RESULT_SELECTED_SELECTOR, this._resultsContainer);
57045	};
57046
57047
57048	/**
57049	 * Create result DOM element within results container
57050	 * that corresponds to a search result.
57051	 *
57052	 * 'result' : one of the elements returned by SearchProvider
57053	 * 'id' : id attribute value to assign to the new DOM node
57054	 * return : created DOM element
57055	 *
57056	 * @param  {SearchResult} result
57057	 * @param  {string} id
57058	 * @return {Element}
57059	 */
57060	SearchPad.prototype._createResultNode = function(result, id) {
57061	  var node = domify(SearchPad.RESULT_HTML);
57062
57063	  // create only if available
57064	  if (result.primaryTokens.length > 0) {
57065	    createInnerTextNode(node, result.primaryTokens, SearchPad.RESULT_PRIMARY_HTML);
57066	  }
57067
57068	  // secondary tokens (represent element ID) are allways available
57069	  createInnerTextNode(node, result.secondaryTokens, SearchPad.RESULT_SECONDARY_HTML);
57070
57071	  attr$1(node, SearchPad.RESULT_ID_ATTRIBUTE, id);
57072
57073	  this._resultsContainer.appendChild(node);
57074
57075	  return node;
57076	};
57077
57078
57079	/**
57080	 * Register search element provider.
57081	 *
57082	 * SearchProvider.find - provides search function over own elements
57083	 *  (pattern) => [{ text: <String>, element: <Element>}, ...]
57084	 *
57085	 * @param  {SearchProvider} provider
57086	 */
57087	SearchPad.prototype.registerProvider = function(provider) {
57088	  this._searchProvider = provider;
57089	};
57090
57091
57092	/**
57093	 * Open search pad.
57094	 */
57095	SearchPad.prototype.open = function() {
57096	  if (!this._searchProvider) {
57097	    throw new Error('no search provider registered');
57098	  }
57099
57100	  if (this.isOpen()) {
57101	    return;
57102	  }
57103
57104	  this._bindEvents();
57105
57106	  this._open = true;
57107
57108	  classes$1(this._container).add('open');
57109
57110	  this._searchInput.focus();
57111
57112	  this._eventBus.fire('searchPad.opened');
57113	};
57114
57115
57116	/**
57117	 * Close search pad.
57118	 */
57119	SearchPad.prototype.close = function() {
57120	  if (!this.isOpen()) {
57121	    return;
57122	  }
57123
57124	  this._unbindEvents();
57125
57126	  this._open = false;
57127
57128	  classes$1(this._container).remove('open');
57129
57130	  this._clearResults();
57131
57132	  this._searchInput.value = '';
57133	  this._searchInput.blur();
57134
57135	  this._resetOverlay();
57136
57137	  this._eventBus.fire('searchPad.closed');
57138	};
57139
57140
57141	/**
57142	 * Toggles search pad on/off.
57143	 */
57144	SearchPad.prototype.toggle = function() {
57145	  this.isOpen() ? this.close() : this.open();
57146	};
57147
57148
57149	/**
57150	 * Report state of search pad.
57151	 */
57152	SearchPad.prototype.isOpen = function() {
57153	  return this._open;
57154	};
57155
57156
57157	/**
57158	 * Preselect result entry.
57159	 *
57160	 * @param  {Element} element
57161	 */
57162	SearchPad.prototype._preselect = function(node) {
57163	  var selectedNode = this._getCurrentResult();
57164
57165	  // already selected
57166	  if (node === selectedNode) {
57167	    return;
57168	  }
57169
57170	  // removing preselection from current node
57171	  if (selectedNode) {
57172	    classes$1(selectedNode).remove(SearchPad.RESULT_SELECTED_CLASS);
57173	  }
57174
57175	  var id = attr$1(node, SearchPad.RESULT_ID_ATTRIBUTE);
57176	  var element = this._results[id].element;
57177
57178	  classes$1(node).add(SearchPad.RESULT_SELECTED_CLASS);
57179
57180	  this._resetOverlay(element);
57181
57182	  this._canvas.scrollToElement(element, { top: 400 });
57183
57184	  this._selection.select(element);
57185
57186	  this._eventBus.fire('searchPad.preselected', element);
57187	};
57188
57189
57190	/**
57191	 * Select result node.
57192	 *
57193	 * @param  {Element} element
57194	 */
57195	SearchPad.prototype._select = function(node) {
57196	  var id = attr$1(node, SearchPad.RESULT_ID_ATTRIBUTE);
57197	  var element = this._results[id].element;
57198
57199	  this.close();
57200
57201	  this._resetOverlay();
57202
57203	  this._canvas.scrollToElement(element, { top: 400 });
57204
57205	  this._selection.select(element);
57206
57207	  this._eventBus.fire('searchPad.selected', element);
57208	};
57209
57210
57211	/**
57212	 * Reset overlay removes and, optionally, set
57213	 * overlay to a new element.
57214	 *
57215	 * @param  {Element} element
57216	 */
57217	SearchPad.prototype._resetOverlay = function(element) {
57218	  if (this._overlayId) {
57219	    this._overlays.remove(this._overlayId);
57220	  }
57221
57222	  if (element) {
57223	    var box = getBBox(element);
57224	    var overlay = constructOverlay(box);
57225	    this._overlayId = this._overlays.add(element, overlay);
57226	  }
57227	};
57228
57229
57230	/**
57231	 * Construct overlay object for the given bounding box.
57232	 *
57233	 * @param  {BoundingBox} box
57234	 * @return {Object}
57235	 */
57236	function constructOverlay(box) {
57237
57238	  var offset = 6;
57239	  var w = box.width + offset * 2;
57240	  var h = box.height + offset * 2;
57241
57242	  var styles = [
57243	    'width: '+ w +'px',
57244	    'height: '+ h + 'px'
57245	  ].join('; ');
57246
57247	  return {
57248	    position: {
57249	      bottom: h - offset,
57250	      right: w - offset
57251	    },
57252	    show: true,
57253	    html: '<div style="' + styles + '" class="' + SearchPad.OVERLAY_CLASS + '"></div>'
57254	  };
57255	}
57256
57257
57258	/**
57259	 * Creates and appends child node from result tokens and HTML template.
57260	 *
57261	 * @param  {Element} node
57262	 * @param  {Array<Object>} tokens
57263	 * @param  {string} template
57264	 */
57265	function createInnerTextNode(parentNode, tokens, template) {
57266	  var text = createHtmlText(tokens);
57267	  var childNode = domify(template);
57268	  childNode.innerHTML = text;
57269	  parentNode.appendChild(childNode);
57270	}
57271
57272	/**
57273	 * Create internal HTML markup from result tokens.
57274	 * Caters for highlighting pattern matched tokens.
57275	 *
57276	 * @param  {Array<Object>} tokens
57277	 * @return {string}
57278	 */
57279	function createHtmlText(tokens) {
57280	  var htmlText = '';
57281
57282	  tokens.forEach(function(t) {
57283	    if (t.matched) {
57284	      htmlText += '<strong class="' + SearchPad.RESULT_HIGHLIGHT_CLASS + '">' + escapeHTML(t.matched) + '</strong>';
57285	    } else {
57286	      htmlText += escapeHTML(t.normal);
57287	    }
57288	  });
57289
57290	  return htmlText !== '' ? htmlText : null;
57291	}
57292
57293
57294	/**
57295	 * CONSTANTS
57296	 */
57297	SearchPad.CONTAINER_SELECTOR = '.djs-search-container';
57298	SearchPad.INPUT_SELECTOR = '.djs-search-input input';
57299	SearchPad.RESULTS_CONTAINER_SELECTOR = '.djs-search-results';
57300	SearchPad.RESULT_SELECTOR = '.djs-search-result';
57301	SearchPad.RESULT_SELECTED_CLASS = 'djs-search-result-selected';
57302	SearchPad.RESULT_SELECTED_SELECTOR = '.' + SearchPad.RESULT_SELECTED_CLASS;
57303	SearchPad.RESULT_ID_ATTRIBUTE = 'data-result-id';
57304	SearchPad.RESULT_HIGHLIGHT_CLASS = 'djs-search-highlight';
57305	SearchPad.OVERLAY_CLASS = 'djs-search-overlay';
57306
57307	SearchPad.BOX_HTML =
57308	  '<div class="djs-search-container djs-draggable djs-scrollable">' +
57309	    '<div class="djs-search-input">' +
57310	      '<input type="text"/>' +
57311	    '</div>' +
57312	    '<div class="djs-search-results"></div>' +
57313	  '</div>';
57314
57315	SearchPad.RESULT_HTML =
57316	  '<div class="djs-search-result"></div>';
57317
57318	SearchPad.RESULT_PRIMARY_HTML =
57319	  '<div class="djs-search-result-primary"></div>';
57320
57321	SearchPad.RESULT_SECONDARY_HTML =
57322	  '<p class="djs-search-result-secondary"></p>';
57323
57324	var SearchPadModule = {
57325	  __depends__: [
57326	    OverlaysModule,
57327	    SelectionModule
57328	  ],
57329	  searchPad: [ 'type', SearchPad ]
57330	};
57331
57332	/**
57333	 * Provides ability to search through BPMN elements
57334	 */
57335	function BpmnSearchProvider(elementRegistry, searchPad, canvas) {
57336
57337	  this._elementRegistry = elementRegistry;
57338	  this._canvas = canvas;
57339
57340	  searchPad.registerProvider(this);
57341	}
57342
57343	BpmnSearchProvider.$inject = [
57344	  'elementRegistry',
57345	  'searchPad',
57346	  'canvas'
57347	];
57348
57349
57350	/**
57351	 * Finds all elements that match given pattern
57352	 *
57353	 * <Result> :
57354	 *  {
57355	 *    primaryTokens: <Array<Token>>,
57356	 *    secondaryTokens: <Array<Token>>,
57357	 *    element: <Element>
57358	 *  }
57359	 *
57360	 * <Token> :
57361	 *  {
57362	 *    normal|matched: <string>
57363	 *  }
57364	 *
57365	 * @param  {string} pattern
57366	 * @return {Array<Result>}
57367	 */
57368	BpmnSearchProvider.prototype.find = function(pattern) {
57369	  var rootElement = this._canvas.getRootElement();
57370
57371	  var elements = this._elementRegistry.filter(function(element) {
57372	    if (element.labelTarget) {
57373	      return false;
57374	    }
57375	    return true;
57376	  });
57377
57378	  // do not include root element
57379	  elements = filter(elements, function(element) {
57380	    return element !== rootElement;
57381	  });
57382
57383	  elements = map$1(elements, function(element) {
57384	    return {
57385	      primaryTokens: matchAndSplit(getLabel(element), pattern),
57386	      secondaryTokens: matchAndSplit(element.id, pattern),
57387	      element: element
57388	    };
57389	  });
57390
57391	  // exclude non-matched elements
57392	  elements = filter(elements, function(element) {
57393	    return hasMatched(element.primaryTokens) || hasMatched(element.secondaryTokens);
57394	  });
57395
57396	  elements = sortBy(elements, function(element) {
57397	    return getLabel(element.element) + element.element.id;
57398	  });
57399
57400	  return elements;
57401	};
57402
57403
57404	function hasMatched(tokens) {
57405	  var matched = filter(tokens, function(t) {
57406	    return !!t.matched;
57407	  });
57408
57409	  return matched.length > 0;
57410	}
57411
57412
57413	function matchAndSplit(text, pattern) {
57414	  var tokens = [],
57415	      originalText = text;
57416
57417	  if (!text) {
57418	    return tokens;
57419	  }
57420
57421	  text = text.toLowerCase();
57422	  pattern = pattern.toLowerCase();
57423
57424	  var i = text.indexOf(pattern);
57425
57426	  if (i > -1) {
57427	    if (i !== 0) {
57428	      tokens.push({
57429	        normal: originalText.substr(0, i)
57430	      });
57431	    }
57432
57433	    tokens.push({
57434	      matched: originalText.substr(i, pattern.length)
57435	    });
57436
57437	    if (pattern.length + i < text.length) {
57438	      tokens.push({
57439	        normal: originalText.substr(pattern.length + i, text.length)
57440	      });
57441	    }
57442	  } else {
57443	    tokens.push({
57444	      normal: originalText
57445	    });
57446	  }
57447
57448	  return tokens;
57449	}
57450
57451	var SearchModule = {
57452	  __depends__: [
57453	    SearchPadModule
57454	  ],
57455	  __init__: [ 'bpmnSearch'],
57456	  bpmnSearch: [ 'type', BpmnSearchProvider ]
57457	};
57458
57459	var initialDiagram =
57460	  '<?xml version="1.0" encoding="UTF-8"?>' +
57461	  '<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
57462	                    'xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" ' +
57463	                    'xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" ' +
57464	                    'xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" ' +
57465	                    'targetNamespace="http://bpmn.io/schema/bpmn" ' +
57466	                    'id="Definitions_1">' +
57467	    '<bpmn:process id="Process_1" isExecutable="false">' +
57468	      '<bpmn:startEvent id="StartEvent_1"/>' +
57469	    '</bpmn:process>' +
57470	    '<bpmndi:BPMNDiagram id="BPMNDiagram_1">' +
57471	      '<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">' +
57472	        '<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">' +
57473	          '<dc:Bounds height="36.0" width="36.0" x="173.0" y="102.0"/>' +
57474	        '</bpmndi:BPMNShape>' +
57475	      '</bpmndi:BPMNPlane>' +
57476	    '</bpmndi:BPMNDiagram>' +
57477	  '</bpmn:definitions>';
57478
57479
57480	/**
57481	 * A modeler for BPMN 2.0 diagrams.
57482	 *
57483	 *
57484	 * ## Extending the Modeler
57485	 *
57486	 * In order to extend the viewer pass extension modules to bootstrap via the
57487	 * `additionalModules` option. An extension module is an object that exposes
57488	 * named services.
57489	 *
57490	 * The following example depicts the integration of a simple
57491	 * logging component that integrates with interaction events:
57492	 *
57493	 *
57494	 * ```javascript
57495	 *
57496	 * // logging component
57497	 * function InteractionLogger(eventBus) {
57498	 *   eventBus.on('element.hover', function(event) {
57499	 *     console.log()
57500	 *   })
57501	 * }
57502	 *
57503	 * InteractionLogger.$inject = [ 'eventBus' ]; // minification save
57504	 *
57505	 * // extension module
57506	 * var extensionModule = {
57507	 *   __init__: [ 'interactionLogger' ],
57508	 *   interactionLogger: [ 'type', InteractionLogger ]
57509	 * };
57510	 *
57511	 * // extend the viewer
57512	 * var bpmnModeler = new Modeler({ additionalModules: [ extensionModule ] });
57513	 * bpmnModeler.importXML(...);
57514	 * ```
57515	 *
57516	 *
57517	 * ## Customizing / Replacing Components
57518	 *
57519	 * You can replace individual diagram components by redefining them in override modules.
57520	 * This works for all components, including those defined in the core.
57521	 *
57522	 * Pass in override modules via the `options.additionalModules` flag like this:
57523	 *
57524	 * ```javascript
57525	 * function CustomContextPadProvider(contextPad) {
57526	 *
57527	 *   contextPad.registerProvider(this);
57528	 *
57529	 *   this.getContextPadEntries = function(element) {
57530	 *     // no entries, effectively disable the context pad
57531	 *     return {};
57532	 *   };
57533	 * }
57534	 *
57535	 * CustomContextPadProvider.$inject = [ 'contextPad' ];
57536	 *
57537	 * var overrideModule = {
57538	 *   contextPadProvider: [ 'type', CustomContextPadProvider ]
57539	 * };
57540	 *
57541	 * var bpmnModeler = new Modeler({ additionalModules: [ overrideModule ]});
57542	 * ```
57543	 *
57544	 * @param {Object} [options] configuration options to pass to the viewer
57545	 * @param {DOMElement} [options.container] the container to render the viewer in, defaults to body.
57546	 * @param {string|number} [options.width] the width of the viewer
57547	 * @param {string|number} [options.height] the height of the viewer
57548	 * @param {Object} [options.moddleExtensions] extension packages to provide
57549	 * @param {Array<didi.Module>} [options.modules] a list of modules to override the default modules
57550	 * @param {Array<didi.Module>} [options.additionalModules] a list of modules to use with the default modules
57551	 */
57552	function Modeler(options) {
57553	  BaseModeler.call(this, options);
57554	}
57555
57556	inherits$1(Modeler, BaseModeler);
57557
57558
57559	Modeler.Viewer = Viewer;
57560	Modeler.NavigatedViewer = NavigatedViewer;
57561
57562	/**
57563	* The createDiagram result.
57564	*
57565	* @typedef {Object} CreateDiagramResult
57566	*
57567	* @property {Array<string>} warnings
57568	*/
57569
57570	/**
57571	* The createDiagram error.
57572	*
57573	* @typedef {Error} CreateDiagramError
57574	*
57575	* @property {Array<string>} warnings
57576	*/
57577
57578	/**
57579	 * Create a new diagram to start modeling.
57580	 *
57581	 * Returns {Promise<CreateDiagramResult, CreateDiagramError>}
57582	 */
57583	Modeler.prototype.createDiagram = wrapForCompatibility(function createDiagram() {
57584	  return this.importXML(initialDiagram);
57585	});
57586
57587
57588	Modeler.prototype._interactionModules = [
57589
57590	  // non-modeling components
57591	  KeyboardMoveModule,
57592	  MoveCanvasModule,
57593	  TouchModule,
57594	  ZoomScrollModule
57595	];
57596
57597	Modeler.prototype._modelingModules = [
57598
57599	  // modeling components
57600	  AlignElementsModule,
57601	  AutoPlaceModule,
57602	  AutoScrollModule,
57603	  AutoResizeModule,
57604	  BendpointsModule,
57605	  ConnectModule,
57606	  ConnectionPreviewModule,
57607	  ContextPadModule,
57608	  CopyPasteModule,
57609	  CreateModule,
57610	  DistributeElementsModule,
57611	  EditorActionsModule,
57612	  GridSnappingModule,
57613	  InteractionEventsModule,
57614	  KeyboardModule,
57615	  KeyboardMoveSelectionModule,
57616	  LabelEditingModule,
57617	  ModelingModule,
57618	  MoveModule,
57619	  PaletteModule,
57620	  ReplacePreviewModule,
57621	  ResizeModule,
57622	  SnappingModule,
57623	  SearchModule
57624	];
57625
57626
57627	// modules the modeler is composed of
57628	//
57629	// - viewer modules
57630	// - interaction modules
57631	// - modeling modules
57632
57633	Modeler.prototype._modules = [].concat(
57634	  Viewer.prototype._modules,
57635	  Modeler.prototype._interactionModules,
57636	  Modeler.prototype._modelingModules
57637	);
57638
57639	return Modeler;
57640
57641})));
57642