server/php/basic/public_html/static/lib/paper/paper-full.js
changeset 442 adb907bba956
child 495 444b80998255
equal deleted inserted replaced
441:4732f078d0fe 442:adb907bba956
       
     1 /*!
       
     2  * Paper.js v0.9.22 - The Swiss Army Knife of Vector Graphics Scripting.
       
     3  * http://paperjs.org/
       
     4  *
       
     5  * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
       
     6  * http://scratchdisk.com/ & http://jonathanpuckey.com/
       
     7  *
       
     8  * Distributed under the MIT license. See LICENSE file for details.
       
     9  *
       
    10  * All rights reserved.
       
    11  *
       
    12  * Date: Sat Feb 28 19:20:48 2015 +0100
       
    13  *
       
    14  ***
       
    15  *
       
    16  * Straps.js - Class inheritance library with support for bean-style accessors
       
    17  *
       
    18  * Copyright (c) 2006 - 2013 Juerg Lehni
       
    19  * http://scratchdisk.com/
       
    20  *
       
    21  * Distributed under the MIT license.
       
    22  *
       
    23  ***
       
    24  *
       
    25  * Acorn.js
       
    26  * http://marijnhaverbeke.nl/acorn/
       
    27  *
       
    28  * Acorn is a tiny, fast JavaScript parser written in JavaScript,
       
    29  * created by Marijn Haverbeke and released under an MIT license.
       
    30  *
       
    31  */
       
    32 
       
    33 var paper = new function(undefined) {
       
    34 
       
    35 var Base = new function() {
       
    36 	var hidden = /^(statics|enumerable|beans|preserve)$/,
       
    37 
       
    38 		forEach = [].forEach || function(iter, bind) {
       
    39 			for (var i = 0, l = this.length; i < l; i++)
       
    40 				iter.call(bind, this[i], i, this);
       
    41 		},
       
    42 
       
    43 		forIn = function(iter, bind) {
       
    44 			for (var i in this)
       
    45 				if (this.hasOwnProperty(i))
       
    46 					iter.call(bind, this[i], i, this);
       
    47 		},
       
    48 
       
    49 		create = Object.create || function(proto) {
       
    50 			return { __proto__: proto };
       
    51 		},
       
    52 
       
    53 		describe = Object.getOwnPropertyDescriptor || function(obj, name) {
       
    54 			var get = obj.__lookupGetter__ && obj.__lookupGetter__(name);
       
    55 			return get
       
    56 					? { get: get, set: obj.__lookupSetter__(name),
       
    57 						enumerable: true, configurable: true }
       
    58 					: obj.hasOwnProperty(name)
       
    59 						? { value: obj[name], enumerable: true,
       
    60 							configurable: true, writable: true }
       
    61 						: null;
       
    62 		},
       
    63 
       
    64 		_define = Object.defineProperty || function(obj, name, desc) {
       
    65 			if ((desc.get || desc.set) && obj.__defineGetter__) {
       
    66 				if (desc.get)
       
    67 					obj.__defineGetter__(name, desc.get);
       
    68 				if (desc.set)
       
    69 					obj.__defineSetter__(name, desc.set);
       
    70 			} else {
       
    71 				obj[name] = desc.value;
       
    72 			}
       
    73 			return obj;
       
    74 		},
       
    75 
       
    76 		define = function(obj, name, desc) {
       
    77 			delete obj[name];
       
    78 			return _define(obj, name, desc);
       
    79 		};
       
    80 
       
    81 	function inject(dest, src, enumerable, beans, preserve) {
       
    82 		var beansNames = {};
       
    83 
       
    84 		function field(name, val) {
       
    85 			val = val || (val = describe(src, name))
       
    86 					&& (val.get ? val : val.value);
       
    87 			if (typeof val === 'string' && val[0] === '#')
       
    88 				val = dest[val.substring(1)] || val;
       
    89 			var isFunc = typeof val === 'function',
       
    90 				res = val,
       
    91 				prev = preserve || isFunc
       
    92 						? (val && val.get ? name in dest : dest[name])
       
    93 						: null,
       
    94 				bean;
       
    95 			if (!preserve || !prev) {
       
    96 				if (isFunc && prev)
       
    97 					val.base = prev;
       
    98 				if (isFunc && beans !== false
       
    99 						&& (bean = name.match(/^([gs]et|is)(([A-Z])(.*))$/)))
       
   100 					beansNames[bean[3].toLowerCase() + bean[4]] = bean[2];
       
   101 				if (!res || isFunc || !res.get || typeof res.get !== 'function'
       
   102 						|| !Base.isPlainObject(res))
       
   103 					res = { value: res, writable: true };
       
   104 				if ((describe(dest, name)
       
   105 						|| { configurable: true }).configurable) {
       
   106 					res.configurable = true;
       
   107 					res.enumerable = enumerable;
       
   108 				}
       
   109 				define(dest, name, res);
       
   110 			}
       
   111 		}
       
   112 		if (src) {
       
   113 			for (var name in src) {
       
   114 				if (src.hasOwnProperty(name) && !hidden.test(name))
       
   115 					field(name);
       
   116 			}
       
   117 			for (var name in beansNames) {
       
   118 				var part = beansNames[name],
       
   119 					set = dest['set' + part],
       
   120 					get = dest['get' + part] || set && dest['is' + part];
       
   121 				if (get && (beans === true || get.length === 0))
       
   122 					field(name, { get: get, set: set });
       
   123 			}
       
   124 		}
       
   125 		return dest;
       
   126 	}
       
   127 
       
   128 	function each(obj, iter, bind) {
       
   129 		if (obj)
       
   130 			('length' in obj && !obj.getLength
       
   131 					&& typeof obj.length === 'number'
       
   132 				? forEach
       
   133 				: forIn).call(obj, iter, bind = bind || obj);
       
   134 		return bind;
       
   135 	}
       
   136 
       
   137 	function set(obj, props, exclude) {
       
   138 		for (var key in props)
       
   139 			if (props.hasOwnProperty(key) && !(exclude && exclude[key]))
       
   140 				obj[key] = props[key];
       
   141 		return obj;
       
   142 	}
       
   143 
       
   144 	return inject(function Base() {
       
   145 		for (var i = 0, l = arguments.length; i < l; i++)
       
   146 			set(this, arguments[i]);
       
   147 	}, {
       
   148 		inject: function(src) {
       
   149 			if (src) {
       
   150 				var statics = src.statics === true ? src : src.statics,
       
   151 					beans = src.beans,
       
   152 					preserve = src.preserve;
       
   153 				if (statics !== src)
       
   154 					inject(this.prototype, src, src.enumerable, beans, preserve);
       
   155 				inject(this, statics, true, beans, preserve);
       
   156 			}
       
   157 			for (var i = 1, l = arguments.length; i < l; i++)
       
   158 				this.inject(arguments[i]);
       
   159 			return this;
       
   160 		},
       
   161 
       
   162 		extend: function() {
       
   163 			var base = this,
       
   164 				ctor;
       
   165 			for (var i = 0, l = arguments.length; i < l; i++)
       
   166 				if (ctor = arguments[i].initialize)
       
   167 					break;
       
   168 			ctor = ctor || function() {
       
   169 				base.apply(this, arguments);
       
   170 			};
       
   171 			ctor.prototype = create(this.prototype);
       
   172 			ctor.base = base;
       
   173 			define(ctor.prototype, 'constructor',
       
   174 					{ value: ctor, writable: true, configurable: true });
       
   175 			inject(ctor, this, true);
       
   176 			return arguments.length ? this.inject.apply(ctor, arguments) : ctor;
       
   177 		}
       
   178 	}, true).inject({
       
   179 		inject: function() {
       
   180 			for (var i = 0, l = arguments.length; i < l; i++) {
       
   181 				var src = arguments[i];
       
   182 				if (src)
       
   183 					inject(this, src, src.enumerable, src.beans, src.preserve);
       
   184 			}
       
   185 			return this;
       
   186 		},
       
   187 
       
   188 		extend: function() {
       
   189 			var res = create(this);
       
   190 			return res.inject.apply(res, arguments);
       
   191 		},
       
   192 
       
   193 		each: function(iter, bind) {
       
   194 			return each(this, iter, bind);
       
   195 		},
       
   196 
       
   197 		set: function(props) {
       
   198 			return set(this, props);
       
   199 		},
       
   200 
       
   201 		clone: function() {
       
   202 			return new this.constructor(this);
       
   203 		},
       
   204 
       
   205 		statics: {
       
   206 			each: each,
       
   207 			create: create,
       
   208 			define: define,
       
   209 			describe: describe,
       
   210 			set: set,
       
   211 
       
   212 			clone: function(obj) {
       
   213 				return set(new obj.constructor(), obj);
       
   214 			},
       
   215 
       
   216 			isPlainObject: function(obj) {
       
   217 				var ctor = obj != null && obj.constructor;
       
   218 				return ctor && (ctor === Object || ctor === Base
       
   219 						|| ctor.name === 'Object');
       
   220 			},
       
   221 
       
   222 			pick: function(a, b) {
       
   223 				return a !== undefined ? a : b;
       
   224 			}
       
   225 		}
       
   226 	});
       
   227 };
       
   228 
       
   229 if (typeof module !== 'undefined')
       
   230 	module.exports = Base;
       
   231 
       
   232 Base.inject({
       
   233 	toString: function() {
       
   234 		return this._id != null
       
   235 			?  (this._class || 'Object') + (this._name
       
   236 				? " '" + this._name + "'"
       
   237 				: ' @' + this._id)
       
   238 			: '{ ' + Base.each(this, function(value, key) {
       
   239 				if (!/^_/.test(key)) {
       
   240 					var type = typeof value;
       
   241 					this.push(key + ': ' + (type === 'number'
       
   242 							? Formatter.instance.number(value)
       
   243 							: type === 'string' ? "'" + value + "'" : value));
       
   244 				}
       
   245 			}, []).join(', ') + ' }';
       
   246 	},
       
   247 
       
   248 	getClassName: function() {
       
   249 		return this._class || '';
       
   250 	},
       
   251 
       
   252 	exportJSON: function(options) {
       
   253 		return Base.exportJSON(this, options);
       
   254 	},
       
   255 
       
   256 	toJSON: function() {
       
   257 		return Base.serialize(this);
       
   258 	},
       
   259 
       
   260 	_set: function(props, exclude, dontCheck) {
       
   261 		if (props && (dontCheck || Base.isPlainObject(props))) {
       
   262 			var orig = props._filtering || props;
       
   263 			for (var key in orig) {
       
   264 				if (orig.hasOwnProperty(key) && !(exclude && exclude[key])) {
       
   265 					var value = props[key];
       
   266 					if (value !== undefined)
       
   267 						this[key] = value;
       
   268 				}
       
   269 			}
       
   270 			return true;
       
   271 		}
       
   272 	},
       
   273 
       
   274 	statics: {
       
   275 
       
   276 		exports: {
       
   277 			enumerable: true
       
   278 		},
       
   279 
       
   280 		extend: function extend() {
       
   281 			var res = extend.base.apply(this, arguments),
       
   282 				name = res.prototype._class;
       
   283 			if (name && !Base.exports[name])
       
   284 				Base.exports[name] = res;
       
   285 			return res;
       
   286 		},
       
   287 
       
   288 		equals: function(obj1, obj2) {
       
   289 			function checkKeys(o1, o2) {
       
   290 				for (var i in o1)
       
   291 					if (o1.hasOwnProperty(i) && !o2.hasOwnProperty(i))
       
   292 						return false;
       
   293 				return true;
       
   294 			}
       
   295 			if (obj1 === obj2)
       
   296 				return true;
       
   297 			if (obj1 && obj1.equals)
       
   298 				return obj1.equals(obj2);
       
   299 			if (obj2 && obj2.equals)
       
   300 				return obj2.equals(obj1);
       
   301 			if (Array.isArray(obj1) && Array.isArray(obj2)) {
       
   302 				if (obj1.length !== obj2.length)
       
   303 					return false;
       
   304 				for (var i = 0, l = obj1.length; i < l; i++) {
       
   305 					if (!Base.equals(obj1[i], obj2[i]))
       
   306 						return false;
       
   307 				}
       
   308 				return true;
       
   309 			}
       
   310 			if (obj1 && typeof obj1 === 'object'
       
   311 					&& obj2 && typeof obj2 === 'object') {
       
   312 				if (!checkKeys(obj1, obj2) || !checkKeys(obj2, obj1))
       
   313 					return false;
       
   314 				for (var i in obj1) {
       
   315 					if (obj1.hasOwnProperty(i)
       
   316 							&& !Base.equals(obj1[i], obj2[i]))
       
   317 						return false;
       
   318 				}
       
   319 				return true;
       
   320 			}
       
   321 			return false;
       
   322 		},
       
   323 
       
   324 		read: function(list, start, options, length) {
       
   325 			if (this === Base) {
       
   326 				var value = this.peek(list, start);
       
   327 				list.__index++;
       
   328 				return value;
       
   329 			}
       
   330 			var proto = this.prototype,
       
   331 				readIndex = proto._readIndex,
       
   332 				index = start || readIndex && list.__index || 0;
       
   333 			if (!length)
       
   334 				length = list.length - index;
       
   335 			var obj = list[index];
       
   336 			if (obj instanceof this
       
   337 				|| options && options.readNull && obj == null && length <= 1) {
       
   338 				if (readIndex)
       
   339 					list.__index = index + 1;
       
   340 				return obj && options && options.clone ? obj.clone() : obj;
       
   341 			}
       
   342 			obj = Base.create(this.prototype);
       
   343 			if (readIndex)
       
   344 				obj.__read = true;
       
   345 			obj = obj.initialize.apply(obj, index > 0 || length < list.length
       
   346 				? Array.prototype.slice.call(list, index, index + length)
       
   347 				: list) || obj;
       
   348 			if (readIndex) {
       
   349 				list.__index = index + obj.__read;
       
   350 				obj.__read = undefined;
       
   351 			}
       
   352 			return obj;
       
   353 		},
       
   354 
       
   355 		peek: function(list, start) {
       
   356 			return list[list.__index = start || list.__index || 0];
       
   357 		},
       
   358 
       
   359 		remain: function(list) {
       
   360 			return list.length - (list.__index || 0);
       
   361 		},
       
   362 
       
   363 		readAll: function(list, start, options) {
       
   364 			var res = [],
       
   365 				entry;
       
   366 			for (var i = start || 0, l = list.length; i < l; i++) {
       
   367 				res.push(Array.isArray(entry = list[i])
       
   368 						? this.read(entry, 0, options)
       
   369 						: this.read(list, i, options, 1));
       
   370 			}
       
   371 			return res;
       
   372 		},
       
   373 
       
   374 		readNamed: function(list, name, start, options, length) {
       
   375 			var value = this.getNamed(list, name),
       
   376 				hasObject = value !== undefined;
       
   377 			if (hasObject) {
       
   378 				var filtered = list._filtered;
       
   379 				if (!filtered) {
       
   380 					filtered = list._filtered = Base.create(list[0]);
       
   381 					filtered._filtering = list[0];
       
   382 				}
       
   383 				filtered[name] = undefined;
       
   384 			}
       
   385 			return this.read(hasObject ? [value] : list, start, options, length);
       
   386 		},
       
   387 
       
   388 		getNamed: function(list, name) {
       
   389 			var arg = list[0];
       
   390 			if (list._hasObject === undefined)
       
   391 				list._hasObject = list.length === 1 && Base.isPlainObject(arg);
       
   392 			if (list._hasObject)
       
   393 				return name ? arg[name] : list._filtered || arg;
       
   394 		},
       
   395 
       
   396 		hasNamed: function(list, name) {
       
   397 			return !!this.getNamed(list, name);
       
   398 		},
       
   399 
       
   400 		isPlainValue: function(obj, asString) {
       
   401 			return this.isPlainObject(obj) || Array.isArray(obj)
       
   402 					|| asString && typeof obj === 'string';
       
   403 		},
       
   404 
       
   405 		serialize: function(obj, options, compact, dictionary) {
       
   406 			options = options || {};
       
   407 
       
   408 			var root = !dictionary,
       
   409 				res;
       
   410 			if (root) {
       
   411 				options.formatter = new Formatter(options.precision);
       
   412 				dictionary = {
       
   413 					length: 0,
       
   414 					definitions: {},
       
   415 					references: {},
       
   416 					add: function(item, create) {
       
   417 						var id = '#' + item._id,
       
   418 							ref = this.references[id];
       
   419 						if (!ref) {
       
   420 							this.length++;
       
   421 							var res = create.call(item),
       
   422 								name = item._class;
       
   423 							if (name && res[0] !== name)
       
   424 								res.unshift(name);
       
   425 							this.definitions[id] = res;
       
   426 							ref = this.references[id] = [id];
       
   427 						}
       
   428 						return ref;
       
   429 					}
       
   430 				};
       
   431 			}
       
   432 			if (obj && obj._serialize) {
       
   433 				res = obj._serialize(options, dictionary);
       
   434 				var name = obj._class;
       
   435 				if (name && !compact && !res._compact && res[0] !== name)
       
   436 					res.unshift(name);
       
   437 			} else if (Array.isArray(obj)) {
       
   438 				res = [];
       
   439 				for (var i = 0, l = obj.length; i < l; i++)
       
   440 					res[i] = Base.serialize(obj[i], options, compact,
       
   441 							dictionary);
       
   442 				if (compact)
       
   443 					res._compact = true;
       
   444 			} else if (Base.isPlainObject(obj)) {
       
   445 				res = {};
       
   446 				for (var i in obj)
       
   447 					if (obj.hasOwnProperty(i))
       
   448 						res[i] = Base.serialize(obj[i], options, compact,
       
   449 								dictionary);
       
   450 			} else if (typeof obj === 'number') {
       
   451 				res = options.formatter.number(obj, options.precision);
       
   452 			} else {
       
   453 				res = obj;
       
   454 			}
       
   455 			return root && dictionary.length > 0
       
   456 					? [['dictionary', dictionary.definitions], res]
       
   457 					: res;
       
   458 		},
       
   459 
       
   460 		deserialize: function(json, create, _data) {
       
   461 			var res = json,
       
   462 				isRoot = !_data;
       
   463 			_data = _data || {};
       
   464 			if (Array.isArray(json)) {
       
   465 				var type = json[0],
       
   466 					isDictionary = type === 'dictionary';
       
   467 				if (!isDictionary) {
       
   468 					if (_data.dictionary && json.length == 1 && /^#/.test(type))
       
   469 						return _data.dictionary[type];
       
   470 					type = Base.exports[type];
       
   471 				}
       
   472 				res = [];
       
   473 				for (var i = type ? 1 : 0, l = json.length; i < l; i++)
       
   474 					res.push(Base.deserialize(json[i], create, _data));
       
   475 				if (isDictionary) {
       
   476 					_data.dictionary = res[0];
       
   477 				} else if (type) {
       
   478 					var args = res;
       
   479 					if (create) {
       
   480 						res = create(type, args);
       
   481 					} else {
       
   482 						res = Base.create(type.prototype);
       
   483 						type.apply(res, args);
       
   484 					}
       
   485 				}
       
   486 			} else if (Base.isPlainObject(json)) {
       
   487 				res = {};
       
   488 				for (var key in json)
       
   489 					res[key] = Base.deserialize(json[key], create, _data);
       
   490 			}
       
   491 			return isRoot && json && json.length && json[0][0] === 'dictionary'
       
   492 					? res[1]
       
   493 					: res;
       
   494 		},
       
   495 
       
   496 		exportJSON: function(obj, options) {
       
   497 			var json = Base.serialize(obj, options);
       
   498 			return options && options.asString === false
       
   499 					? json
       
   500 					: JSON.stringify(json);
       
   501 		},
       
   502 
       
   503 		importJSON: function(json, target) {
       
   504 			return Base.deserialize(
       
   505 					typeof json === 'string' ? JSON.parse(json) : json,
       
   506 					function(type, args) {
       
   507 						var obj = target && target.constructor === type
       
   508 								? target
       
   509 								: Base.create(type.prototype),
       
   510 							isTarget = obj === target;
       
   511 						if (args.length === 1 && obj instanceof Item
       
   512 								&& (isTarget || !(obj instanceof Layer))) {
       
   513 							var arg = args[0];
       
   514 							if (Base.isPlainObject(arg))
       
   515 								arg.insert = false;
       
   516 						}
       
   517 						type.apply(obj, args);
       
   518 						if (isTarget)
       
   519 							target = null;
       
   520 						return obj;
       
   521 					});
       
   522 		},
       
   523 
       
   524 		splice: function(list, items, index, remove) {
       
   525 			var amount = items && items.length,
       
   526 				append = index === undefined;
       
   527 			index = append ? list.length : index;
       
   528 			if (index > list.length)
       
   529 				index = list.length;
       
   530 			for (var i = 0; i < amount; i++)
       
   531 				items[i]._index = index + i;
       
   532 			if (append) {
       
   533 				list.push.apply(list, items);
       
   534 				return [];
       
   535 			} else {
       
   536 				var args = [index, remove];
       
   537 				if (items)
       
   538 					args.push.apply(args, items);
       
   539 				var removed = list.splice.apply(list, args);
       
   540 				for (var i = 0, l = removed.length; i < l; i++)
       
   541 					removed[i]._index = undefined;
       
   542 				for (var i = index + amount, l = list.length; i < l; i++)
       
   543 					list[i]._index = i;
       
   544 				return removed;
       
   545 			}
       
   546 		},
       
   547 
       
   548 		capitalize: function(str) {
       
   549 			return str.replace(/\b[a-z]/g, function(match) {
       
   550 				return match.toUpperCase();
       
   551 			});
       
   552 		},
       
   553 
       
   554 		camelize: function(str) {
       
   555 			return str.replace(/-(.)/g, function(all, chr) {
       
   556 				return chr.toUpperCase();
       
   557 			});
       
   558 		},
       
   559 
       
   560 		hyphenate: function(str) {
       
   561 			return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
       
   562 		}
       
   563 	}
       
   564 });
       
   565 
       
   566 var Emitter = {
       
   567 	on: function(type, func) {
       
   568 		if (typeof type !== 'string') {
       
   569 			Base.each(type, function(value, key) {
       
   570 				this.on(key, value);
       
   571 			}, this);
       
   572 		} else {
       
   573 			var entry = this._eventTypes[type];
       
   574 			if (entry) {
       
   575 				var handlers = this._callbacks = this._callbacks || {};
       
   576 				handlers = handlers[type] = handlers[type] || [];
       
   577 				if (handlers.indexOf(func) === -1) {
       
   578 					handlers.push(func);
       
   579 					if (entry.install && handlers.length == 1)
       
   580 						entry.install.call(this, type);
       
   581 				}
       
   582 			}
       
   583 		}
       
   584 		return this;
       
   585 	},
       
   586 
       
   587 	off: function(type, func) {
       
   588 		if (typeof type !== 'string') {
       
   589 			Base.each(type, function(value, key) {
       
   590 				this.off(key, value);
       
   591 			}, this);
       
   592 			return;
       
   593 		}
       
   594 		var entry = this._eventTypes[type],
       
   595 			handlers = this._callbacks && this._callbacks[type],
       
   596 			index;
       
   597 		if (entry && handlers) {
       
   598 			if (!func || (index = handlers.indexOf(func)) !== -1
       
   599 					&& handlers.length === 1) {
       
   600 				if (entry.uninstall)
       
   601 					entry.uninstall.call(this, type);
       
   602 				delete this._callbacks[type];
       
   603 			} else if (index !== -1) {
       
   604 				handlers.splice(index, 1);
       
   605 			}
       
   606 		}
       
   607 		return this;
       
   608 	},
       
   609 
       
   610 	once: function(type, func) {
       
   611 		return this.on(type, function() {
       
   612 			func.apply(this, arguments);
       
   613 			this.off(type, func);
       
   614 		});
       
   615 	},
       
   616 
       
   617 	emit: function(type, event) {
       
   618 		var handlers = this._callbacks && this._callbacks[type];
       
   619 		if (!handlers)
       
   620 			return false;
       
   621 		var args = [].slice.call(arguments, 1);
       
   622 		for (var i = 0, l = handlers.length; i < l; i++) {
       
   623 			if (handlers[i].apply(this, args) === false
       
   624 					&& event && event.stop) {
       
   625 				event.stop();
       
   626 				break;
       
   627 			}
       
   628 		}
       
   629 		return true;
       
   630 	},
       
   631 
       
   632 	responds: function(type) {
       
   633 		return !!(this._callbacks && this._callbacks[type]);
       
   634 	},
       
   635 
       
   636 	attach: '#on',
       
   637 	detach: '#off',
       
   638 	fire: '#emit',
       
   639 
       
   640 	_installEvents: function(install) {
       
   641 		var handlers = this._callbacks,
       
   642 			key = install ? 'install' : 'uninstall';
       
   643 		for (var type in handlers) {
       
   644 			if (handlers[type].length > 0) {
       
   645 				var entry = this._eventTypes[type],
       
   646 					func = entry[key];
       
   647 				if (func)
       
   648 					func.call(this, type);
       
   649 			}
       
   650 		}
       
   651 	},
       
   652 
       
   653 	statics: {
       
   654 		inject: function inject(src) {
       
   655 			var events = src._events;
       
   656 			if (events) {
       
   657 				var types = {};
       
   658 				Base.each(events, function(entry, key) {
       
   659 					var isString = typeof entry === 'string',
       
   660 						name = isString ? entry : key,
       
   661 						part = Base.capitalize(name),
       
   662 						type = name.substring(2).toLowerCase();
       
   663 					types[type] = isString ? {} : entry;
       
   664 					name = '_' + name;
       
   665 					src['get' + part] = function() {
       
   666 						return this[name];
       
   667 					};
       
   668 					src['set' + part] = function(func) {
       
   669 						var prev = this[name];
       
   670 						if (prev)
       
   671 							this.off(type, prev);
       
   672 						if (func)
       
   673 							this.on(type, func);
       
   674 						this[name] = func;
       
   675 					};
       
   676 				});
       
   677 				src._eventTypes = types;
       
   678 			}
       
   679 			return inject.base.apply(this, arguments);
       
   680 		}
       
   681 	}
       
   682 };
       
   683 
       
   684 var PaperScope = Base.extend({
       
   685 	_class: 'PaperScope',
       
   686 
       
   687 	initialize: function PaperScope() {
       
   688 		paper = this;
       
   689 		this.settings = new Base({
       
   690 			applyMatrix: true,
       
   691 			handleSize: 4,
       
   692 			hitTolerance: 0
       
   693 		});
       
   694 		this.project = null;
       
   695 		this.projects = [];
       
   696 		this.tools = [];
       
   697 		this.palettes = [];
       
   698 		this._id = PaperScope._id++;
       
   699 		PaperScope._scopes[this._id] = this;
       
   700 		var proto = PaperScope.prototype;
       
   701 		if (!this.support) {
       
   702 			var ctx = CanvasProvider.getContext(1, 1);
       
   703 			proto.support = {
       
   704 				nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx,
       
   705 				nativeBlendModes: BlendMode.nativeModes
       
   706 			};
       
   707 			CanvasProvider.release(ctx);
       
   708 		}
       
   709 
       
   710 		if (!this.browser) {
       
   711 			var browser = proto.browser = {};
       
   712 			navigator.userAgent.toLowerCase().replace(
       
   713 				/(opera|chrome|safari|webkit|firefox|msie|trident|atom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:([.\d]+))?/g,
       
   714 				function(all, n, v1, v2, rv) {
       
   715 					if (!browser.chrome) {
       
   716 						var v = n === 'opera' ? v2 : v1;
       
   717 						if (n === 'trident') {
       
   718 							v = rv;
       
   719 							n = 'msie';
       
   720 						}
       
   721 						browser.version = v;
       
   722 						browser.versionNumber = parseFloat(v);
       
   723 						browser.name = n;
       
   724 						browser[n] = true;
       
   725 					}
       
   726 				}
       
   727 			);
       
   728 			if (browser.chrome)
       
   729 				delete browser.webkit;
       
   730 			if (browser.atom)
       
   731 				delete browser.chrome;
       
   732 		}
       
   733 	},
       
   734 
       
   735 	version: '0.9.22',
       
   736 
       
   737 	getView: function() {
       
   738 		return this.project && this.project.getView();
       
   739 	},
       
   740 
       
   741 	getPaper: function() {
       
   742 		return this;
       
   743 	},
       
   744 
       
   745 	execute: function(code, url, options) {
       
   746 		paper.PaperScript.execute(code, this, url, options);
       
   747 		View.updateFocus();
       
   748 	},
       
   749 
       
   750 	install: function(scope) {
       
   751 		var that = this;
       
   752 		Base.each(['project', 'view', 'tool'], function(key) {
       
   753 			Base.define(scope, key, {
       
   754 				configurable: true,
       
   755 				get: function() {
       
   756 					return that[key];
       
   757 				}
       
   758 			});
       
   759 		});
       
   760 		for (var key in this)
       
   761 			if (!/^_/.test(key) && this[key])
       
   762 				scope[key] = this[key];
       
   763 	},
       
   764 
       
   765 	setup: function(element) {
       
   766 		paper = this;
       
   767 		this.project = new Project(element);
       
   768 		return this;
       
   769 	},
       
   770 
       
   771 	activate: function() {
       
   772 		paper = this;
       
   773 	},
       
   774 
       
   775 	clear: function() {
       
   776 		for (var i = this.projects.length - 1; i >= 0; i--)
       
   777 			this.projects[i].remove();
       
   778 		for (var i = this.tools.length - 1; i >= 0; i--)
       
   779 			this.tools[i].remove();
       
   780 		for (var i = this.palettes.length - 1; i >= 0; i--)
       
   781 			this.palettes[i].remove();
       
   782 	},
       
   783 
       
   784 	remove: function() {
       
   785 		this.clear();
       
   786 		delete PaperScope._scopes[this._id];
       
   787 	},
       
   788 
       
   789 	statics: new function() {
       
   790 		function handleAttribute(name) {
       
   791 			name += 'Attribute';
       
   792 			return function(el, attr) {
       
   793 				return el[name](attr) || el[name]('data-paper-' + attr);
       
   794 			};
       
   795 		}
       
   796 
       
   797 		return {
       
   798 			_scopes: {},
       
   799 			_id: 0,
       
   800 
       
   801 			get: function(id) {
       
   802 				return this._scopes[id] || null;
       
   803 			},
       
   804 
       
   805 			getAttribute: handleAttribute('get'),
       
   806 			hasAttribute: handleAttribute('has')
       
   807 		};
       
   808 	}
       
   809 });
       
   810 
       
   811 var PaperScopeItem = Base.extend(Emitter, {
       
   812 
       
   813 	initialize: function(activate) {
       
   814 		this._scope = paper;
       
   815 		this._index = this._scope[this._list].push(this) - 1;
       
   816 		if (activate || !this._scope[this._reference])
       
   817 			this.activate();
       
   818 	},
       
   819 
       
   820 	activate: function() {
       
   821 		if (!this._scope)
       
   822 			return false;
       
   823 		var prev = this._scope[this._reference];
       
   824 		if (prev && prev !== this)
       
   825 			prev.emit('deactivate');
       
   826 		this._scope[this._reference] = this;
       
   827 		this.emit('activate', prev);
       
   828 		return true;
       
   829 	},
       
   830 
       
   831 	isActive: function() {
       
   832 		return this._scope[this._reference] === this;
       
   833 	},
       
   834 
       
   835 	remove: function() {
       
   836 		if (this._index == null)
       
   837 			return false;
       
   838 		Base.splice(this._scope[this._list], null, this._index, 1);
       
   839 		if (this._scope[this._reference] == this)
       
   840 			this._scope[this._reference] = null;
       
   841 		this._scope = null;
       
   842 		return true;
       
   843 	}
       
   844 });
       
   845 
       
   846 var Formatter = Base.extend({
       
   847 	initialize: function(precision) {
       
   848 		this.precision = precision || 5;
       
   849 		this.multiplier = Math.pow(10, this.precision);
       
   850 	},
       
   851 
       
   852 	number: function(val) {
       
   853 		return Math.round(val * this.multiplier) / this.multiplier;
       
   854 	},
       
   855 
       
   856 	pair: function(val1, val2, separator) {
       
   857 		return this.number(val1) + (separator || ',') + this.number(val2);
       
   858 	},
       
   859 
       
   860 	point: function(val, separator) {
       
   861 		return this.number(val.x) + (separator || ',') + this.number(val.y);
       
   862 	},
       
   863 
       
   864 	size: function(val, separator) {
       
   865 		return this.number(val.width) + (separator || ',')
       
   866 				+ this.number(val.height);
       
   867 	},
       
   868 
       
   869 	rectangle: function(val, separator) {
       
   870 		return this.point(val, separator) + (separator || ',')
       
   871 				+ this.size(val, separator);
       
   872 	}
       
   873 });
       
   874 
       
   875 Formatter.instance = new Formatter();
       
   876 
       
   877 var Numerical = new function() {
       
   878 
       
   879 	var abscissas = [
       
   880 		[  0.5773502691896257645091488],
       
   881 		[0,0.7745966692414833770358531],
       
   882 		[  0.3399810435848562648026658,0.8611363115940525752239465],
       
   883 		[0,0.5384693101056830910363144,0.9061798459386639927976269],
       
   884 		[  0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016],
       
   885 		[0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897],
       
   886 		[  0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609],
       
   887 		[0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762],
       
   888 		[  0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640],
       
   889 		[0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380],
       
   890 		[  0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491],
       
   891 		[0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294],
       
   892 		[  0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973],
       
   893 		[0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657],
       
   894 		[  0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542]
       
   895 	];
       
   896 
       
   897 	var weights = [
       
   898 		[1],
       
   899 		[0.8888888888888888888888889,0.5555555555555555555555556],
       
   900 		[0.6521451548625461426269361,0.3478548451374538573730639],
       
   901 		[0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640],
       
   902 		[0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961],
       
   903 		[0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114],
       
   904 		[0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314],
       
   905 		[0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922],
       
   906 		[0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688],
       
   907 		[0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537],
       
   908 		[0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160],
       
   909 		[0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216],
       
   910 		[0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329],
       
   911 		[0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284],
       
   912 		[0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806]
       
   913 	];
       
   914 
       
   915 	var abs = Math.abs,
       
   916 		sqrt = Math.sqrt,
       
   917 		pow = Math.pow,
       
   918 		TOLERANCE = 1e-6,
       
   919 		EPSILON = 1e-12,
       
   920 		MACHINE_EPSILON = 1.12e-16;
       
   921 
       
   922 	return {
       
   923 		TOLERANCE: TOLERANCE,
       
   924 		EPSILON: EPSILON,
       
   925 		MACHINE_EPSILON: MACHINE_EPSILON,
       
   926 		KAPPA: 4 * (sqrt(2) - 1) / 3,
       
   927 
       
   928 		isZero: function(val) {
       
   929 			return abs(val) <= EPSILON;
       
   930 		},
       
   931 
       
   932 		integrate: function(f, a, b, n) {
       
   933 			var x = abscissas[n - 2],
       
   934 				w = weights[n - 2],
       
   935 				A = (b - a) * 0.5,
       
   936 				B = A + a,
       
   937 				i = 0,
       
   938 				m = (n + 1) >> 1,
       
   939 				sum = n & 1 ? w[i++] * f(B) : 0;
       
   940 			while (i < m) {
       
   941 				var Ax = A * x[i];
       
   942 				sum += w[i++] * (f(B + Ax) + f(B - Ax));
       
   943 			}
       
   944 			return A * sum;
       
   945 		},
       
   946 
       
   947 		findRoot: function(f, df, x, a, b, n, tolerance) {
       
   948 			for (var i = 0; i < n; i++) {
       
   949 				var fx = f(x),
       
   950 					dx = fx / df(x),
       
   951 					nx = x - dx;
       
   952 				if (abs(dx) < tolerance)
       
   953 					return nx;
       
   954 				if (fx > 0) {
       
   955 					b = x;
       
   956 					x = nx <= a ? (a + b) * 0.5 : nx;
       
   957 				} else {
       
   958 					a = x;
       
   959 					x = nx >= b ? (a + b) * 0.5 : nx;
       
   960 				}
       
   961 			}
       
   962 			return x;
       
   963 		},
       
   964 
       
   965 		solveQuadratic: function(a, b, c, roots, min, max) {
       
   966 			var count = 0,
       
   967 				x1, x2 = Infinity,
       
   968 				B = b,
       
   969 				D;
       
   970 			b /= 2;
       
   971 			D = b * b - a * c;
       
   972 			if (abs(D) < MACHINE_EPSILON) {
       
   973 				var pow = Math.pow,
       
   974 					gmC = pow(abs(a*b*c), 1/3);
       
   975 				if (gmC < 1e-8) {
       
   976 					/*
       
   977 					 * we multiply with a factor to normalize the
       
   978 					 * coefficients. The factor is just the nearest exponent
       
   979 					 * of 10, big enough to raise all the coefficients to
       
   980 					 * nearly [-1, +1] range.
       
   981 					 */
       
   982 					var mult = pow(10, abs(
       
   983 						Math.floor(Math.log(gmC) * Math.LOG10E)));
       
   984 					if (!isFinite(mult))
       
   985 						mult = 0;
       
   986 					a *= mult;
       
   987 					b *= mult;
       
   988 					c *= mult;
       
   989 					D = b * b - a * c;
       
   990 				}
       
   991 			}
       
   992 			if (abs(a) < MACHINE_EPSILON) {
       
   993 				if (abs(B) < MACHINE_EPSILON)
       
   994 					return abs(c) < MACHINE_EPSILON ? -1 : 0;
       
   995 				x1 = -c / B;
       
   996 			} else {
       
   997 				if (D >= -MACHINE_EPSILON) {
       
   998 					D = D < 0 ? 0 : D;
       
   999 					var R = sqrt(D);
       
  1000 					if (b >= MACHINE_EPSILON && b <= MACHINE_EPSILON) {
       
  1001 						x1 = abs(a) >= abs(c) ? R / a : -c / R;
       
  1002 						x2 = -x1;
       
  1003 					} else {
       
  1004 						var q = -(b + (b < 0 ? -1 : 1) * R);
       
  1005 						x1 = q / a;
       
  1006 						x2 = c / q;
       
  1007 					}
       
  1008 				}
       
  1009 			}
       
  1010 			if (isFinite(x1) && (min == null || x1 >= min && x1 <= max))
       
  1011 				roots[count++] = x1;
       
  1012 			if (x2 !== x1
       
  1013 					&& isFinite(x2) && (min == null || x2 >= min && x2 <= max))
       
  1014 				roots[count++] = x2;
       
  1015 			return count;
       
  1016 		},
       
  1017 
       
  1018 		solveCubic: function(a, b, c, d, roots, min, max) {
       
  1019 			var x, b1, c2, count = 0;
       
  1020 			if (a === 0) {
       
  1021 				a = b;
       
  1022 				b1 = c;
       
  1023 				c2 = d;
       
  1024 				x = Infinity;
       
  1025 			} else if (d === 0) {
       
  1026 				b1 = b;
       
  1027 				c2 = c;
       
  1028 				x = 0;
       
  1029 			} else {
       
  1030 				var ec = 1 + MACHINE_EPSILON,
       
  1031 					x0, q, qd, t, r, s, tmp;
       
  1032 				x = -(b / a) / 3;
       
  1033 				tmp = a * x,
       
  1034 				b1 = tmp + b,
       
  1035 				c2 = b1 * x + c,
       
  1036 				qd = (tmp + b1) * x + c2,
       
  1037 				q = c2 * x + d;
       
  1038 				t = q /a;
       
  1039 				r = pow(abs(t), 1/3);
       
  1040 				s = t < 0 ? -1 : 1;
       
  1041 				t = -qd / a;
       
  1042 				r = t > 0 ? 1.3247179572 * Math.max(r, sqrt(t)) : r;
       
  1043 				x0 = x - s * r;
       
  1044 				if (x0 !== x) {
       
  1045 					do {
       
  1046 						x = x0;
       
  1047 						tmp = a * x,
       
  1048 						b1 = tmp + b,
       
  1049 						c2 = b1 * x + c,
       
  1050 						qd = (tmp + b1) * x + c2,
       
  1051 						q = c2 * x + d;
       
  1052 						x0 = qd === 0 ? x : x - q / qd / ec;
       
  1053 						if (x0 === x) {
       
  1054 							x = x0;
       
  1055 							break;
       
  1056 						}
       
  1057 					} while (s * x0 > s * x);
       
  1058 					if (abs(a) * x * x > abs(d / x)) {
       
  1059 						c2 = -d / x;
       
  1060 						b1 = (c2 - c) / x;
       
  1061 					}
       
  1062 				}
       
  1063 			}
       
  1064 			var count = Numerical.solveQuadratic(a, b1, c2, roots, min, max);
       
  1065 			if (isFinite(x) && (count === 0 || x !== roots[count - 1])
       
  1066 					&& (min == null || x >= min && x <= max))
       
  1067 				roots[count++] = x;
       
  1068 			return count;
       
  1069 		}
       
  1070 	};
       
  1071 };
       
  1072 
       
  1073 var Point = Base.extend({
       
  1074 	_class: 'Point',
       
  1075 	_readIndex: true,
       
  1076 
       
  1077 	initialize: function Point(arg0, arg1) {
       
  1078 		var type = typeof arg0;
       
  1079 		if (type === 'number') {
       
  1080 			var hasY = typeof arg1 === 'number';
       
  1081 			this.x = arg0;
       
  1082 			this.y = hasY ? arg1 : arg0;
       
  1083 			if (this.__read)
       
  1084 				this.__read = hasY ? 2 : 1;
       
  1085 		} else if (type === 'undefined' || arg0 === null) {
       
  1086 			this.x = this.y = 0;
       
  1087 			if (this.__read)
       
  1088 				this.__read = arg0 === null ? 1 : 0;
       
  1089 		} else {
       
  1090 			if (Array.isArray(arg0)) {
       
  1091 				this.x = arg0[0];
       
  1092 				this.y = arg0.length > 1 ? arg0[1] : arg0[0];
       
  1093 			} else if (arg0.x != null) {
       
  1094 				this.x = arg0.x;
       
  1095 				this.y = arg0.y;
       
  1096 			} else if (arg0.width != null) {
       
  1097 				this.x = arg0.width;
       
  1098 				this.y = arg0.height;
       
  1099 			} else if (arg0.angle != null) {
       
  1100 				this.x = arg0.length;
       
  1101 				this.y = 0;
       
  1102 				this.setAngle(arg0.angle);
       
  1103 			} else {
       
  1104 				this.x = this.y = 0;
       
  1105 				if (this.__read)
       
  1106 					this.__read = 0;
       
  1107 			}
       
  1108 			if (this.__read)
       
  1109 				this.__read = 1;
       
  1110 		}
       
  1111 	},
       
  1112 
       
  1113 	set: function(x, y) {
       
  1114 		this.x = x;
       
  1115 		this.y = y;
       
  1116 		return this;
       
  1117 	},
       
  1118 
       
  1119 	equals: function(point) {
       
  1120 		return this === point || point
       
  1121 				&& (this.x === point.x && this.y === point.y
       
  1122 					|| Array.isArray(point)
       
  1123 						&& this.x === point[0] && this.y === point[1])
       
  1124 				|| false;
       
  1125 	},
       
  1126 
       
  1127 	clone: function() {
       
  1128 		return new Point(this.x, this.y);
       
  1129 	},
       
  1130 
       
  1131 	toString: function() {
       
  1132 		var f = Formatter.instance;
       
  1133 		return '{ x: ' + f.number(this.x) + ', y: ' + f.number(this.y) + ' }';
       
  1134 	},
       
  1135 
       
  1136 	_serialize: function(options) {
       
  1137 		var f = options.formatter;
       
  1138 		return [f.number(this.x), f.number(this.y)];
       
  1139 	},
       
  1140 
       
  1141 	getLength: function() {
       
  1142 		return Math.sqrt(this.x * this.x + this.y * this.y);
       
  1143 	},
       
  1144 
       
  1145 	setLength: function(length) {
       
  1146 		if (this.isZero()) {
       
  1147 			var angle = this._angle || 0;
       
  1148 			this.set(
       
  1149 				Math.cos(angle) * length,
       
  1150 				Math.sin(angle) * length
       
  1151 			);
       
  1152 		} else {
       
  1153 			var scale = length / this.getLength();
       
  1154 			if (Numerical.isZero(scale))
       
  1155 				this.getAngle();
       
  1156 			this.set(
       
  1157 				this.x * scale,
       
  1158 				this.y * scale
       
  1159 			);
       
  1160 		}
       
  1161 	},
       
  1162 	getAngle: function() {
       
  1163 		return this.getAngleInRadians.apply(this, arguments) * 180 / Math.PI;
       
  1164 	},
       
  1165 
       
  1166 	setAngle: function(angle) {
       
  1167 		this.setAngleInRadians.call(this, angle * Math.PI / 180);
       
  1168 	},
       
  1169 
       
  1170 	getAngleInDegrees: '#getAngle',
       
  1171 	setAngleInDegrees: '#setAngle',
       
  1172 
       
  1173 	getAngleInRadians: function() {
       
  1174 		if (!arguments.length) {
       
  1175 			return this.isZero()
       
  1176 					? this._angle || 0
       
  1177 					: this._angle = Math.atan2(this.y, this.x);
       
  1178 		} else {
       
  1179 			var point = Point.read(arguments),
       
  1180 				div = this.getLength() * point.getLength();
       
  1181 			if (Numerical.isZero(div)) {
       
  1182 				return NaN;
       
  1183 			} else {
       
  1184 				var a = this.dot(point) / div;
       
  1185 				return Math.acos(a < -1 ? -1 : a > 1 ? 1 : a);
       
  1186 			}
       
  1187 		}
       
  1188 	},
       
  1189 
       
  1190 	setAngleInRadians: function(angle) {
       
  1191 		this._angle = angle;
       
  1192 		if (!this.isZero()) {
       
  1193 			var length = this.getLength();
       
  1194 			this.set(
       
  1195 				Math.cos(angle) * length,
       
  1196 				Math.sin(angle) * length
       
  1197 			);
       
  1198 		}
       
  1199 	},
       
  1200 
       
  1201 	getQuadrant: function() {
       
  1202 		return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3;
       
  1203 	}
       
  1204 }, {
       
  1205 	beans: false,
       
  1206 
       
  1207 	getDirectedAngle: function() {
       
  1208 		var point = Point.read(arguments);
       
  1209 		return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI;
       
  1210 	},
       
  1211 
       
  1212 	getDistance: function() {
       
  1213 		var point = Point.read(arguments),
       
  1214 			x = point.x - this.x,
       
  1215 			y = point.y - this.y,
       
  1216 			d = x * x + y * y,
       
  1217 			squared = Base.read(arguments);
       
  1218 		return squared ? d : Math.sqrt(d);
       
  1219 	},
       
  1220 
       
  1221 	normalize: function(length) {
       
  1222 		if (length === undefined)
       
  1223 			length = 1;
       
  1224 		var current = this.getLength(),
       
  1225 			scale = current !== 0 ? length / current : 0,
       
  1226 			point = new Point(this.x * scale, this.y * scale);
       
  1227 		if (scale >= 0)
       
  1228 			point._angle = this._angle;
       
  1229 		return point;
       
  1230 	},
       
  1231 
       
  1232 	rotate: function(angle, center) {
       
  1233 		if (angle === 0)
       
  1234 			return this.clone();
       
  1235 		angle = angle * Math.PI / 180;
       
  1236 		var point = center ? this.subtract(center) : this,
       
  1237 			s = Math.sin(angle),
       
  1238 			c = Math.cos(angle);
       
  1239 		point = new Point(
       
  1240 			point.x * c - point.y * s,
       
  1241 			point.x * s + point.y * c
       
  1242 		);
       
  1243 		return center ? point.add(center) : point;
       
  1244 	},
       
  1245 
       
  1246 	transform: function(matrix) {
       
  1247 		return matrix ? matrix._transformPoint(this) : this;
       
  1248 	},
       
  1249 
       
  1250 	add: function() {
       
  1251 		var point = Point.read(arguments);
       
  1252 		return new Point(this.x + point.x, this.y + point.y);
       
  1253 	},
       
  1254 
       
  1255 	subtract: function() {
       
  1256 		var point = Point.read(arguments);
       
  1257 		return new Point(this.x - point.x, this.y - point.y);
       
  1258 	},
       
  1259 
       
  1260 	multiply: function() {
       
  1261 		var point = Point.read(arguments);
       
  1262 		return new Point(this.x * point.x, this.y * point.y);
       
  1263 	},
       
  1264 
       
  1265 	divide: function() {
       
  1266 		var point = Point.read(arguments);
       
  1267 		return new Point(this.x / point.x, this.y / point.y);
       
  1268 	},
       
  1269 
       
  1270 	modulo: function() {
       
  1271 		var point = Point.read(arguments);
       
  1272 		return new Point(this.x % point.x, this.y % point.y);
       
  1273 	},
       
  1274 
       
  1275 	negate: function() {
       
  1276 		return new Point(-this.x, -this.y);
       
  1277 	},
       
  1278 
       
  1279 	isInside: function() {
       
  1280 		return Rectangle.read(arguments).contains(this);
       
  1281 	},
       
  1282 
       
  1283 	isClose: function(point, tolerance) {
       
  1284 		return this.getDistance(point) < tolerance;
       
  1285 	},
       
  1286 
       
  1287 	isColinear: function(point) {
       
  1288 		return Math.abs(this.cross(point)) < 1e-12;
       
  1289 	},
       
  1290 
       
  1291 	isOrthogonal: function(point) {
       
  1292 		return Math.abs(this.dot(point)) < 1e-12;
       
  1293 	},
       
  1294 
       
  1295 	isZero: function() {
       
  1296 		return Numerical.isZero(this.x) && Numerical.isZero(this.y);
       
  1297 	},
       
  1298 
       
  1299 	isNaN: function() {
       
  1300 		return isNaN(this.x) || isNaN(this.y);
       
  1301 	},
       
  1302 
       
  1303 	dot: function() {
       
  1304 		var point = Point.read(arguments);
       
  1305 		return this.x * point.x + this.y * point.y;
       
  1306 	},
       
  1307 
       
  1308 	cross: function() {
       
  1309 		var point = Point.read(arguments);
       
  1310 		return this.x * point.y - this.y * point.x;
       
  1311 	},
       
  1312 
       
  1313 	project: function() {
       
  1314 		var point = Point.read(arguments);
       
  1315 		if (point.isZero()) {
       
  1316 			return new Point(0, 0);
       
  1317 		} else {
       
  1318 			var scale = this.dot(point) / point.dot(point);
       
  1319 			return new Point(
       
  1320 				point.x * scale,
       
  1321 				point.y * scale
       
  1322 			);
       
  1323 		}
       
  1324 	},
       
  1325 
       
  1326 	statics: {
       
  1327 		min: function() {
       
  1328 			var point1 = Point.read(arguments),
       
  1329 				point2 = Point.read(arguments);
       
  1330 			return new Point(
       
  1331 				Math.min(point1.x, point2.x),
       
  1332 				Math.min(point1.y, point2.y)
       
  1333 			);
       
  1334 		},
       
  1335 
       
  1336 		max: function() {
       
  1337 			var point1 = Point.read(arguments),
       
  1338 				point2 = Point.read(arguments);
       
  1339 			return new Point(
       
  1340 				Math.max(point1.x, point2.x),
       
  1341 				Math.max(point1.y, point2.y)
       
  1342 			);
       
  1343 		},
       
  1344 
       
  1345 		random: function() {
       
  1346 			return new Point(Math.random(), Math.random());
       
  1347 		}
       
  1348 	}
       
  1349 }, Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
       
  1350 	var op = Math[name];
       
  1351 	this[name] = function() {
       
  1352 		return new Point(op(this.x), op(this.y));
       
  1353 	};
       
  1354 }, {}));
       
  1355 
       
  1356 var LinkedPoint = Point.extend({
       
  1357 	initialize: function Point(x, y, owner, setter) {
       
  1358 		this._x = x;
       
  1359 		this._y = y;
       
  1360 		this._owner = owner;
       
  1361 		this._setter = setter;
       
  1362 	},
       
  1363 
       
  1364 	set: function(x, y, _dontNotify) {
       
  1365 		this._x = x;
       
  1366 		this._y = y;
       
  1367 		if (!_dontNotify)
       
  1368 			this._owner[this._setter](this);
       
  1369 		return this;
       
  1370 	},
       
  1371 
       
  1372 	getX: function() {
       
  1373 		return this._x;
       
  1374 	},
       
  1375 
       
  1376 	setX: function(x) {
       
  1377 		this._x = x;
       
  1378 		this._owner[this._setter](this);
       
  1379 	},
       
  1380 
       
  1381 	getY: function() {
       
  1382 		return this._y;
       
  1383 	},
       
  1384 
       
  1385 	setY: function(y) {
       
  1386 		this._y = y;
       
  1387 		this._owner[this._setter](this);
       
  1388 	}
       
  1389 });
       
  1390 
       
  1391 var Size = Base.extend({
       
  1392 	_class: 'Size',
       
  1393 	_readIndex: true,
       
  1394 
       
  1395 	initialize: function Size(arg0, arg1) {
       
  1396 		var type = typeof arg0;
       
  1397 		if (type === 'number') {
       
  1398 			var hasHeight = typeof arg1 === 'number';
       
  1399 			this.width = arg0;
       
  1400 			this.height = hasHeight ? arg1 : arg0;
       
  1401 			if (this.__read)
       
  1402 				this.__read = hasHeight ? 2 : 1;
       
  1403 		} else if (type === 'undefined' || arg0 === null) {
       
  1404 			this.width = this.height = 0;
       
  1405 			if (this.__read)
       
  1406 				this.__read = arg0 === null ? 1 : 0;
       
  1407 		} else {
       
  1408 			if (Array.isArray(arg0)) {
       
  1409 				this.width = arg0[0];
       
  1410 				this.height = arg0.length > 1 ? arg0[1] : arg0[0];
       
  1411 			} else if (arg0.width != null) {
       
  1412 				this.width = arg0.width;
       
  1413 				this.height = arg0.height;
       
  1414 			} else if (arg0.x != null) {
       
  1415 				this.width = arg0.x;
       
  1416 				this.height = arg0.y;
       
  1417 			} else {
       
  1418 				this.width = this.height = 0;
       
  1419 				if (this.__read)
       
  1420 					this.__read = 0;
       
  1421 			}
       
  1422 			if (this.__read)
       
  1423 				this.__read = 1;
       
  1424 		}
       
  1425 	},
       
  1426 
       
  1427 	set: function(width, height) {
       
  1428 		this.width = width;
       
  1429 		this.height = height;
       
  1430 		return this;
       
  1431 	},
       
  1432 
       
  1433 	equals: function(size) {
       
  1434 		return size === this || size && (this.width === size.width
       
  1435 				&& this.height === size.height
       
  1436 				|| Array.isArray(size) && this.width === size[0]
       
  1437 					&& this.height === size[1]) || false;
       
  1438 	},
       
  1439 
       
  1440 	clone: function() {
       
  1441 		return new Size(this.width, this.height);
       
  1442 	},
       
  1443 
       
  1444 	toString: function() {
       
  1445 		var f = Formatter.instance;
       
  1446 		return '{ width: ' + f.number(this.width)
       
  1447 				+ ', height: ' + f.number(this.height) + ' }';
       
  1448 	},
       
  1449 
       
  1450 	_serialize: function(options) {
       
  1451 		var f = options.formatter;
       
  1452 		return [f.number(this.width),
       
  1453 				f.number(this.height)];
       
  1454 	},
       
  1455 
       
  1456 	add: function() {
       
  1457 		var size = Size.read(arguments);
       
  1458 		return new Size(this.width + size.width, this.height + size.height);
       
  1459 	},
       
  1460 
       
  1461 	subtract: function() {
       
  1462 		var size = Size.read(arguments);
       
  1463 		return new Size(this.width - size.width, this.height - size.height);
       
  1464 	},
       
  1465 
       
  1466 	multiply: function() {
       
  1467 		var size = Size.read(arguments);
       
  1468 		return new Size(this.width * size.width, this.height * size.height);
       
  1469 	},
       
  1470 
       
  1471 	divide: function() {
       
  1472 		var size = Size.read(arguments);
       
  1473 		return new Size(this.width / size.width, this.height / size.height);
       
  1474 	},
       
  1475 
       
  1476 	modulo: function() {
       
  1477 		var size = Size.read(arguments);
       
  1478 		return new Size(this.width % size.width, this.height % size.height);
       
  1479 	},
       
  1480 
       
  1481 	negate: function() {
       
  1482 		return new Size(-this.width, -this.height);
       
  1483 	},
       
  1484 
       
  1485 	isZero: function() {
       
  1486 		return Numerical.isZero(this.width) && Numerical.isZero(this.height);
       
  1487 	},
       
  1488 
       
  1489 	isNaN: function() {
       
  1490 		return isNaN(this.width) || isNaN(this.height);
       
  1491 	},
       
  1492 
       
  1493 	statics: {
       
  1494 		min: function(size1, size2) {
       
  1495 			return new Size(
       
  1496 				Math.min(size1.width, size2.width),
       
  1497 				Math.min(size1.height, size2.height));
       
  1498 		},
       
  1499 
       
  1500 		max: function(size1, size2) {
       
  1501 			return new Size(
       
  1502 				Math.max(size1.width, size2.width),
       
  1503 				Math.max(size1.height, size2.height));
       
  1504 		},
       
  1505 
       
  1506 		random: function() {
       
  1507 			return new Size(Math.random(), Math.random());
       
  1508 		}
       
  1509 	}
       
  1510 }, Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
       
  1511 	var op = Math[name];
       
  1512 	this[name] = function() {
       
  1513 		return new Size(op(this.width), op(this.height));
       
  1514 	};
       
  1515 }, {}));
       
  1516 
       
  1517 var LinkedSize = Size.extend({
       
  1518 	initialize: function Size(width, height, owner, setter) {
       
  1519 		this._width = width;
       
  1520 		this._height = height;
       
  1521 		this._owner = owner;
       
  1522 		this._setter = setter;
       
  1523 	},
       
  1524 
       
  1525 	set: function(width, height, _dontNotify) {
       
  1526 		this._width = width;
       
  1527 		this._height = height;
       
  1528 		if (!_dontNotify)
       
  1529 			this._owner[this._setter](this);
       
  1530 		return this;
       
  1531 	},
       
  1532 
       
  1533 	getWidth: function() {
       
  1534 		return this._width;
       
  1535 	},
       
  1536 
       
  1537 	setWidth: function(width) {
       
  1538 		this._width = width;
       
  1539 		this._owner[this._setter](this);
       
  1540 	},
       
  1541 
       
  1542 	getHeight: function() {
       
  1543 		return this._height;
       
  1544 	},
       
  1545 
       
  1546 	setHeight: function(height) {
       
  1547 		this._height = height;
       
  1548 		this._owner[this._setter](this);
       
  1549 	}
       
  1550 });
       
  1551 
       
  1552 var Rectangle = Base.extend({
       
  1553 	_class: 'Rectangle',
       
  1554 	_readIndex: true,
       
  1555 	beans: true,
       
  1556 
       
  1557 	initialize: function Rectangle(arg0, arg1, arg2, arg3) {
       
  1558 		var type = typeof arg0,
       
  1559 			read = 0;
       
  1560 		if (type === 'number') {
       
  1561 			this.x = arg0;
       
  1562 			this.y = arg1;
       
  1563 			this.width = arg2;
       
  1564 			this.height = arg3;
       
  1565 			read = 4;
       
  1566 		} else if (type === 'undefined' || arg0 === null) {
       
  1567 			this.x = this.y = this.width = this.height = 0;
       
  1568 			read = arg0 === null ? 1 : 0;
       
  1569 		} else if (arguments.length === 1) {
       
  1570 			if (Array.isArray(arg0)) {
       
  1571 				this.x = arg0[0];
       
  1572 				this.y = arg0[1];
       
  1573 				this.width = arg0[2];
       
  1574 				this.height = arg0[3];
       
  1575 				read = 1;
       
  1576 			} else if (arg0.x !== undefined || arg0.width !== undefined) {
       
  1577 				this.x = arg0.x || 0;
       
  1578 				this.y = arg0.y || 0;
       
  1579 				this.width = arg0.width || 0;
       
  1580 				this.height = arg0.height || 0;
       
  1581 				read = 1;
       
  1582 			} else if (arg0.from === undefined && arg0.to === undefined) {
       
  1583 				this.x = this.y = this.width = this.height = 0;
       
  1584 				this._set(arg0);
       
  1585 				read = 1;
       
  1586 			}
       
  1587 		}
       
  1588 		if (!read) {
       
  1589 			var point = Point.readNamed(arguments, 'from'),
       
  1590 				next = Base.peek(arguments);
       
  1591 			this.x = point.x;
       
  1592 			this.y = point.y;
       
  1593 			if (next && next.x !== undefined || Base.hasNamed(arguments, 'to')) {
       
  1594 				var to = Point.readNamed(arguments, 'to');
       
  1595 				this.width = to.x - point.x;
       
  1596 				this.height = to.y - point.y;
       
  1597 				if (this.width < 0) {
       
  1598 					this.x = to.x;
       
  1599 					this.width = -this.width;
       
  1600 				}
       
  1601 				if (this.height < 0) {
       
  1602 					this.y = to.y;
       
  1603 					this.height = -this.height;
       
  1604 				}
       
  1605 			} else {
       
  1606 				var size = Size.read(arguments);
       
  1607 				this.width = size.width;
       
  1608 				this.height = size.height;
       
  1609 			}
       
  1610 			read = arguments.__index;
       
  1611 		}
       
  1612 		if (this.__read)
       
  1613 			this.__read = read;
       
  1614 	},
       
  1615 
       
  1616 	set: function(x, y, width, height) {
       
  1617 		this.x = x;
       
  1618 		this.y = y;
       
  1619 		this.width = width;
       
  1620 		this.height = height;
       
  1621 		return this;
       
  1622 	},
       
  1623 
       
  1624 	clone: function() {
       
  1625 		return new Rectangle(this.x, this.y, this.width, this.height);
       
  1626 	},
       
  1627 
       
  1628 	equals: function(rect) {
       
  1629 		var rt = Base.isPlainValue(rect)
       
  1630 				? Rectangle.read(arguments)
       
  1631 				: rect;
       
  1632 		return rt === this
       
  1633 				|| rt && this.x === rt.x && this.y === rt.y
       
  1634 					&& this.width === rt.width && this.height === rt.height
       
  1635 				|| false;
       
  1636 	},
       
  1637 
       
  1638 	toString: function() {
       
  1639 		var f = Formatter.instance;
       
  1640 		return '{ x: ' + f.number(this.x)
       
  1641 				+ ', y: ' + f.number(this.y)
       
  1642 				+ ', width: ' + f.number(this.width)
       
  1643 				+ ', height: ' + f.number(this.height)
       
  1644 				+ ' }';
       
  1645 	},
       
  1646 
       
  1647 	_serialize: function(options) {
       
  1648 		var f = options.formatter;
       
  1649 		return [f.number(this.x),
       
  1650 				f.number(this.y),
       
  1651 				f.number(this.width),
       
  1652 				f.number(this.height)];
       
  1653 	},
       
  1654 
       
  1655 	getPoint: function(_dontLink) {
       
  1656 		var ctor = _dontLink ? Point : LinkedPoint;
       
  1657 		return new ctor(this.x, this.y, this, 'setPoint');
       
  1658 	},
       
  1659 
       
  1660 	setPoint: function() {
       
  1661 		var point = Point.read(arguments);
       
  1662 		this.x = point.x;
       
  1663 		this.y = point.y;
       
  1664 	},
       
  1665 
       
  1666 	getSize: function(_dontLink) {
       
  1667 		var ctor = _dontLink ? Size : LinkedSize;
       
  1668 		return new ctor(this.width, this.height, this, 'setSize');
       
  1669 	},
       
  1670 
       
  1671 	setSize: function() {
       
  1672 		var size = Size.read(arguments);
       
  1673 		if (this._fixX)
       
  1674 			this.x += (this.width - size.width) * this._fixX;
       
  1675 		if (this._fixY)
       
  1676 			this.y += (this.height - size.height) * this._fixY;
       
  1677 		this.width = size.width;
       
  1678 		this.height = size.height;
       
  1679 		this._fixW = 1;
       
  1680 		this._fixH = 1;
       
  1681 	},
       
  1682 
       
  1683 	getLeft: function() {
       
  1684 		return this.x;
       
  1685 	},
       
  1686 
       
  1687 	setLeft: function(left) {
       
  1688 		if (!this._fixW)
       
  1689 			this.width -= left - this.x;
       
  1690 		this.x = left;
       
  1691 		this._fixX = 0;
       
  1692 	},
       
  1693 
       
  1694 	getTop: function() {
       
  1695 		return this.y;
       
  1696 	},
       
  1697 
       
  1698 	setTop: function(top) {
       
  1699 		if (!this._fixH)
       
  1700 			this.height -= top - this.y;
       
  1701 		this.y = top;
       
  1702 		this._fixY = 0;
       
  1703 	},
       
  1704 
       
  1705 	getRight: function() {
       
  1706 		return this.x + this.width;
       
  1707 	},
       
  1708 
       
  1709 	setRight: function(right) {
       
  1710 		if (this._fixX !== undefined && this._fixX !== 1)
       
  1711 			this._fixW = 0;
       
  1712 		if (this._fixW)
       
  1713 			this.x = right - this.width;
       
  1714 		else
       
  1715 			this.width = right - this.x;
       
  1716 		this._fixX = 1;
       
  1717 	},
       
  1718 
       
  1719 	getBottom: function() {
       
  1720 		return this.y + this.height;
       
  1721 	},
       
  1722 
       
  1723 	setBottom: function(bottom) {
       
  1724 		if (this._fixY !== undefined && this._fixY !== 1)
       
  1725 			this._fixH = 0;
       
  1726 		if (this._fixH)
       
  1727 			this.y = bottom - this.height;
       
  1728 		else
       
  1729 			this.height = bottom - this.y;
       
  1730 		this._fixY = 1;
       
  1731 	},
       
  1732 
       
  1733 	getCenterX: function() {
       
  1734 		return this.x + this.width * 0.5;
       
  1735 	},
       
  1736 
       
  1737 	setCenterX: function(x) {
       
  1738 		this.x = x - this.width * 0.5;
       
  1739 		this._fixX = 0.5;
       
  1740 	},
       
  1741 
       
  1742 	getCenterY: function() {
       
  1743 		return this.y + this.height * 0.5;
       
  1744 	},
       
  1745 
       
  1746 	setCenterY: function(y) {
       
  1747 		this.y = y - this.height * 0.5;
       
  1748 		this._fixY = 0.5;
       
  1749 	},
       
  1750 
       
  1751 	getCenter: function(_dontLink) {
       
  1752 		var ctor = _dontLink ? Point : LinkedPoint;
       
  1753 		return new ctor(this.getCenterX(), this.getCenterY(), this, 'setCenter');
       
  1754 	},
       
  1755 
       
  1756 	setCenter: function() {
       
  1757 		var point = Point.read(arguments);
       
  1758 		this.setCenterX(point.x);
       
  1759 		this.setCenterY(point.y);
       
  1760 		return this;
       
  1761 	},
       
  1762 
       
  1763 	getArea: function() {
       
  1764 		return this.width * this.height;
       
  1765 	},
       
  1766 
       
  1767 	isEmpty: function() {
       
  1768 		return this.width === 0 || this.height === 0;
       
  1769 	},
       
  1770 
       
  1771 	contains: function(arg) {
       
  1772 		return arg && arg.width !== undefined
       
  1773 				|| (Array.isArray(arg) ? arg : arguments).length == 4
       
  1774 				? this._containsRectangle(Rectangle.read(arguments))
       
  1775 				: this._containsPoint(Point.read(arguments));
       
  1776 	},
       
  1777 
       
  1778 	_containsPoint: function(point) {
       
  1779 		var x = point.x,
       
  1780 			y = point.y;
       
  1781 		return x >= this.x && y >= this.y
       
  1782 				&& x <= this.x + this.width
       
  1783 				&& y <= this.y + this.height;
       
  1784 	},
       
  1785 
       
  1786 	_containsRectangle: function(rect) {
       
  1787 		var x = rect.x,
       
  1788 			y = rect.y;
       
  1789 		return x >= this.x && y >= this.y
       
  1790 				&& x + rect.width <= this.x + this.width
       
  1791 				&& y + rect.height <= this.y + this.height;
       
  1792 	},
       
  1793 
       
  1794 	intersects: function() {
       
  1795 		var rect = Rectangle.read(arguments);
       
  1796 		return rect.x + rect.width > this.x
       
  1797 				&& rect.y + rect.height > this.y
       
  1798 				&& rect.x < this.x + this.width
       
  1799 				&& rect.y < this.y + this.height;
       
  1800 	},
       
  1801 
       
  1802 	touches: function() {
       
  1803 		var rect = Rectangle.read(arguments);
       
  1804 		return rect.x + rect.width >= this.x
       
  1805 				&& rect.y + rect.height >= this.y
       
  1806 				&& rect.x <= this.x + this.width
       
  1807 				&& rect.y <= this.y + this.height;
       
  1808 	},
       
  1809 
       
  1810 	intersect: function() {
       
  1811 		var rect = Rectangle.read(arguments),
       
  1812 			x1 = Math.max(this.x, rect.x),
       
  1813 			y1 = Math.max(this.y, rect.y),
       
  1814 			x2 = Math.min(this.x + this.width, rect.x + rect.width),
       
  1815 			y2 = Math.min(this.y + this.height, rect.y + rect.height);
       
  1816 		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
       
  1817 	},
       
  1818 
       
  1819 	unite: function() {
       
  1820 		var rect = Rectangle.read(arguments),
       
  1821 			x1 = Math.min(this.x, rect.x),
       
  1822 			y1 = Math.min(this.y, rect.y),
       
  1823 			x2 = Math.max(this.x + this.width, rect.x + rect.width),
       
  1824 			y2 = Math.max(this.y + this.height, rect.y + rect.height);
       
  1825 		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
       
  1826 	},
       
  1827 
       
  1828 	include: function() {
       
  1829 		var point = Point.read(arguments);
       
  1830 		var x1 = Math.min(this.x, point.x),
       
  1831 			y1 = Math.min(this.y, point.y),
       
  1832 			x2 = Math.max(this.x + this.width, point.x),
       
  1833 			y2 = Math.max(this.y + this.height, point.y);
       
  1834 		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
       
  1835 	},
       
  1836 
       
  1837 	expand: function() {
       
  1838 		var amount = Size.read(arguments),
       
  1839 			hor = amount.width,
       
  1840 			ver = amount.height;
       
  1841 		return new Rectangle(this.x - hor / 2, this.y - ver / 2,
       
  1842 				this.width + hor, this.height + ver);
       
  1843 	},
       
  1844 
       
  1845 	scale: function(hor, ver) {
       
  1846 		return this.expand(this.width * hor - this.width,
       
  1847 				this.height * (ver === undefined ? hor : ver) - this.height);
       
  1848 	}
       
  1849 }, Base.each([
       
  1850 		['Top', 'Left'], ['Top', 'Right'],
       
  1851 		['Bottom', 'Left'], ['Bottom', 'Right'],
       
  1852 		['Left', 'Center'], ['Top', 'Center'],
       
  1853 		['Right', 'Center'], ['Bottom', 'Center']
       
  1854 	],
       
  1855 	function(parts, index) {
       
  1856 		var part = parts.join('');
       
  1857 		var xFirst = /^[RL]/.test(part);
       
  1858 		if (index >= 4)
       
  1859 			parts[1] += xFirst ? 'Y' : 'X';
       
  1860 		var x = parts[xFirst ? 0 : 1],
       
  1861 			y = parts[xFirst ? 1 : 0],
       
  1862 			getX = 'get' + x,
       
  1863 			getY = 'get' + y,
       
  1864 			setX = 'set' + x,
       
  1865 			setY = 'set' + y,
       
  1866 			get = 'get' + part,
       
  1867 			set = 'set' + part;
       
  1868 		this[get] = function(_dontLink) {
       
  1869 			var ctor = _dontLink ? Point : LinkedPoint;
       
  1870 			return new ctor(this[getX](), this[getY](), this, set);
       
  1871 		};
       
  1872 		this[set] = function() {
       
  1873 			var point = Point.read(arguments);
       
  1874 			this[setX](point.x);
       
  1875 			this[setY](point.y);
       
  1876 		};
       
  1877 	}, {
       
  1878 		beans: true
       
  1879 	}
       
  1880 ));
       
  1881 
       
  1882 var LinkedRectangle = Rectangle.extend({
       
  1883 	initialize: function Rectangle(x, y, width, height, owner, setter) {
       
  1884 		this.set(x, y, width, height, true);
       
  1885 		this._owner = owner;
       
  1886 		this._setter = setter;
       
  1887 	},
       
  1888 
       
  1889 	set: function(x, y, width, height, _dontNotify) {
       
  1890 		this._x = x;
       
  1891 		this._y = y;
       
  1892 		this._width = width;
       
  1893 		this._height = height;
       
  1894 		if (!_dontNotify)
       
  1895 			this._owner[this._setter](this);
       
  1896 		return this;
       
  1897 	}
       
  1898 }, new function() {
       
  1899 	var proto = Rectangle.prototype;
       
  1900 
       
  1901 	return Base.each(['x', 'y', 'width', 'height'], function(key) {
       
  1902 		var part = Base.capitalize(key);
       
  1903 		var internal = '_' + key;
       
  1904 		this['get' + part] = function() {
       
  1905 			return this[internal];
       
  1906 		};
       
  1907 
       
  1908 		this['set' + part] = function(value) {
       
  1909 			this[internal] = value;
       
  1910 			if (!this._dontNotify)
       
  1911 				this._owner[this._setter](this);
       
  1912 		};
       
  1913 	}, Base.each(['Point', 'Size', 'Center',
       
  1914 			'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY',
       
  1915 			'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight',
       
  1916 			'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'],
       
  1917 		function(key) {
       
  1918 			var name = 'set' + key;
       
  1919 			this[name] = function() {
       
  1920 				this._dontNotify = true;
       
  1921 				proto[name].apply(this, arguments);
       
  1922 				this._dontNotify = false;
       
  1923 				this._owner[this._setter](this);
       
  1924 			};
       
  1925 		}, {
       
  1926 			isSelected: function() {
       
  1927 				return this._owner._boundsSelected;
       
  1928 			},
       
  1929 
       
  1930 			setSelected: function(selected) {
       
  1931 				var owner = this._owner;
       
  1932 				if (owner.setSelected) {
       
  1933 					owner._boundsSelected = selected;
       
  1934 					owner.setSelected(selected || owner._selectedSegmentState > 0);
       
  1935 				}
       
  1936 			}
       
  1937 		})
       
  1938 	);
       
  1939 });
       
  1940 
       
  1941 var Matrix = Base.extend({
       
  1942 	_class: 'Matrix',
       
  1943 
       
  1944 	initialize: function Matrix(arg) {
       
  1945 		var count = arguments.length,
       
  1946 			ok = true;
       
  1947 		if (count === 6) {
       
  1948 			this.set.apply(this, arguments);
       
  1949 		} else if (count === 1) {
       
  1950 			if (arg instanceof Matrix) {
       
  1951 				this.set(arg._a, arg._c, arg._b, arg._d, arg._tx, arg._ty);
       
  1952 			} else if (Array.isArray(arg)) {
       
  1953 				this.set.apply(this, arg);
       
  1954 			} else {
       
  1955 				ok = false;
       
  1956 			}
       
  1957 		} else if (count === 0) {
       
  1958 			this.reset();
       
  1959 		} else {
       
  1960 			ok = false;
       
  1961 		}
       
  1962 		if (!ok)
       
  1963 			throw new Error('Unsupported matrix parameters');
       
  1964 	},
       
  1965 
       
  1966 	set: function(a, c, b, d, tx, ty, _dontNotify) {
       
  1967 		this._a = a;
       
  1968 		this._c = c;
       
  1969 		this._b = b;
       
  1970 		this._d = d;
       
  1971 		this._tx = tx;
       
  1972 		this._ty = ty;
       
  1973 		if (!_dontNotify)
       
  1974 			this._changed();
       
  1975 		return this;
       
  1976 	},
       
  1977 
       
  1978 	_serialize: function(options) {
       
  1979 		return Base.serialize(this.getValues(), options);
       
  1980 	},
       
  1981 
       
  1982 	_changed: function() {
       
  1983 		var owner = this._owner;
       
  1984 		if (owner) {
       
  1985 			if (owner._applyMatrix) {
       
  1986 				owner.transform(null, true);
       
  1987 			} else {
       
  1988 				owner._changed(9);
       
  1989 			}
       
  1990 		}
       
  1991 	},
       
  1992 
       
  1993 	clone: function() {
       
  1994 		return new Matrix(this._a, this._c, this._b, this._d,
       
  1995 				this._tx, this._ty);
       
  1996 	},
       
  1997 
       
  1998 	equals: function(mx) {
       
  1999 		return mx === this || mx && this._a === mx._a && this._b === mx._b
       
  2000 				&& this._c === mx._c && this._d === mx._d
       
  2001 				&& this._tx === mx._tx && this._ty === mx._ty
       
  2002 				|| false;
       
  2003 	},
       
  2004 
       
  2005 	toString: function() {
       
  2006 		var f = Formatter.instance;
       
  2007 		return '[[' + [f.number(this._a), f.number(this._b),
       
  2008 					f.number(this._tx)].join(', ') + '], ['
       
  2009 				+ [f.number(this._c), f.number(this._d),
       
  2010 					f.number(this._ty)].join(', ') + ']]';
       
  2011 	},
       
  2012 
       
  2013 	reset: function(_dontNotify) {
       
  2014 		this._a = this._d = 1;
       
  2015 		this._c = this._b = this._tx = this._ty = 0;
       
  2016 		if (!_dontNotify)
       
  2017 			this._changed();
       
  2018 		return this;
       
  2019 	},
       
  2020 
       
  2021 	apply: function(recursively, _setApplyMatrix) {
       
  2022 		var owner = this._owner;
       
  2023 		if (owner) {
       
  2024 			owner.transform(null, true, Base.pick(recursively, true),
       
  2025 					_setApplyMatrix);
       
  2026 			return this.isIdentity();
       
  2027 		}
       
  2028 		return false;
       
  2029 	},
       
  2030 
       
  2031 	translate: function() {
       
  2032 		var point = Point.read(arguments),
       
  2033 			x = point.x,
       
  2034 			y = point.y;
       
  2035 		this._tx += x * this._a + y * this._b;
       
  2036 		this._ty += x * this._c + y * this._d;
       
  2037 		this._changed();
       
  2038 		return this;
       
  2039 	},
       
  2040 
       
  2041 	scale: function() {
       
  2042 		var scale = Point.read(arguments),
       
  2043 			center = Point.read(arguments, 0, { readNull: true });
       
  2044 		if (center)
       
  2045 			this.translate(center);
       
  2046 		this._a *= scale.x;
       
  2047 		this._c *= scale.x;
       
  2048 		this._b *= scale.y;
       
  2049 		this._d *= scale.y;
       
  2050 		if (center)
       
  2051 			this.translate(center.negate());
       
  2052 		this._changed();
       
  2053 		return this;
       
  2054 	},
       
  2055 
       
  2056 	rotate: function(angle ) {
       
  2057 		angle *= Math.PI / 180;
       
  2058 		var center = Point.read(arguments, 1),
       
  2059 			x = center.x,
       
  2060 			y = center.y,
       
  2061 			cos = Math.cos(angle),
       
  2062 			sin = Math.sin(angle),
       
  2063 			tx = x - x * cos + y * sin,
       
  2064 			ty = y - x * sin - y * cos,
       
  2065 			a = this._a,
       
  2066 			b = this._b,
       
  2067 			c = this._c,
       
  2068 			d = this._d;
       
  2069 		this._a = cos * a + sin * b;
       
  2070 		this._b = -sin * a + cos * b;
       
  2071 		this._c = cos * c + sin * d;
       
  2072 		this._d = -sin * c + cos * d;
       
  2073 		this._tx += tx * a + ty * b;
       
  2074 		this._ty += tx * c + ty * d;
       
  2075 		this._changed();
       
  2076 		return this;
       
  2077 	},
       
  2078 
       
  2079 	shear: function() {
       
  2080 		var shear = Point.read(arguments),
       
  2081 			center = Point.read(arguments, 0, { readNull: true });
       
  2082 		if (center)
       
  2083 			this.translate(center);
       
  2084 		var a = this._a,
       
  2085 			c = this._c;
       
  2086 		this._a += shear.y * this._b;
       
  2087 		this._c += shear.y * this._d;
       
  2088 		this._b += shear.x * a;
       
  2089 		this._d += shear.x * c;
       
  2090 		if (center)
       
  2091 			this.translate(center.negate());
       
  2092 		this._changed();
       
  2093 		return this;
       
  2094 	},
       
  2095 
       
  2096 	skew: function() {
       
  2097 		var skew = Point.read(arguments),
       
  2098 			center = Point.read(arguments, 0, { readNull: true }),
       
  2099 			toRadians = Math.PI / 180,
       
  2100 			shear = new Point(Math.tan(skew.x * toRadians),
       
  2101 				Math.tan(skew.y * toRadians));
       
  2102 		return this.shear(shear, center);
       
  2103 	},
       
  2104 
       
  2105 	concatenate: function(mx) {
       
  2106 		var a1 = this._a,
       
  2107 			b1 = this._b,
       
  2108 			c1 = this._c,
       
  2109 			d1 = this._d,
       
  2110 			a2 = mx._a,
       
  2111 			b2 = mx._b,
       
  2112 			c2 = mx._c,
       
  2113 			d2 = mx._d,
       
  2114 			tx2 = mx._tx,
       
  2115 			ty2 = mx._ty;
       
  2116 		this._a = a2 * a1 + c2 * b1;
       
  2117 		this._b = b2 * a1 + d2 * b1;
       
  2118 		this._c = a2 * c1 + c2 * d1;
       
  2119 		this._d = b2 * c1 + d2 * d1;
       
  2120 		this._tx += tx2 * a1 + ty2 * b1;
       
  2121 		this._ty += tx2 * c1 + ty2 * d1;
       
  2122 		this._changed();
       
  2123 		return this;
       
  2124 	},
       
  2125 
       
  2126 	preConcatenate: function(mx) {
       
  2127 		var a1 = this._a,
       
  2128 			b1 = this._b,
       
  2129 			c1 = this._c,
       
  2130 			d1 = this._d,
       
  2131 			tx1 = this._tx,
       
  2132 			ty1 = this._ty,
       
  2133 			a2 = mx._a,
       
  2134 			b2 = mx._b,
       
  2135 			c2 = mx._c,
       
  2136 			d2 = mx._d,
       
  2137 			tx2 = mx._tx,
       
  2138 			ty2 = mx._ty;
       
  2139 		this._a = a2 * a1 + b2 * c1;
       
  2140 		this._b = a2 * b1 + b2 * d1;
       
  2141 		this._c = c2 * a1 + d2 * c1;
       
  2142 		this._d = c2 * b1 + d2 * d1;
       
  2143 		this._tx = a2 * tx1 + b2 * ty1 + tx2;
       
  2144 		this._ty = c2 * tx1 + d2 * ty1 + ty2;
       
  2145 		this._changed();
       
  2146 		return this;
       
  2147 	},
       
  2148 
       
  2149 	chain: function(mx) {
       
  2150 		var a1 = this._a,
       
  2151 			b1 = this._b,
       
  2152 			c1 = this._c,
       
  2153 			d1 = this._d,
       
  2154 			tx1 = this._tx,
       
  2155 			ty1 = this._ty,
       
  2156 			a2 = mx._a,
       
  2157 			b2 = mx._b,
       
  2158 			c2 = mx._c,
       
  2159 			d2 = mx._d,
       
  2160 			tx2 = mx._tx,
       
  2161 			ty2 = mx._ty;
       
  2162 		return new Matrix(
       
  2163 				a2 * a1 + c2 * b1,
       
  2164 				a2 * c1 + c2 * d1,
       
  2165 				b2 * a1 + d2 * b1,
       
  2166 				b2 * c1 + d2 * d1,
       
  2167 				tx1 + tx2 * a1 + ty2 * b1,
       
  2168 				ty1 + tx2 * c1 + ty2 * d1);
       
  2169 	},
       
  2170 
       
  2171 	isIdentity: function() {
       
  2172 		return this._a === 1 && this._c === 0 && this._b === 0 && this._d === 1
       
  2173 				&& this._tx === 0 && this._ty === 0;
       
  2174 	},
       
  2175 
       
  2176 	orNullIfIdentity: function() {
       
  2177 		return this.isIdentity() ? null : this;
       
  2178 	},
       
  2179 
       
  2180 	isInvertible: function() {
       
  2181 		return !!this._getDeterminant();
       
  2182 	},
       
  2183 
       
  2184 	isSingular: function() {
       
  2185 		return !this._getDeterminant();
       
  2186 	},
       
  2187 
       
  2188 	transform: function( src, dst, count) {
       
  2189 		return arguments.length < 3
       
  2190 			? this._transformPoint(Point.read(arguments))
       
  2191 			: this._transformCoordinates(src, dst, count);
       
  2192 	},
       
  2193 
       
  2194 	_transformPoint: function(point, dest, _dontNotify) {
       
  2195 		var x = point.x,
       
  2196 			y = point.y;
       
  2197 		if (!dest)
       
  2198 			dest = new Point();
       
  2199 		return dest.set(
       
  2200 			x * this._a + y * this._b + this._tx,
       
  2201 			x * this._c + y * this._d + this._ty,
       
  2202 			_dontNotify
       
  2203 		);
       
  2204 	},
       
  2205 
       
  2206 	_transformCoordinates: function(src, dst, count) {
       
  2207 		var i = 0,
       
  2208 			j = 0,
       
  2209 			max = 2 * count;
       
  2210 		while (i < max) {
       
  2211 			var x = src[i++],
       
  2212 				y = src[i++];
       
  2213 			dst[j++] = x * this._a + y * this._b + this._tx;
       
  2214 			dst[j++] = x * this._c + y * this._d + this._ty;
       
  2215 		}
       
  2216 		return dst;
       
  2217 	},
       
  2218 
       
  2219 	_transformCorners: function(rect) {
       
  2220 		var x1 = rect.x,
       
  2221 			y1 = rect.y,
       
  2222 			x2 = x1 + rect.width,
       
  2223 			y2 = y1 + rect.height,
       
  2224 			coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ];
       
  2225 		return this._transformCoordinates(coords, coords, 4);
       
  2226 	},
       
  2227 
       
  2228 	_transformBounds: function(bounds, dest, _dontNotify) {
       
  2229 		var coords = this._transformCorners(bounds),
       
  2230 			min = coords.slice(0, 2),
       
  2231 			max = coords.slice();
       
  2232 		for (var i = 2; i < 8; i++) {
       
  2233 			var val = coords[i],
       
  2234 				j = i & 1;
       
  2235 			if (val < min[j])
       
  2236 				min[j] = val;
       
  2237 			else if (val > max[j])
       
  2238 				max[j] = val;
       
  2239 		}
       
  2240 		if (!dest)
       
  2241 			dest = new Rectangle();
       
  2242 		return dest.set(min[0], min[1], max[0] - min[0], max[1] - min[1],
       
  2243 				_dontNotify);
       
  2244 	},
       
  2245 
       
  2246 	inverseTransform: function() {
       
  2247 		return this._inverseTransform(Point.read(arguments));
       
  2248 	},
       
  2249 
       
  2250 	_getDeterminant: function() {
       
  2251 		var det = this._a * this._d - this._b * this._c;
       
  2252 		return isFinite(det) && !Numerical.isZero(det)
       
  2253 				&& isFinite(this._tx) && isFinite(this._ty)
       
  2254 				? det : null;
       
  2255 	},
       
  2256 
       
  2257 	_inverseTransform: function(point, dest, _dontNotify) {
       
  2258 		var det = this._getDeterminant();
       
  2259 		if (!det)
       
  2260 			return null;
       
  2261 		var x = point.x - this._tx,
       
  2262 			y = point.y - this._ty;
       
  2263 		if (!dest)
       
  2264 			dest = new Point();
       
  2265 		return dest.set(
       
  2266 			(x * this._d - y * this._b) / det,
       
  2267 			(y * this._a - x * this._c) / det,
       
  2268 			_dontNotify
       
  2269 		);
       
  2270 	},
       
  2271 
       
  2272 	decompose: function() {
       
  2273 		var a = this._a, b = this._b, c = this._c, d = this._d;
       
  2274 		if (Numerical.isZero(a * d - b * c))
       
  2275 			return null;
       
  2276 
       
  2277 		var scaleX = Math.sqrt(a * a + b * b);
       
  2278 		a /= scaleX;
       
  2279 		b /= scaleX;
       
  2280 
       
  2281 		var shear = a * c + b * d;
       
  2282 		c -= a * shear;
       
  2283 		d -= b * shear;
       
  2284 
       
  2285 		var scaleY = Math.sqrt(c * c + d * d);
       
  2286 		c /= scaleY;
       
  2287 		d /= scaleY;
       
  2288 		shear /= scaleY;
       
  2289 
       
  2290 		if (a * d < b * c) {
       
  2291 			a = -a;
       
  2292 			b = -b;
       
  2293 			shear = -shear;
       
  2294 			scaleX = -scaleX;
       
  2295 		}
       
  2296 
       
  2297 		return {
       
  2298 			scaling: new Point(scaleX, scaleY),
       
  2299 			rotation: -Math.atan2(b, a) * 180 / Math.PI,
       
  2300 			shearing: shear
       
  2301 		};
       
  2302 	},
       
  2303 
       
  2304 	getValues: function() {
       
  2305 		return [ this._a, this._c, this._b, this._d, this._tx, this._ty ];
       
  2306 	},
       
  2307 
       
  2308 	getTranslation: function() {
       
  2309 		return new Point(this._tx, this._ty);
       
  2310 	},
       
  2311 
       
  2312 	getScaling: function() {
       
  2313 		return (this.decompose() || {}).scaling;
       
  2314 	},
       
  2315 
       
  2316 	getRotation: function() {
       
  2317 		return (this.decompose() || {}).rotation;
       
  2318 	},
       
  2319 
       
  2320 	inverted: function() {
       
  2321 		var det = this._getDeterminant();
       
  2322 		return det && new Matrix(
       
  2323 				this._d / det,
       
  2324 				-this._c / det,
       
  2325 				-this._b / det,
       
  2326 				this._a / det,
       
  2327 				(this._b * this._ty - this._d * this._tx) / det,
       
  2328 				(this._c * this._tx - this._a * this._ty) / det);
       
  2329 	},
       
  2330 
       
  2331 	shiftless: function() {
       
  2332 		return new Matrix(this._a, this._c, this._b, this._d, 0, 0);
       
  2333 	},
       
  2334 
       
  2335 	applyToContext: function(ctx) {
       
  2336 		ctx.transform(this._a, this._c, this._b, this._d, this._tx, this._ty);
       
  2337 	}
       
  2338 }, Base.each(['a', 'c', 'b', 'd', 'tx', 'ty'], function(name) {
       
  2339 	var part = Base.capitalize(name),
       
  2340 		prop = '_' + name;
       
  2341 	this['get' + part] = function() {
       
  2342 		return this[prop];
       
  2343 	};
       
  2344 	this['set' + part] = function(value) {
       
  2345 		this[prop] = value;
       
  2346 		this._changed();
       
  2347 	};
       
  2348 }, {}));
       
  2349 
       
  2350 var Line = Base.extend({
       
  2351 	_class: 'Line',
       
  2352 
       
  2353 	initialize: function Line(arg0, arg1, arg2, arg3, arg4) {
       
  2354 		var asVector = false;
       
  2355 		if (arguments.length >= 4) {
       
  2356 			this._px = arg0;
       
  2357 			this._py = arg1;
       
  2358 			this._vx = arg2;
       
  2359 			this._vy = arg3;
       
  2360 			asVector = arg4;
       
  2361 		} else {
       
  2362 			this._px = arg0.x;
       
  2363 			this._py = arg0.y;
       
  2364 			this._vx = arg1.x;
       
  2365 			this._vy = arg1.y;
       
  2366 			asVector = arg2;
       
  2367 		}
       
  2368 		if (!asVector) {
       
  2369 			this._vx -= this._px;
       
  2370 			this._vy -= this._py;
       
  2371 		}
       
  2372 	},
       
  2373 
       
  2374 	getPoint: function() {
       
  2375 		return new Point(this._px, this._py);
       
  2376 	},
       
  2377 
       
  2378 	getVector: function() {
       
  2379 		return new Point(this._vx, this._vy);
       
  2380 	},
       
  2381 
       
  2382 	getLength: function() {
       
  2383 		return this.getVector().getLength();
       
  2384 	},
       
  2385 
       
  2386 	intersect: function(line, isInfinite) {
       
  2387 		return Line.intersect(
       
  2388 				this._px, this._py, this._vx, this._vy,
       
  2389 				line._px, line._py, line._vx, line._vy,
       
  2390 				true, isInfinite);
       
  2391 	},
       
  2392 
       
  2393 	getSide: function(point) {
       
  2394 		return Line.getSide(
       
  2395 				this._px, this._py, this._vx, this._vy,
       
  2396 				point.x, point.y, true);
       
  2397 	},
       
  2398 
       
  2399 	getDistance: function(point) {
       
  2400 		return Math.abs(Line.getSignedDistance(
       
  2401 				this._px, this._py, this._vx, this._vy,
       
  2402 				point.x, point.y, true));
       
  2403 	},
       
  2404 
       
  2405 	statics: {
       
  2406 		intersect: function(apx, apy, avx, avy, bpx, bpy, bvx, bvy, asVector,
       
  2407 				isInfinite) {
       
  2408 			if (!asVector) {
       
  2409 				avx -= apx;
       
  2410 				avy -= apy;
       
  2411 				bvx -= bpx;
       
  2412 				bvy -= bpy;
       
  2413 			}
       
  2414 			var cross = avx * bvy - avy * bvx;
       
  2415 			if (!Numerical.isZero(cross)) {
       
  2416 				var dx = apx - bpx,
       
  2417 					dy = apy - bpy,
       
  2418 					ta = (bvx * dy - bvy * dx) / cross,
       
  2419 					tb = (avx * dy - avy * dx) / cross;
       
  2420 				if (isInfinite || 0 <= ta && ta <= 1 && 0 <= tb && tb <= 1)
       
  2421 					return new Point(
       
  2422 								apx + ta * avx,
       
  2423 								apy + ta * avy);
       
  2424 			}
       
  2425 		},
       
  2426 
       
  2427 		getSide: function(px, py, vx, vy, x, y, asVector) {
       
  2428 			if (!asVector) {
       
  2429 				vx -= px;
       
  2430 				vy -= py;
       
  2431 			}
       
  2432 			var v2x = x - px,
       
  2433 				v2y = y - py,
       
  2434 				ccw = v2x * vy - v2y * vx;
       
  2435 			if (ccw === 0) {
       
  2436 				ccw = v2x * vx + v2y * vy;
       
  2437 				if (ccw > 0) {
       
  2438 					v2x -= vx;
       
  2439 					v2y -= vy;
       
  2440 					ccw = v2x * vx + v2y * vy;
       
  2441 					if (ccw < 0)
       
  2442 						ccw = 0;
       
  2443 				}
       
  2444 			}
       
  2445 			return ccw < 0 ? -1 : ccw > 0 ? 1 : 0;
       
  2446 		},
       
  2447 
       
  2448 		getSignedDistance: function(px, py, vx, vy, x, y, asVector) {
       
  2449 			if (!asVector) {
       
  2450 				vx -= px;
       
  2451 				vy -= py;
       
  2452 			}
       
  2453 			return Numerical.isZero(vx)
       
  2454 					? vy >= 0 ? px - x : x - px
       
  2455 					: Numerical.isZero(vy)
       
  2456 						? vx >= 0 ? y - py : py - y
       
  2457 						: (vx * (y - py) - vy * (x - px)) / Math.sqrt(vx * vx + vy * vy);
       
  2458 		}
       
  2459 	}
       
  2460 });
       
  2461 
       
  2462 var Project = PaperScopeItem.extend({
       
  2463 	_class: 'Project',
       
  2464 	_list: 'projects',
       
  2465 	_reference: 'project',
       
  2466 
       
  2467 	initialize: function Project(element) {
       
  2468 		PaperScopeItem.call(this, true);
       
  2469 		this.layers = [];
       
  2470 		this._activeLayer = null;
       
  2471 		this.symbols = [];
       
  2472 		this._currentStyle = new Style(null, null, this);
       
  2473 		this._view = View.create(this,
       
  2474 				element || CanvasProvider.getCanvas(1, 1));
       
  2475 		this._selectedItems = {};
       
  2476 		this._selectedItemCount = 0;
       
  2477 		this._updateVersion = 0;
       
  2478 	},
       
  2479 
       
  2480 	_serialize: function(options, dictionary) {
       
  2481 		return Base.serialize(this.layers, options, true, dictionary);
       
  2482 	},
       
  2483 
       
  2484 	clear: function() {
       
  2485 		for (var i = this.layers.length - 1; i >= 0; i--)
       
  2486 			this.layers[i].remove();
       
  2487 		this.symbols = [];
       
  2488 	},
       
  2489 
       
  2490 	isEmpty: function() {
       
  2491 		return this.layers.length === 0;
       
  2492 	},
       
  2493 
       
  2494 	remove: function remove() {
       
  2495 		if (!remove.base.call(this))
       
  2496 			return false;
       
  2497 		if (this._view)
       
  2498 			this._view.remove();
       
  2499 		return true;
       
  2500 	},
       
  2501 
       
  2502 	getView: function() {
       
  2503 		return this._view;
       
  2504 	},
       
  2505 
       
  2506 	getCurrentStyle: function() {
       
  2507 		return this._currentStyle;
       
  2508 	},
       
  2509 
       
  2510 	setCurrentStyle: function(style) {
       
  2511 		this._currentStyle.initialize(style);
       
  2512 	},
       
  2513 
       
  2514 	getIndex: function() {
       
  2515 		return this._index;
       
  2516 	},
       
  2517 
       
  2518 	getOptions: function() {
       
  2519 		return this._scope.settings;
       
  2520 	},
       
  2521 
       
  2522 	getActiveLayer: function() {
       
  2523 		return this._activeLayer || new Layer({ project: this });
       
  2524 	},
       
  2525 
       
  2526 	getSelectedItems: function() {
       
  2527 		var items = [];
       
  2528 		for (var id in this._selectedItems) {
       
  2529 			var item = this._selectedItems[id];
       
  2530 			if (item.isInserted())
       
  2531 				items.push(item);
       
  2532 		}
       
  2533 		return items;
       
  2534 	},
       
  2535 
       
  2536 	insertChild: function(index, item, _preserve) {
       
  2537 		if (item instanceof Layer) {
       
  2538 			item._remove(false, true);
       
  2539 			Base.splice(this.layers, [item], index, 0);
       
  2540 			item._setProject(this, true);
       
  2541 			if (this._changes)
       
  2542 				item._changed(5);
       
  2543 			if (!this._activeLayer)
       
  2544 				this._activeLayer = item;
       
  2545 		} else if (item instanceof Item) {
       
  2546 			(this._activeLayer
       
  2547 				|| this.insertChild(index, new Layer(Item.NO_INSERT)))
       
  2548 					.insertChild(index, item, _preserve);
       
  2549 		} else {
       
  2550 			item = null;
       
  2551 		}
       
  2552 		return item;
       
  2553 	},
       
  2554 
       
  2555 	addChild: function(item, _preserve) {
       
  2556 		return this.insertChild(undefined, item, _preserve);
       
  2557 	},
       
  2558 
       
  2559 	_updateSelection: function(item) {
       
  2560 		var id = item._id,
       
  2561 			selectedItems = this._selectedItems;
       
  2562 		if (item._selected) {
       
  2563 			if (selectedItems[id] !== item) {
       
  2564 				this._selectedItemCount++;
       
  2565 				selectedItems[id] = item;
       
  2566 			}
       
  2567 		} else if (selectedItems[id] === item) {
       
  2568 			this._selectedItemCount--;
       
  2569 			delete selectedItems[id];
       
  2570 		}
       
  2571 	},
       
  2572 
       
  2573 	selectAll: function() {
       
  2574 		var layers = this.layers;
       
  2575 		for (var i = 0, l = layers.length; i < l; i++)
       
  2576 			layers[i].setFullySelected(true);
       
  2577 	},
       
  2578 
       
  2579 	deselectAll: function() {
       
  2580 		var selectedItems = this._selectedItems;
       
  2581 		for (var i in selectedItems)
       
  2582 			selectedItems[i].setFullySelected(false);
       
  2583 	},
       
  2584 
       
  2585 	hitTest: function() {
       
  2586 		var point = Point.read(arguments),
       
  2587 			options = HitResult.getOptions(Base.read(arguments));
       
  2588 		for (var i = this.layers.length - 1; i >= 0; i--) {
       
  2589 			var res = this.layers[i]._hitTest(point, options);
       
  2590 			if (res) return res;
       
  2591 		}
       
  2592 		return null;
       
  2593 	},
       
  2594 
       
  2595 	getItems: function(match) {
       
  2596 		return Item._getItems(this.layers, match);
       
  2597 	},
       
  2598 
       
  2599 	getItem: function(match) {
       
  2600 		return Item._getItems(this.layers, match, null, null, true)[0] || null;
       
  2601 	},
       
  2602 
       
  2603 	importJSON: function(json) {
       
  2604 		this.activate();
       
  2605 		var layer = this._activeLayer;
       
  2606 		return Base.importJSON(json, layer && layer.isEmpty() && layer);
       
  2607 	},
       
  2608 
       
  2609 	draw: function(ctx, matrix, pixelRatio) {
       
  2610 		this._updateVersion++;
       
  2611 		ctx.save();
       
  2612 		matrix.applyToContext(ctx);
       
  2613 		var param = new Base({
       
  2614 			offset: new Point(0, 0),
       
  2615 			pixelRatio: pixelRatio,
       
  2616 			viewMatrix: matrix.isIdentity() ? null : matrix,
       
  2617 			matrices: [new Matrix()],
       
  2618 			updateMatrix: true
       
  2619 		});
       
  2620 		for (var i = 0, layers = this.layers, l = layers.length; i < l; i++)
       
  2621 			layers[i].draw(ctx, param);
       
  2622 		ctx.restore();
       
  2623 
       
  2624 		if (this._selectedItemCount > 0) {
       
  2625 			ctx.save();
       
  2626 			ctx.strokeWidth = 1;
       
  2627 			var items = this._selectedItems,
       
  2628 				size = this._scope.settings.handleSize,
       
  2629 				version = this._updateVersion;
       
  2630 			for (var id in items)
       
  2631 				items[id]._drawSelection(ctx, matrix, size, items, version);
       
  2632 			ctx.restore();
       
  2633 		}
       
  2634 	}
       
  2635 });
       
  2636 
       
  2637 var Symbol = Base.extend({
       
  2638 	_class: 'Symbol',
       
  2639 
       
  2640 	initialize: function Symbol(item, dontCenter) {
       
  2641 		this._id = Symbol._id = (Symbol._id || 0) + 1;
       
  2642 		this.project = paper.project;
       
  2643 		this.project.symbols.push(this);
       
  2644 		if (item)
       
  2645 			this.setDefinition(item, dontCenter);
       
  2646 	},
       
  2647 
       
  2648 	_serialize: function(options, dictionary) {
       
  2649 		return dictionary.add(this, function() {
       
  2650 			return Base.serialize([this._class, this._definition],
       
  2651 					options, false, dictionary);
       
  2652 		});
       
  2653 	},
       
  2654 
       
  2655 	_changed: function(flags) {
       
  2656 		if (flags & 8) {
       
  2657 			Item._clearBoundsCache(this);
       
  2658 		}
       
  2659 		if (flags & 1) {
       
  2660 			this.project._needsUpdate = true;
       
  2661 		}
       
  2662 	},
       
  2663 
       
  2664 	getDefinition: function() {
       
  2665 		return this._definition;
       
  2666 	},
       
  2667 
       
  2668 	setDefinition: function(item, _dontCenter) {
       
  2669 		if (item._parentSymbol)
       
  2670 			item = item.clone();
       
  2671 		if (this._definition)
       
  2672 			this._definition._parentSymbol = null;
       
  2673 		this._definition = item;
       
  2674 		item.remove();
       
  2675 		item.setSelected(false);
       
  2676 		if (!_dontCenter)
       
  2677 			item.setPosition(new Point());
       
  2678 		item._parentSymbol = this;
       
  2679 		this._changed(9);
       
  2680 	},
       
  2681 
       
  2682 	place: function(position) {
       
  2683 		return new PlacedSymbol(this, position);
       
  2684 	},
       
  2685 
       
  2686 	clone: function() {
       
  2687 		return new Symbol(this._definition.clone(false));
       
  2688 	},
       
  2689 
       
  2690 	equals: function(symbol) {
       
  2691 		return symbol === this
       
  2692 				|| symbol && this.definition.equals(symbol.definition)
       
  2693 				|| false;
       
  2694 	}
       
  2695 });
       
  2696 
       
  2697 var Item = Base.extend(Emitter, {
       
  2698 	statics: {
       
  2699 		extend: function extend(src) {
       
  2700 			if (src._serializeFields)
       
  2701 				src._serializeFields = new Base(
       
  2702 						this.prototype._serializeFields, src._serializeFields);
       
  2703 			return extend.base.apply(this, arguments);
       
  2704 		},
       
  2705 
       
  2706 		NO_INSERT: { insert: false }
       
  2707 	},
       
  2708 
       
  2709 	_class: 'Item',
       
  2710 	_applyMatrix: true,
       
  2711 	_canApplyMatrix: true,
       
  2712 	_boundsSelected: false,
       
  2713 	_selectChildren: false,
       
  2714 	_serializeFields: {
       
  2715 		name: null,
       
  2716 		applyMatrix: null,
       
  2717 		matrix: new Matrix(),
       
  2718 		pivot: null,
       
  2719 		locked: false,
       
  2720 		visible: true,
       
  2721 		blendMode: 'normal',
       
  2722 		opacity: 1,
       
  2723 		guide: false,
       
  2724 		selected: false,
       
  2725 		clipMask: false,
       
  2726 		data: {}
       
  2727 	},
       
  2728 
       
  2729 	initialize: function Item() {
       
  2730 	},
       
  2731 
       
  2732 	_initialize: function(props, point) {
       
  2733 		var hasProps = props && Base.isPlainObject(props),
       
  2734 			internal = hasProps && props.internal === true,
       
  2735 			matrix = this._matrix = new Matrix(),
       
  2736 			project = hasProps && props.project || paper.project;
       
  2737 		if (!internal)
       
  2738 			this._id = Item._id = (Item._id || 0) + 1;
       
  2739 		this._applyMatrix = this._canApplyMatrix && paper.settings.applyMatrix;
       
  2740 		if (point)
       
  2741 			matrix.translate(point);
       
  2742 		matrix._owner = this;
       
  2743 		this._style = new Style(project._currentStyle, this, project);
       
  2744 		if (!this._project) {
       
  2745 			if (internal || hasProps && props.insert === false) {
       
  2746 				this._setProject(project);
       
  2747 			} else if (hasProps && props.parent) {
       
  2748 				this.setParent(props.parent);
       
  2749 			} else {
       
  2750 				(project._activeLayer || new Layer()).addChild(this);
       
  2751 			}
       
  2752 		}
       
  2753 		if (hasProps && props !== Item.NO_INSERT)
       
  2754 			this._set(props, { insert: true, parent: true }, true);
       
  2755 		return hasProps;
       
  2756 	},
       
  2757 
       
  2758 	_events: new function() {
       
  2759 
       
  2760 		var mouseFlags = {
       
  2761 			mousedown: {
       
  2762 				mousedown: 1,
       
  2763 				mousedrag: 1,
       
  2764 				click: 1,
       
  2765 				doubleclick: 1
       
  2766 			},
       
  2767 			mouseup: {
       
  2768 				mouseup: 1,
       
  2769 				mousedrag: 1,
       
  2770 				click: 1,
       
  2771 				doubleclick: 1
       
  2772 			},
       
  2773 			mousemove: {
       
  2774 				mousedrag: 1,
       
  2775 				mousemove: 1,
       
  2776 				mouseenter: 1,
       
  2777 				mouseleave: 1
       
  2778 			}
       
  2779 		};
       
  2780 
       
  2781 		var mouseEvent = {
       
  2782 			install: function(type) {
       
  2783 				var counters = this.getView()._eventCounters;
       
  2784 				if (counters) {
       
  2785 					for (var key in mouseFlags) {
       
  2786 						counters[key] = (counters[key] || 0)
       
  2787 								+ (mouseFlags[key][type] || 0);
       
  2788 					}
       
  2789 				}
       
  2790 			},
       
  2791 			uninstall: function(type) {
       
  2792 				var counters = this.getView()._eventCounters;
       
  2793 				if (counters) {
       
  2794 					for (var key in mouseFlags)
       
  2795 						counters[key] -= mouseFlags[key][type] || 0;
       
  2796 				}
       
  2797 			}
       
  2798 		};
       
  2799 
       
  2800 		return Base.each(['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick',
       
  2801 			'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave'],
       
  2802 			function(name) {
       
  2803 				this[name] = mouseEvent;
       
  2804 			}, {
       
  2805 				onFrame: {
       
  2806 					install: function() {
       
  2807 						this._animateItem(true);
       
  2808 					},
       
  2809 					uninstall: function() {
       
  2810 						this._animateItem(false);
       
  2811 					}
       
  2812 				},
       
  2813 
       
  2814 				onLoad: {}
       
  2815 			}
       
  2816 		);
       
  2817 	},
       
  2818 
       
  2819 	_animateItem: function(animate) {
       
  2820 		this.getView()._animateItem(this, animate);
       
  2821 	},
       
  2822 
       
  2823 	_serialize: function(options, dictionary) {
       
  2824 		var props = {},
       
  2825 			that = this;
       
  2826 
       
  2827 		function serialize(fields) {
       
  2828 			for (var key in fields) {
       
  2829 				var value = that[key];
       
  2830 				if (!Base.equals(value, key === 'leading'
       
  2831 						? fields.fontSize * 1.2 : fields[key])) {
       
  2832 					props[key] = Base.serialize(value, options,
       
  2833 							key !== 'data', dictionary);
       
  2834 				}
       
  2835 			}
       
  2836 		}
       
  2837 
       
  2838 		serialize(this._serializeFields);
       
  2839 		if (!(this instanceof Group))
       
  2840 			serialize(this._style._defaults);
       
  2841 		return [ this._class, props ];
       
  2842 	},
       
  2843 
       
  2844 	_changed: function(flags) {
       
  2845 		var symbol = this._parentSymbol,
       
  2846 			cacheParent = this._parent || symbol,
       
  2847 			project = this._project;
       
  2848 		if (flags & 8) {
       
  2849 			this._bounds = this._position = this._decomposed =
       
  2850 					this._globalMatrix = this._currentPath = undefined;
       
  2851 		}
       
  2852 		if (cacheParent
       
  2853 				&& (flags & 40)) {
       
  2854 			Item._clearBoundsCache(cacheParent);
       
  2855 		}
       
  2856 		if (flags & 2) {
       
  2857 			Item._clearBoundsCache(this);
       
  2858 		}
       
  2859 		if (project) {
       
  2860 			if (flags & 1) {
       
  2861 				project._needsUpdate = true;
       
  2862 			}
       
  2863 			if (project._changes) {
       
  2864 				var entry = project._changesById[this._id];
       
  2865 				if (entry) {
       
  2866 					entry.flags |= flags;
       
  2867 				} else {
       
  2868 					entry = { item: this, flags: flags };
       
  2869 					project._changesById[this._id] = entry;
       
  2870 					project._changes.push(entry);
       
  2871 				}
       
  2872 			}
       
  2873 		}
       
  2874 		if (symbol)
       
  2875 			symbol._changed(flags);
       
  2876 	},
       
  2877 
       
  2878 	set: function(props) {
       
  2879 		if (props)
       
  2880 			this._set(props);
       
  2881 		return this;
       
  2882 	},
       
  2883 
       
  2884 	getId: function() {
       
  2885 		return this._id;
       
  2886 	},
       
  2887 
       
  2888 	getName: function() {
       
  2889 		return this._name;
       
  2890 	},
       
  2891 
       
  2892 	setName: function(name, unique) {
       
  2893 
       
  2894 		if (this._name)
       
  2895 			this._removeNamed();
       
  2896 		if (name === (+name) + '')
       
  2897 			throw new Error(
       
  2898 					'Names consisting only of numbers are not supported.');
       
  2899 		var parent = this._parent;
       
  2900 		if (name && parent) {
       
  2901 			var children = parent._children,
       
  2902 				namedChildren = parent._namedChildren,
       
  2903 				orig = name,
       
  2904 				i = 1;
       
  2905 			while (unique && children[name])
       
  2906 				name = orig + ' ' + (i++);
       
  2907 			(namedChildren[name] = namedChildren[name] || []).push(this);
       
  2908 			children[name] = this;
       
  2909 		}
       
  2910 		this._name = name || undefined;
       
  2911 		this._changed(128);
       
  2912 	},
       
  2913 
       
  2914 	getStyle: function() {
       
  2915 		return this._style;
       
  2916 	},
       
  2917 
       
  2918 	setStyle: function(style) {
       
  2919 		this.getStyle().set(style);
       
  2920 	}
       
  2921 }, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'],
       
  2922 	function(name) {
       
  2923 		var part = Base.capitalize(name),
       
  2924 			name = '_' + name;
       
  2925 		this['get' + part] = function() {
       
  2926 			return this[name];
       
  2927 		};
       
  2928 		this['set' + part] = function(value) {
       
  2929 			if (value != this[name]) {
       
  2930 				this[name] = value;
       
  2931 				this._changed(name === '_locked'
       
  2932 						? 128 : 129);
       
  2933 			}
       
  2934 		};
       
  2935 	},
       
  2936 {}), {
       
  2937 	beans: true,
       
  2938 
       
  2939 	_locked: false,
       
  2940 
       
  2941 	_visible: true,
       
  2942 
       
  2943 	_blendMode: 'normal',
       
  2944 
       
  2945 	_opacity: 1,
       
  2946 
       
  2947 	_guide: false,
       
  2948 
       
  2949 	isSelected: function() {
       
  2950 		if (this._selectChildren) {
       
  2951 			var children = this._children;
       
  2952 			for (var i = 0, l = children.length; i < l; i++)
       
  2953 				if (children[i].isSelected())
       
  2954 					return true;
       
  2955 		}
       
  2956 		return this._selected;
       
  2957 	},
       
  2958 
       
  2959 	setSelected: function(selected, noChildren) {
       
  2960 		if (!noChildren && this._selectChildren) {
       
  2961 			var children = this._children;
       
  2962 			for (var i = 0, l = children.length; i < l; i++)
       
  2963 				children[i].setSelected(selected);
       
  2964 		}
       
  2965 		if ((selected = !!selected) ^ this._selected) {
       
  2966 			this._selected = selected;
       
  2967 			this._project._updateSelection(this);
       
  2968 			this._changed(129);
       
  2969 		}
       
  2970 	},
       
  2971 
       
  2972 	_selected: false,
       
  2973 
       
  2974 	isFullySelected: function() {
       
  2975 		var children = this._children;
       
  2976 		if (children && this._selected) {
       
  2977 			for (var i = 0, l = children.length; i < l; i++)
       
  2978 				if (!children[i].isFullySelected())
       
  2979 					return false;
       
  2980 			return true;
       
  2981 		}
       
  2982 		return this._selected;
       
  2983 	},
       
  2984 
       
  2985 	setFullySelected: function(selected) {
       
  2986 		var children = this._children;
       
  2987 		if (children) {
       
  2988 			for (var i = 0, l = children.length; i < l; i++)
       
  2989 				children[i].setFullySelected(selected);
       
  2990 		}
       
  2991 		this.setSelected(selected, true);
       
  2992 	},
       
  2993 
       
  2994 	isClipMask: function() {
       
  2995 		return this._clipMask;
       
  2996 	},
       
  2997 
       
  2998 	setClipMask: function(clipMask) {
       
  2999 		if (this._clipMask != (clipMask = !!clipMask)) {
       
  3000 			this._clipMask = clipMask;
       
  3001 			if (clipMask) {
       
  3002 				this.setFillColor(null);
       
  3003 				this.setStrokeColor(null);
       
  3004 			}
       
  3005 			this._changed(129);
       
  3006 			if (this._parent)
       
  3007 				this._parent._changed(1024);
       
  3008 		}
       
  3009 	},
       
  3010 
       
  3011 	_clipMask: false,
       
  3012 
       
  3013 	getData: function() {
       
  3014 		if (!this._data)
       
  3015 			this._data = {};
       
  3016 		return this._data;
       
  3017 	},
       
  3018 
       
  3019 	setData: function(data) {
       
  3020 		this._data = data;
       
  3021 	},
       
  3022 
       
  3023 	getPosition: function(_dontLink) {
       
  3024 		var position = this._position,
       
  3025 			ctor = _dontLink ? Point : LinkedPoint;
       
  3026 		if (!position) {
       
  3027 			var pivot = this._pivot;
       
  3028 			position = this._position = pivot
       
  3029 					? this._matrix._transformPoint(pivot)
       
  3030 					: this.getBounds().getCenter(true);
       
  3031 		}
       
  3032 		return new ctor(position.x, position.y, this, 'setPosition');
       
  3033 	},
       
  3034 
       
  3035 	setPosition: function() {
       
  3036 		this.translate(Point.read(arguments).subtract(this.getPosition(true)));
       
  3037 	},
       
  3038 
       
  3039 	getPivot: function(_dontLink) {
       
  3040 		var pivot = this._pivot;
       
  3041 		if (pivot) {
       
  3042 			var ctor = _dontLink ? Point : LinkedPoint;
       
  3043 			pivot = new ctor(pivot.x, pivot.y, this, 'setPivot');
       
  3044 		}
       
  3045 		return pivot;
       
  3046 	},
       
  3047 
       
  3048 	setPivot: function() {
       
  3049 		this._pivot = Point.read(arguments);
       
  3050 		this._position = undefined;
       
  3051 	},
       
  3052 
       
  3053 	_pivot: null,
       
  3054 
       
  3055 	getRegistration: '#getPivot',
       
  3056 	setRegistration: '#setPivot'
       
  3057 }, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds',
       
  3058 		'internalBounds', 'internalRoughBounds'],
       
  3059 	function(key) {
       
  3060 		var getter = 'get' + Base.capitalize(key),
       
  3061 			match = key.match(/^internal(.*)$/),
       
  3062 			internalGetter = match ? 'get' + match[1] : null;
       
  3063 		this[getter] = function(_matrix) {
       
  3064 			var boundsGetter = this._boundsGetter,
       
  3065 				name = !internalGetter && (typeof boundsGetter === 'string'
       
  3066 						? boundsGetter : boundsGetter && boundsGetter[getter])
       
  3067 						|| getter,
       
  3068 				bounds = this._getCachedBounds(name, _matrix, this,
       
  3069 						internalGetter);
       
  3070 			return key === 'bounds'
       
  3071 					? new LinkedRectangle(bounds.x, bounds.y, bounds.width,
       
  3072 							bounds.height, this, 'setBounds')
       
  3073 					: bounds;
       
  3074 		};
       
  3075 	},
       
  3076 {
       
  3077 	beans: true,
       
  3078 
       
  3079 	_getBounds: function(getter, matrix, cacheItem) {
       
  3080 		var children = this._children;
       
  3081 		if (!children || children.length == 0)
       
  3082 			return new Rectangle();
       
  3083 		var x1 = Infinity,
       
  3084 			x2 = -x1,
       
  3085 			y1 = x1,
       
  3086 			y2 = x2;
       
  3087 		for (var i = 0, l = children.length; i < l; i++) {
       
  3088 			var child = children[i];
       
  3089 			if (child._visible && !child.isEmpty()) {
       
  3090 				var rect = child._getCachedBounds(getter,
       
  3091 						matrix && matrix.chain(child._matrix), cacheItem);
       
  3092 				x1 = Math.min(rect.x, x1);
       
  3093 				y1 = Math.min(rect.y, y1);
       
  3094 				x2 = Math.max(rect.x + rect.width, x2);
       
  3095 				y2 = Math.max(rect.y + rect.height, y2);
       
  3096 			}
       
  3097 		}
       
  3098 		return isFinite(x1)
       
  3099 				? new Rectangle(x1, y1, x2 - x1, y2 - y1)
       
  3100 				: new Rectangle();
       
  3101 	},
       
  3102 
       
  3103 	setBounds: function() {
       
  3104 		var rect = Rectangle.read(arguments),
       
  3105 			bounds = this.getBounds(),
       
  3106 			matrix = new Matrix(),
       
  3107 			center = rect.getCenter();
       
  3108 		matrix.translate(center);
       
  3109 		if (rect.width != bounds.width || rect.height != bounds.height) {
       
  3110 			matrix.scale(
       
  3111 					bounds.width != 0 ? rect.width / bounds.width : 1,
       
  3112 					bounds.height != 0 ? rect.height / bounds.height : 1);
       
  3113 		}
       
  3114 		center = bounds.getCenter();
       
  3115 		matrix.translate(-center.x, -center.y);
       
  3116 		this.transform(matrix);
       
  3117 	},
       
  3118 
       
  3119 	_getCachedBounds: function(getter, matrix, cacheItem, internalGetter) {
       
  3120 		matrix = matrix && matrix.orNullIfIdentity();
       
  3121 		var _matrix = internalGetter ? null : this._matrix.orNullIfIdentity(),
       
  3122 			cache = (!matrix || matrix.equals(_matrix)) && getter;
       
  3123 		var cacheParent = this._parent || this._parentSymbol;
       
  3124 		if (cacheParent) {
       
  3125 			var id = cacheItem._id,
       
  3126 				ref = cacheParent._boundsCache = cacheParent._boundsCache || {
       
  3127 					ids: {},
       
  3128 					list: []
       
  3129 				};
       
  3130 			if (!ref.ids[id]) {
       
  3131 				ref.list.push(cacheItem);
       
  3132 				ref.ids[id] = cacheItem;
       
  3133 			}
       
  3134 		}
       
  3135 		if (cache && this._bounds && this._bounds[cache])
       
  3136 			return this._bounds[cache].clone();
       
  3137 		var bounds = this._getBounds(internalGetter || getter,
       
  3138 				matrix || _matrix, cacheItem);
       
  3139 		if (cache) {
       
  3140 			if (!this._bounds)
       
  3141 				this._bounds = {};
       
  3142 			var cached = this._bounds[cache] = bounds.clone();
       
  3143 			cached._internal = !!internalGetter;
       
  3144 		}
       
  3145 		return bounds;
       
  3146 	},
       
  3147 
       
  3148 	statics: {
       
  3149 		_clearBoundsCache: function(item) {
       
  3150 			var cache = item._boundsCache;
       
  3151 			if (cache) {
       
  3152 				item._bounds = item._position = item._boundsCache = undefined;
       
  3153 				for (var i = 0, list = cache.list, l = list.length; i < l; i++) {
       
  3154 					var other = list[i];
       
  3155 					if (other !== item) {
       
  3156 						other._bounds = other._position = undefined;
       
  3157 						if (other._boundsCache)
       
  3158 							Item._clearBoundsCache(other);
       
  3159 					}
       
  3160 				}
       
  3161 			}
       
  3162 		}
       
  3163 	}
       
  3164 
       
  3165 }), {
       
  3166 	beans: true,
       
  3167 
       
  3168 	_decompose: function() {
       
  3169 		return this._decomposed = this._matrix.decompose();
       
  3170 	},
       
  3171 
       
  3172 	getRotation: function() {
       
  3173 		var decomposed = this._decomposed || this._decompose();
       
  3174 		return decomposed && decomposed.rotation;
       
  3175 	},
       
  3176 
       
  3177 	setRotation: function(rotation) {
       
  3178 		var current = this.getRotation();
       
  3179 		if (current != null && rotation != null) {
       
  3180 			var decomposed = this._decomposed;
       
  3181 			this.rotate(rotation - current);
       
  3182 			decomposed.rotation = rotation;
       
  3183 			this._decomposed = decomposed;
       
  3184 		}
       
  3185 	},
       
  3186 
       
  3187 	getScaling: function(_dontLink) {
       
  3188 		var decomposed = this._decomposed || this._decompose(),
       
  3189 			scaling = decomposed && decomposed.scaling,
       
  3190 			ctor = _dontLink ? Point : LinkedPoint;
       
  3191 		return scaling && new ctor(scaling.x, scaling.y, this, 'setScaling');
       
  3192 	},
       
  3193 
       
  3194 	setScaling: function() {
       
  3195 		var current = this.getScaling();
       
  3196 		if (current) {
       
  3197 			var scaling = Point.read(arguments, 0, { clone: true }),
       
  3198 				decomposed = this._decomposed;
       
  3199 			this.scale(scaling.x / current.x, scaling.y / current.y);
       
  3200 			decomposed.scaling = scaling;
       
  3201 			this._decomposed = decomposed;
       
  3202 		}
       
  3203 	},
       
  3204 
       
  3205 	getMatrix: function() {
       
  3206 		return this._matrix;
       
  3207 	},
       
  3208 
       
  3209 	setMatrix: function(matrix) {
       
  3210 		this._matrix.initialize(matrix);
       
  3211 		if (this._applyMatrix) {
       
  3212 			this.transform(null, true);
       
  3213 		} else {
       
  3214 			this._changed(9);
       
  3215 		}
       
  3216 	},
       
  3217 
       
  3218 	getGlobalMatrix: function(_dontClone) {
       
  3219 		var matrix = this._globalMatrix,
       
  3220 			updateVersion = this._project._updateVersion;
       
  3221 		if (matrix && matrix._updateVersion !== updateVersion)
       
  3222 			matrix = null;
       
  3223 		if (!matrix) {
       
  3224 			matrix = this._globalMatrix = this._matrix.clone();
       
  3225 			var parent = this._parent;
       
  3226 			if (parent)
       
  3227 				matrix.preConcatenate(parent.getGlobalMatrix(true));
       
  3228 			matrix._updateVersion = updateVersion;
       
  3229 		}
       
  3230 		return _dontClone ? matrix : matrix.clone();
       
  3231 	},
       
  3232 
       
  3233 	getApplyMatrix: function() {
       
  3234 		return this._applyMatrix;
       
  3235 	},
       
  3236 
       
  3237 	setApplyMatrix: function(apply) {
       
  3238 		if (this._applyMatrix = this._canApplyMatrix && !!apply)
       
  3239 			this.transform(null, true);
       
  3240 	},
       
  3241 
       
  3242 	getTransformContent: '#getApplyMatrix',
       
  3243 	setTransformContent: '#setApplyMatrix',
       
  3244 }, {
       
  3245 	getProject: function() {
       
  3246 		return this._project;
       
  3247 	},
       
  3248 
       
  3249 	_setProject: function(project, installEvents) {
       
  3250 		if (this._project !== project) {
       
  3251 			if (this._project)
       
  3252 				this._installEvents(false);
       
  3253 			this._project = project;
       
  3254 			var children = this._children;
       
  3255 			for (var i = 0, l = children && children.length; i < l; i++)
       
  3256 				children[i]._setProject(project);
       
  3257 			installEvents = true;
       
  3258 		}
       
  3259 		if (installEvents)
       
  3260 			this._installEvents(true);
       
  3261 	},
       
  3262 
       
  3263 	getView: function() {
       
  3264 		return this._project.getView();
       
  3265 	},
       
  3266 
       
  3267 	_installEvents: function _installEvents(install) {
       
  3268 		_installEvents.base.call(this, install);
       
  3269 		var children = this._children;
       
  3270 		for (var i = 0, l = children && children.length; i < l; i++)
       
  3271 			children[i]._installEvents(install);
       
  3272 	},
       
  3273 
       
  3274 	getLayer: function() {
       
  3275 		var parent = this;
       
  3276 		while (parent = parent._parent) {
       
  3277 			if (parent instanceof Layer)
       
  3278 				return parent;
       
  3279 		}
       
  3280 		return null;
       
  3281 	},
       
  3282 
       
  3283 	getParent: function() {
       
  3284 		return this._parent;
       
  3285 	},
       
  3286 
       
  3287 	setParent: function(item) {
       
  3288 		return item.addChild(this);
       
  3289 	},
       
  3290 
       
  3291 	getChildren: function() {
       
  3292 		return this._children;
       
  3293 	},
       
  3294 
       
  3295 	setChildren: function(items) {
       
  3296 		this.removeChildren();
       
  3297 		this.addChildren(items);
       
  3298 	},
       
  3299 
       
  3300 	getFirstChild: function() {
       
  3301 		return this._children && this._children[0] || null;
       
  3302 	},
       
  3303 
       
  3304 	getLastChild: function() {
       
  3305 		return this._children && this._children[this._children.length - 1]
       
  3306 				|| null;
       
  3307 	},
       
  3308 
       
  3309 	getNextSibling: function() {
       
  3310 		return this._parent && this._parent._children[this._index + 1] || null;
       
  3311 	},
       
  3312 
       
  3313 	getPreviousSibling: function() {
       
  3314 		return this._parent && this._parent._children[this._index - 1] || null;
       
  3315 	},
       
  3316 
       
  3317 	getIndex: function() {
       
  3318 		return this._index;
       
  3319 	},
       
  3320 
       
  3321 	equals: function(item) {
       
  3322 		return item === this || item && this._class === item._class
       
  3323 				&& this._style.equals(item._style)
       
  3324 				&& this._matrix.equals(item._matrix)
       
  3325 				&& this._locked === item._locked
       
  3326 				&& this._visible === item._visible
       
  3327 				&& this._blendMode === item._blendMode
       
  3328 				&& this._opacity === item._opacity
       
  3329 				&& this._clipMask === item._clipMask
       
  3330 				&& this._guide === item._guide
       
  3331 				&& this._equals(item)
       
  3332 				|| false;
       
  3333 	},
       
  3334 
       
  3335 	_equals: function(item) {
       
  3336 		return Base.equals(this._children, item._children);
       
  3337 	},
       
  3338 
       
  3339 	clone: function(insert) {
       
  3340 		return this._clone(new this.constructor(Item.NO_INSERT), insert);
       
  3341 	},
       
  3342 
       
  3343 	_clone: function(copy, insert) {
       
  3344 		copy.setStyle(this._style);
       
  3345 		if (this._children) {
       
  3346 			for (var i = 0, l = this._children.length; i < l; i++)
       
  3347 				copy.addChild(this._children[i].clone(false), true);
       
  3348 		}
       
  3349 		if (insert || insert === undefined)
       
  3350 			copy.insertAbove(this);
       
  3351 		var keys = ['_locked', '_visible', '_blendMode', '_opacity',
       
  3352 				'_clipMask', '_guide', '_applyMatrix'];
       
  3353 		for (var i = 0, l = keys.length; i < l; i++) {
       
  3354 			var key = keys[i];
       
  3355 			if (this.hasOwnProperty(key))
       
  3356 				copy[key] = this[key];
       
  3357 		}
       
  3358 		copy._matrix.initialize(this._matrix);
       
  3359 		copy._data = this._data ? Base.clone(this._data) : null;
       
  3360 		copy.setSelected(this._selected);
       
  3361 		if (this._name)
       
  3362 			copy.setName(this._name, true);
       
  3363 		return copy;
       
  3364 	},
       
  3365 
       
  3366 	copyTo: function(itemOrProject) {
       
  3367 		return itemOrProject.addChild(this.clone(false));
       
  3368 	},
       
  3369 
       
  3370 	rasterize: function(resolution) {
       
  3371 		var bounds = this.getStrokeBounds(),
       
  3372 			scale = (resolution || this.getView().getResolution()) / 72,
       
  3373 			topLeft = bounds.getTopLeft().floor(),
       
  3374 			bottomRight = bounds.getBottomRight().ceil(),
       
  3375 			size = new Size(bottomRight.subtract(topLeft)),
       
  3376 			canvas = CanvasProvider.getCanvas(size.multiply(scale)),
       
  3377 			ctx = canvas.getContext('2d'),
       
  3378 			matrix = new Matrix().scale(scale).translate(topLeft.negate());
       
  3379 		ctx.save();
       
  3380 		matrix.applyToContext(ctx);
       
  3381 		this.draw(ctx, new Base({ matrices: [matrix] }));
       
  3382 		ctx.restore();
       
  3383 		var raster = new Raster(Item.NO_INSERT);
       
  3384 		raster.setCanvas(canvas);
       
  3385 		raster.transform(new Matrix().translate(topLeft.add(size.divide(2)))
       
  3386 				.scale(1 / scale));
       
  3387 		raster.insertAbove(this);
       
  3388 		return raster;
       
  3389 	},
       
  3390 
       
  3391 	contains: function() {
       
  3392 		return !!this._contains(
       
  3393 				this._matrix._inverseTransform(Point.read(arguments)));
       
  3394 	},
       
  3395 
       
  3396 	_contains: function(point) {
       
  3397 		if (this._children) {
       
  3398 			for (var i = this._children.length - 1; i >= 0; i--) {
       
  3399 				if (this._children[i].contains(point))
       
  3400 					return true;
       
  3401 			}
       
  3402 			return false;
       
  3403 		}
       
  3404 		return point.isInside(this.getInternalBounds());
       
  3405 	},
       
  3406 
       
  3407 	isInside: function() {
       
  3408 		return Rectangle.read(arguments).contains(this.getBounds());
       
  3409 	},
       
  3410 
       
  3411 	_asPathItem: function() {
       
  3412 		return new Path.Rectangle({
       
  3413 			rectangle: this.getInternalBounds(),
       
  3414 			matrix: this._matrix,
       
  3415 			insert: false,
       
  3416 		});
       
  3417 	},
       
  3418 
       
  3419 	intersects: function(item, _matrix) {
       
  3420 		if (!(item instanceof Item))
       
  3421 			return false;
       
  3422 		return this._asPathItem().getIntersections(item._asPathItem(),
       
  3423 				_matrix || item._matrix).length > 0;
       
  3424 	},
       
  3425 
       
  3426 	hitTest: function() {
       
  3427 		return this._hitTest(
       
  3428 				Point.read(arguments),
       
  3429 				HitResult.getOptions(Base.read(arguments)));
       
  3430 	},
       
  3431 
       
  3432 	_hitTest: function(point, options) {
       
  3433 		if (this._locked || !this._visible || this._guide && !options.guides
       
  3434 				|| this.isEmpty())
       
  3435 			return null;
       
  3436 
       
  3437 		var matrix = this._matrix,
       
  3438 			parentTotalMatrix = options._totalMatrix,
       
  3439 			view = this.getView(),
       
  3440 			totalMatrix = options._totalMatrix = parentTotalMatrix
       
  3441 					? parentTotalMatrix.chain(matrix)
       
  3442 					: this.getGlobalMatrix().preConcatenate(view._matrix),
       
  3443 			tolerancePadding = options._tolerancePadding = new Size(
       
  3444 						Path._getPenPadding(1, totalMatrix.inverted())
       
  3445 					).multiply(
       
  3446 						Math.max(options.tolerance, 0.000001)
       
  3447 					);
       
  3448 		point = matrix._inverseTransform(point);
       
  3449 
       
  3450 		if (!this._children && !this.getInternalRoughBounds()
       
  3451 				.expand(tolerancePadding.multiply(2))._containsPoint(point))
       
  3452 			return null;
       
  3453 		var checkSelf = !(options.guides && !this._guide
       
  3454 				|| options.selected && !this._selected
       
  3455 				|| options.type && options.type !== Base.hyphenate(this._class)
       
  3456 				|| options.class && !(this instanceof options.class)),
       
  3457 			that = this,
       
  3458 			res;
       
  3459 
       
  3460 		function checkBounds(type, part) {
       
  3461 			var pt = bounds['get' + part]();
       
  3462 			if (point.subtract(pt).divide(tolerancePadding).length <= 1)
       
  3463 				return new HitResult(type, that,
       
  3464 						{ name: Base.hyphenate(part), point: pt });
       
  3465 		}
       
  3466 
       
  3467 		if (checkSelf && (options.center || options.bounds) && this._parent) {
       
  3468 			var bounds = this.getInternalBounds();
       
  3469 			if (options.center)
       
  3470 				res = checkBounds('center', 'Center');
       
  3471 			if (!res && options.bounds) {
       
  3472 				var points = [
       
  3473 					'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight',
       
  3474 					'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'
       
  3475 				];
       
  3476 				for (var i = 0; i < 8 && !res; i++)
       
  3477 					res = checkBounds('bounds', points[i]);
       
  3478 			}
       
  3479 		}
       
  3480 
       
  3481 		var children = !res && this._children;
       
  3482 		if (children) {
       
  3483 			var opts = this._getChildHitTestOptions(options);
       
  3484 			for (var i = children.length - 1; i >= 0 && !res; i--)
       
  3485 				res = children[i]._hitTest(point, opts);
       
  3486 		}
       
  3487 		if (!res && checkSelf)
       
  3488 			res = this._hitTestSelf(point, options);
       
  3489 		if (res && res.point)
       
  3490 			res.point = matrix.transform(res.point);
       
  3491 		options._totalMatrix = parentTotalMatrix;
       
  3492 		return res;
       
  3493 	},
       
  3494 
       
  3495 	_getChildHitTestOptions: function(options) {
       
  3496 		return options;
       
  3497 	},
       
  3498 
       
  3499 	_hitTestSelf: function(point, options) {
       
  3500 		if (options.fill && this.hasFill() && this._contains(point))
       
  3501 			return new HitResult('fill', this);
       
  3502 	},
       
  3503 
       
  3504 	matches: function(name, compare) {
       
  3505 		function matchObject(obj1, obj2) {
       
  3506 			for (var i in obj1) {
       
  3507 				if (obj1.hasOwnProperty(i)) {
       
  3508 					var val1 = obj1[i],
       
  3509 						val2 = obj2[i];
       
  3510 					if (Base.isPlainObject(val1) && Base.isPlainObject(val2)) {
       
  3511 						if (!matchObject(val1, val2))
       
  3512 							return false;
       
  3513 					} else if (!Base.equals(val1, val2)) {
       
  3514 						return false;
       
  3515 					}
       
  3516 				}
       
  3517 			}
       
  3518 			return true;
       
  3519 		}
       
  3520 		if (typeof name === 'object') {
       
  3521 			for (var key in name) {
       
  3522 				if (name.hasOwnProperty(key) && !this.matches(key, name[key]))
       
  3523 					return false;
       
  3524 			}
       
  3525 		} else {
       
  3526 			var value = /^(empty|editable)$/.test(name)
       
  3527 					? this['is' + Base.capitalize(name)]()
       
  3528 					: name === 'type'
       
  3529 						? Base.hyphenate(this._class)
       
  3530 						: this[name];
       
  3531 			if (/^(constructor|class)$/.test(name)) {
       
  3532 				if (!(this instanceof compare))
       
  3533 					return false;
       
  3534 			} else if (compare instanceof RegExp) {
       
  3535 				if (!compare.test(value))
       
  3536 					return false;
       
  3537 			} else if (typeof compare === 'function') {
       
  3538 				if (!compare(value))
       
  3539 					return false;
       
  3540 			} else if (Base.isPlainObject(compare)) {
       
  3541 				if (!matchObject(compare, value))
       
  3542 					return false;
       
  3543 			} else if (!Base.equals(value, compare)) {
       
  3544 				return false;
       
  3545 			}
       
  3546 		}
       
  3547 		return true;
       
  3548 	},
       
  3549 
       
  3550 	getItems: function(match) {
       
  3551 		return Item._getItems(this._children, match, this._matrix);
       
  3552 	},
       
  3553 
       
  3554 	getItem: function(match) {
       
  3555 		return Item._getItems(this._children, match, this._matrix, null, true)
       
  3556 				[0] || null;
       
  3557 	},
       
  3558 
       
  3559 	statics: {
       
  3560 		_getItems: function _getItems(children, match, matrix, param,
       
  3561 				firstOnly) {
       
  3562 			if (!param) {
       
  3563 				var overlapping = match.overlapping,
       
  3564 					inside = match.inside,
       
  3565 					bounds = overlapping || inside,
       
  3566 					rect =	bounds && Rectangle.read([bounds]);
       
  3567 				param = {
       
  3568 					items: [],
       
  3569 					inside: rect,
       
  3570 					overlapping: overlapping && new Path.Rectangle({
       
  3571 						rectangle: rect,
       
  3572 						insert: false
       
  3573 					})
       
  3574 				};
       
  3575 				if (bounds)
       
  3576 					match = Base.set({}, match,
       
  3577 							{ inside: true, overlapping: true });
       
  3578 			}
       
  3579 			var items = param.items,
       
  3580 				inside = param.inside,
       
  3581 				overlapping = param.overlapping;
       
  3582 			matrix = inside && (matrix || new Matrix());
       
  3583 			for (var i = 0, l = children && children.length; i < l; i++) {
       
  3584 				var child = children[i],
       
  3585 					childMatrix = matrix && matrix.chain(child._matrix),
       
  3586 					add = true;
       
  3587 				if (inside) {
       
  3588 					var bounds = child.getBounds(childMatrix);
       
  3589 					if (!inside.intersects(bounds))
       
  3590 						continue;
       
  3591 					if (!(inside && inside.contains(bounds)) && !(overlapping
       
  3592 							&& overlapping.intersects(child, childMatrix)))
       
  3593 						add = false;
       
  3594 				}
       
  3595 				if (add && child.matches(match)) {
       
  3596 					items.push(child);
       
  3597 					if (firstOnly)
       
  3598 						break;
       
  3599 				}
       
  3600 				_getItems(child._children, match,
       
  3601 						childMatrix, param,
       
  3602 						firstOnly);
       
  3603 				if (firstOnly && items.length > 0)
       
  3604 					break;
       
  3605 			}
       
  3606 			return items;
       
  3607 		}
       
  3608 	}
       
  3609 }, {
       
  3610 
       
  3611 	importJSON: function(json) {
       
  3612 		var res = Base.importJSON(json, this);
       
  3613 		return res !== this
       
  3614 				? this.addChild(res)
       
  3615 				: res;
       
  3616 	},
       
  3617 
       
  3618 	addChild: function(item, _preserve) {
       
  3619 		return this.insertChild(undefined, item, _preserve);
       
  3620 	},
       
  3621 
       
  3622 	insertChild: function(index, item, _preserve) {
       
  3623 		var res = item ? this.insertChildren(index, [item], _preserve) : null;
       
  3624 		return res && res[0];
       
  3625 	},
       
  3626 
       
  3627 	addChildren: function(items, _preserve) {
       
  3628 		return this.insertChildren(this._children.length, items, _preserve);
       
  3629 	},
       
  3630 
       
  3631 	insertChildren: function(index, items, _preserve, _proto) {
       
  3632 		var children = this._children;
       
  3633 		if (children && items && items.length > 0) {
       
  3634 			items = Array.prototype.slice.apply(items);
       
  3635 			for (var i = items.length - 1; i >= 0; i--) {
       
  3636 				var item = items[i];
       
  3637 				if (_proto && !(item instanceof _proto)) {
       
  3638 					items.splice(i, 1);
       
  3639 				} else {
       
  3640 					var shift = item._parent === this && item._index < index;
       
  3641 					if (item._remove(false, true) && shift)
       
  3642 						index--;
       
  3643 				}
       
  3644 			}
       
  3645 			Base.splice(children, items, index, 0);
       
  3646 			var project = this._project,
       
  3647 				notifySelf = project && project._changes;
       
  3648 			for (var i = 0, l = items.length; i < l; i++) {
       
  3649 				var item = items[i];
       
  3650 				item._parent = this;
       
  3651 				item._setProject(this._project, true);
       
  3652 				if (item._name)
       
  3653 					item.setName(item._name);
       
  3654 				if (notifySelf)
       
  3655 					this._changed(5);
       
  3656 			}
       
  3657 			this._changed(11);
       
  3658 		} else {
       
  3659 			items = null;
       
  3660 		}
       
  3661 		return items;
       
  3662 	},
       
  3663 
       
  3664 	_insertSibling: function(index, item, _preserve) {
       
  3665 		return this._parent
       
  3666 				? this._parent.insertChild(index, item, _preserve)
       
  3667 				: null;
       
  3668 	},
       
  3669 
       
  3670 	insertAbove: function(item, _preserve) {
       
  3671 		return item._insertSibling(item._index + 1, this, _preserve);
       
  3672 	},
       
  3673 
       
  3674 	insertBelow: function(item, _preserve) {
       
  3675 		return item._insertSibling(item._index, this, _preserve);
       
  3676 	},
       
  3677 
       
  3678 	sendToBack: function() {
       
  3679 		return (this._parent || this instanceof Layer && this._project)
       
  3680 				.insertChild(0, this);
       
  3681 	},
       
  3682 
       
  3683 	bringToFront: function() {
       
  3684 		return (this._parent || this instanceof Layer && this._project)
       
  3685 				.addChild(this);
       
  3686 	},
       
  3687 
       
  3688 	appendTop: '#addChild',
       
  3689 
       
  3690 	appendBottom: function(item) {
       
  3691 		return this.insertChild(0, item);
       
  3692 	},
       
  3693 
       
  3694 	moveAbove: '#insertAbove',
       
  3695 
       
  3696 	moveBelow: '#insertBelow',
       
  3697 
       
  3698 	reduce: function() {
       
  3699 		if (this._children && this._children.length === 1) {
       
  3700 			var child = this._children[0].reduce();
       
  3701 			child.insertAbove(this);
       
  3702 			child.setStyle(this._style);
       
  3703 			this.remove();
       
  3704 			return child;
       
  3705 		}
       
  3706 		return this;
       
  3707 	},
       
  3708 
       
  3709 	_removeNamed: function() {
       
  3710 		var parent = this._parent;
       
  3711 		if (parent) {
       
  3712 			var children = parent._children,
       
  3713 				namedChildren = parent._namedChildren,
       
  3714 				name = this._name,
       
  3715 				namedArray = namedChildren[name],
       
  3716 				index = namedArray ? namedArray.indexOf(this) : -1;
       
  3717 			if (index !== -1) {
       
  3718 				if (children[name] == this)
       
  3719 					delete children[name];
       
  3720 				namedArray.splice(index, 1);
       
  3721 				if (namedArray.length) {
       
  3722 					children[name] = namedArray[namedArray.length - 1];
       
  3723 				} else {
       
  3724 					delete namedChildren[name];
       
  3725 				}
       
  3726 			}
       
  3727 		}
       
  3728 	},
       
  3729 
       
  3730 	_remove: function(notifySelf, notifyParent) {
       
  3731 		var parent = this._parent;
       
  3732 		if (parent) {
       
  3733 			if (this._name)
       
  3734 				this._removeNamed();
       
  3735 			if (this._index != null)
       
  3736 				Base.splice(parent._children, null, this._index, 1);
       
  3737 			this._installEvents(false);
       
  3738 			if (notifySelf) {
       
  3739 				var project = this._project;
       
  3740 				if (project && project._changes)
       
  3741 					this._changed(5);
       
  3742 			}
       
  3743 			if (notifyParent)
       
  3744 				parent._changed(11);
       
  3745 			this._parent = null;
       
  3746 			return true;
       
  3747 		}
       
  3748 		return false;
       
  3749 	},
       
  3750 
       
  3751 	remove: function() {
       
  3752 		return this._remove(true, true);
       
  3753 	},
       
  3754 
       
  3755 	replaceWith: function(item) {
       
  3756 		var ok = item && item.insertBelow(this);
       
  3757 		if (ok)
       
  3758 			this.remove();
       
  3759 		return ok;
       
  3760 	},
       
  3761 
       
  3762 	removeChildren: function(from, to) {
       
  3763 		if (!this._children)
       
  3764 			return null;
       
  3765 		from = from || 0;
       
  3766 		to = Base.pick(to, this._children.length);
       
  3767 		var removed = Base.splice(this._children, null, from, to - from);
       
  3768 		for (var i = removed.length - 1; i >= 0; i--) {
       
  3769 			removed[i]._remove(true, false);
       
  3770 		}
       
  3771 		if (removed.length > 0)
       
  3772 			this._changed(11);
       
  3773 		return removed;
       
  3774 	},
       
  3775 
       
  3776 	clear: '#removeChildren',
       
  3777 
       
  3778 	reverseChildren: function() {
       
  3779 		if (this._children) {
       
  3780 			this._children.reverse();
       
  3781 			for (var i = 0, l = this._children.length; i < l; i++)
       
  3782 				this._children[i]._index = i;
       
  3783 			this._changed(11);
       
  3784 		}
       
  3785 	},
       
  3786 
       
  3787 	isEmpty: function() {
       
  3788 		return !this._children || this._children.length === 0;
       
  3789 	},
       
  3790 
       
  3791 	isEditable: function() {
       
  3792 		var item = this;
       
  3793 		while (item) {
       
  3794 			if (!item._visible || item._locked)
       
  3795 				return false;
       
  3796 			item = item._parent;
       
  3797 		}
       
  3798 		return true;
       
  3799 	},
       
  3800 
       
  3801 	hasFill: function() {
       
  3802 		return this.getStyle().hasFill();
       
  3803 	},
       
  3804 
       
  3805 	hasStroke: function() {
       
  3806 		return this.getStyle().hasStroke();
       
  3807 	},
       
  3808 
       
  3809 	hasShadow: function() {
       
  3810 		return this.getStyle().hasShadow();
       
  3811 	},
       
  3812 
       
  3813 	_getOrder: function(item) {
       
  3814 		function getList(item) {
       
  3815 			var list = [];
       
  3816 			do {
       
  3817 				list.unshift(item);
       
  3818 			} while (item = item._parent);
       
  3819 			return list;
       
  3820 		}
       
  3821 		var list1 = getList(this),
       
  3822 			list2 = getList(item);
       
  3823 		for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) {
       
  3824 			if (list1[i] != list2[i]) {
       
  3825 				return list1[i]._index < list2[i]._index ? 1 : -1;
       
  3826 			}
       
  3827 		}
       
  3828 		return 0;
       
  3829 	},
       
  3830 
       
  3831 	hasChildren: function() {
       
  3832 		return this._children && this._children.length > 0;
       
  3833 	},
       
  3834 
       
  3835 	isInserted: function() {
       
  3836 		return this._parent ? this._parent.isInserted() : false;
       
  3837 	},
       
  3838 
       
  3839 	isAbove: function(item) {
       
  3840 		return this._getOrder(item) === -1;
       
  3841 	},
       
  3842 
       
  3843 	isBelow: function(item) {
       
  3844 		return this._getOrder(item) === 1;
       
  3845 	},
       
  3846 
       
  3847 	isParent: function(item) {
       
  3848 		return this._parent === item;
       
  3849 	},
       
  3850 
       
  3851 	isChild: function(item) {
       
  3852 		return item && item._parent === this;
       
  3853 	},
       
  3854 
       
  3855 	isDescendant: function(item) {
       
  3856 		var parent = this;
       
  3857 		while (parent = parent._parent) {
       
  3858 			if (parent == item)
       
  3859 				return true;
       
  3860 		}
       
  3861 		return false;
       
  3862 	},
       
  3863 
       
  3864 	isAncestor: function(item) {
       
  3865 		return item ? item.isDescendant(this) : false;
       
  3866 	},
       
  3867 
       
  3868 	isGroupedWith: function(item) {
       
  3869 		var parent = this._parent;
       
  3870 		while (parent) {
       
  3871 			if (parent._parent
       
  3872 				&& /^(Group|Layer|CompoundPath)$/.test(parent._class)
       
  3873 				&& item.isDescendant(parent))
       
  3874 					return true;
       
  3875 			parent = parent._parent;
       
  3876 		}
       
  3877 		return false;
       
  3878 	},
       
  3879 
       
  3880 	translate: function() {
       
  3881 		var mx = new Matrix();
       
  3882 		return this.transform(mx.translate.apply(mx, arguments));
       
  3883 	},
       
  3884 
       
  3885 	rotate: function(angle ) {
       
  3886 		return this.transform(new Matrix().rotate(angle,
       
  3887 				Point.read(arguments, 1, { readNull: true })
       
  3888 					|| this.getPosition(true)));
       
  3889 	}
       
  3890 }, Base.each(['scale', 'shear', 'skew'], function(name) {
       
  3891 	this[name] = function() {
       
  3892 		var point = Point.read(arguments),
       
  3893 			center = Point.read(arguments, 0, { readNull: true });
       
  3894 		return this.transform(new Matrix()[name](point,
       
  3895 				center || this.getPosition(true)));
       
  3896 	};
       
  3897 }, {
       
  3898 
       
  3899 }), {
       
  3900 	transform: function(matrix, _applyMatrix, _applyRecursively,
       
  3901 			_setApplyMatrix) {
       
  3902 		if (matrix && matrix.isIdentity())
       
  3903 			matrix = null;
       
  3904 		var _matrix = this._matrix,
       
  3905 			applyMatrix = (_applyMatrix || this._applyMatrix)
       
  3906 					&& ((!_matrix.isIdentity() || matrix)
       
  3907 						|| _applyMatrix && _applyRecursively && this._children);
       
  3908 		if (!matrix && !applyMatrix)
       
  3909 			return this;
       
  3910 		if (matrix)
       
  3911 			_matrix.preConcatenate(matrix);
       
  3912 		if (applyMatrix = applyMatrix && this._transformContent(_matrix,
       
  3913 					_applyRecursively, _setApplyMatrix)) {
       
  3914 			var pivot = this._pivot,
       
  3915 				style = this._style,
       
  3916 				fillColor = style.getFillColor(true),
       
  3917 				strokeColor = style.getStrokeColor(true);
       
  3918 			if (pivot)
       
  3919 				_matrix._transformPoint(pivot, pivot, true);
       
  3920 			if (fillColor)
       
  3921 				fillColor.transform(_matrix);
       
  3922 			if (strokeColor)
       
  3923 				strokeColor.transform(_matrix);
       
  3924 			_matrix.reset(true);
       
  3925 			if (_setApplyMatrix && this._canApplyMatrix)
       
  3926 				this._applyMatrix = true;
       
  3927 		}
       
  3928 		var bounds = this._bounds,
       
  3929 			position = this._position;
       
  3930 		this._changed(9);
       
  3931 		var decomp = bounds && matrix && matrix.decompose();
       
  3932 		if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
       
  3933 			for (var key in bounds) {
       
  3934 				var rect = bounds[key];
       
  3935 				if (applyMatrix || !rect._internal)
       
  3936 					matrix._transformBounds(rect, rect);
       
  3937 			}
       
  3938 			var getter = this._boundsGetter,
       
  3939 				rect = bounds[getter && getter.getBounds || getter || 'getBounds'];
       
  3940 			if (rect)
       
  3941 				this._position = rect.getCenter(true);
       
  3942 			this._bounds = bounds;
       
  3943 		} else if (matrix && position) {
       
  3944 			this._position = matrix._transformPoint(position, position);
       
  3945 		}
       
  3946 		return this;
       
  3947 	},
       
  3948 
       
  3949 	_transformContent: function(matrix, applyRecursively, setApplyMatrix) {
       
  3950 		var children = this._children;
       
  3951 		if (children) {
       
  3952 			for (var i = 0, l = children.length; i < l; i++)
       
  3953 				children[i].transform(matrix, true, applyRecursively,
       
  3954 						setApplyMatrix);
       
  3955 			return true;
       
  3956 		}
       
  3957 	},
       
  3958 
       
  3959 	globalToLocal: function() {
       
  3960 		return this.getGlobalMatrix(true)._inverseTransform(
       
  3961 				Point.read(arguments));
       
  3962 	},
       
  3963 
       
  3964 	localToGlobal: function() {
       
  3965 		return this.getGlobalMatrix(true)._transformPoint(
       
  3966 				Point.read(arguments));
       
  3967 	},
       
  3968 
       
  3969 	parentToLocal: function() {
       
  3970 		return this._matrix._inverseTransform(Point.read(arguments));
       
  3971 	},
       
  3972 
       
  3973 	localToParent: function() {
       
  3974 		return this._matrix._transformPoint(Point.read(arguments));
       
  3975 	},
       
  3976 
       
  3977 	fitBounds: function(rectangle, fill) {
       
  3978 		rectangle = Rectangle.read(arguments);
       
  3979 		var bounds = this.getBounds(),
       
  3980 			itemRatio = bounds.height / bounds.width,
       
  3981 			rectRatio = rectangle.height / rectangle.width,
       
  3982 			scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio)
       
  3983 					? rectangle.width / bounds.width
       
  3984 					: rectangle.height / bounds.height,
       
  3985 			newBounds = new Rectangle(new Point(),
       
  3986 					new Size(bounds.width * scale, bounds.height * scale));
       
  3987 		newBounds.setCenter(rectangle.getCenter());
       
  3988 		this.setBounds(newBounds);
       
  3989 	},
       
  3990 
       
  3991 	_setStyles: function(ctx) {
       
  3992 		var style = this._style,
       
  3993 			fillColor = style.getFillColor(),
       
  3994 			strokeColor = style.getStrokeColor(),
       
  3995 			shadowColor = style.getShadowColor();
       
  3996 		if (fillColor)
       
  3997 			ctx.fillStyle = fillColor.toCanvasStyle(ctx);
       
  3998 		if (strokeColor) {
       
  3999 			var strokeWidth = style.getStrokeWidth();
       
  4000 			if (strokeWidth > 0) {
       
  4001 				ctx.strokeStyle = strokeColor.toCanvasStyle(ctx);
       
  4002 				ctx.lineWidth = strokeWidth;
       
  4003 				var strokeJoin = style.getStrokeJoin(),
       
  4004 					strokeCap = style.getStrokeCap(),
       
  4005 					miterLimit = style.getMiterLimit();
       
  4006 				if (strokeJoin)
       
  4007 					ctx.lineJoin = strokeJoin;
       
  4008 				if (strokeCap)
       
  4009 					ctx.lineCap = strokeCap;
       
  4010 				if (miterLimit)
       
  4011 					ctx.miterLimit = miterLimit;
       
  4012 				if (paper.support.nativeDash) {
       
  4013 					var dashArray = style.getDashArray(),
       
  4014 						dashOffset = style.getDashOffset();
       
  4015 					if (dashArray && dashArray.length) {
       
  4016 						if ('setLineDash' in ctx) {
       
  4017 							ctx.setLineDash(dashArray);
       
  4018 							ctx.lineDashOffset = dashOffset;
       
  4019 						} else {
       
  4020 							ctx.mozDash = dashArray;
       
  4021 							ctx.mozDashOffset = dashOffset;
       
  4022 						}
       
  4023 					}
       
  4024 				}
       
  4025 			}
       
  4026 		}
       
  4027 		if (shadowColor) {
       
  4028 			var shadowBlur = style.getShadowBlur();
       
  4029 			if (shadowBlur > 0) {
       
  4030 				ctx.shadowColor = shadowColor.toCanvasStyle(ctx);
       
  4031 				ctx.shadowBlur = shadowBlur;
       
  4032 				var offset = this.getShadowOffset();
       
  4033 				ctx.shadowOffsetX = offset.x;
       
  4034 				ctx.shadowOffsetY = offset.y;
       
  4035 			}
       
  4036 		}
       
  4037 	},
       
  4038 
       
  4039 	draw: function(ctx, param, parentStrokeMatrix) {
       
  4040 		var updateVersion = this._updateVersion = this._project._updateVersion;
       
  4041 		if (!this._visible || this._opacity === 0)
       
  4042 			return;
       
  4043 		var matrices = param.matrices,
       
  4044 			viewMatrix = param.viewMatrix,
       
  4045 			matrix = this._matrix,
       
  4046 			globalMatrix = matrices[matrices.length - 1].chain(matrix);
       
  4047 		if (!globalMatrix.isInvertible())
       
  4048 			return;
       
  4049 
       
  4050 		function getViewMatrix(matrix) {
       
  4051 			return viewMatrix ? viewMatrix.chain(matrix) : matrix;
       
  4052 		}
       
  4053 
       
  4054 		matrices.push(globalMatrix);
       
  4055 		if (param.updateMatrix) {
       
  4056 			globalMatrix._updateVersion = updateVersion;
       
  4057 			this._globalMatrix = globalMatrix;
       
  4058 		}
       
  4059 
       
  4060 		var blendMode = this._blendMode,
       
  4061 			opacity = this._opacity,
       
  4062 			normalBlend = blendMode === 'normal',
       
  4063 			nativeBlend = BlendMode.nativeModes[blendMode],
       
  4064 			direct = normalBlend && opacity === 1
       
  4065 					|| param.dontStart
       
  4066 					|| param.clip
       
  4067 					|| (nativeBlend || normalBlend && opacity < 1)
       
  4068 						&& this._canComposite(),
       
  4069 			pixelRatio = param.pixelRatio,
       
  4070 			mainCtx, itemOffset, prevOffset;
       
  4071 		if (!direct) {
       
  4072 			var bounds = this.getStrokeBounds(getViewMatrix(globalMatrix));
       
  4073 			if (!bounds.width || !bounds.height)
       
  4074 				return;
       
  4075 			prevOffset = param.offset;
       
  4076 			itemOffset = param.offset = bounds.getTopLeft().floor();
       
  4077 			mainCtx = ctx;
       
  4078 			ctx = CanvasProvider.getContext(bounds.getSize().ceil().add(1)
       
  4079 					.multiply(pixelRatio));
       
  4080 			if (pixelRatio !== 1)
       
  4081 				ctx.scale(pixelRatio, pixelRatio);
       
  4082 		}
       
  4083 		ctx.save();
       
  4084 		var strokeMatrix = parentStrokeMatrix
       
  4085 				? parentStrokeMatrix.chain(matrix)
       
  4086 				: !this.getStrokeScaling(true) && getViewMatrix(globalMatrix),
       
  4087 			clip = !direct && param.clipItem,
       
  4088 			transform = !strokeMatrix || clip;
       
  4089 		if (direct) {
       
  4090 			ctx.globalAlpha = opacity;
       
  4091 			if (nativeBlend)
       
  4092 				ctx.globalCompositeOperation = blendMode;
       
  4093 		} else if (transform) {
       
  4094 			ctx.translate(-itemOffset.x, -itemOffset.y);
       
  4095 		}
       
  4096 		if (transform)
       
  4097 			(direct ? matrix : getViewMatrix(globalMatrix)).applyToContext(ctx);
       
  4098 		if (clip)
       
  4099 			param.clipItem.draw(ctx, param.extend({ clip: true }));
       
  4100 		if (strokeMatrix) {
       
  4101 			ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
       
  4102 			var offset = param.offset;
       
  4103 			if (offset)
       
  4104 				ctx.translate(-offset.x, -offset.y);
       
  4105 		}
       
  4106 		this._draw(ctx, param, strokeMatrix);
       
  4107 		ctx.restore();
       
  4108 		matrices.pop();
       
  4109 		if (param.clip && !param.dontFinish)
       
  4110 			ctx.clip();
       
  4111 		if (!direct) {
       
  4112 			BlendMode.process(blendMode, ctx, mainCtx, opacity,
       
  4113 					itemOffset.subtract(prevOffset).multiply(pixelRatio));
       
  4114 			CanvasProvider.release(ctx);
       
  4115 			param.offset = prevOffset;
       
  4116 		}
       
  4117 	},
       
  4118 
       
  4119 	_isUpdated: function(updateVersion) {
       
  4120 		var parent = this._parent;
       
  4121 		if (parent instanceof CompoundPath)
       
  4122 			return parent._isUpdated(updateVersion);
       
  4123 		var updated = this._updateVersion === updateVersion;
       
  4124 		if (!updated && parent && parent._visible
       
  4125 				&& parent._isUpdated(updateVersion)) {
       
  4126 			this._updateVersion = updateVersion;
       
  4127 			updated = true;
       
  4128 		}
       
  4129 		return updated;
       
  4130 	},
       
  4131 
       
  4132 	_drawSelection: function(ctx, matrix, size, selectedItems, updateVersion) {
       
  4133 		if ((this._drawSelected || this._boundsSelected)
       
  4134 				&& this._isUpdated(updateVersion)) {
       
  4135 			var color = this.getSelectedColor(true)
       
  4136 					|| this.getLayer().getSelectedColor(true),
       
  4137 				mx = matrix.chain(this.getGlobalMatrix(true));
       
  4138 			ctx.strokeStyle = ctx.fillStyle = color
       
  4139 					? color.toCanvasStyle(ctx) : '#009dec';
       
  4140 			if (this._drawSelected)
       
  4141 				this._drawSelected(ctx, mx, selectedItems);
       
  4142 			if (this._boundsSelected) {
       
  4143 				var half = size / 2;
       
  4144 					coords = mx._transformCorners(this.getInternalBounds());
       
  4145 				ctx.beginPath();
       
  4146 				for (var i = 0; i < 8; i++)
       
  4147 					ctx[i === 0 ? 'moveTo' : 'lineTo'](coords[i], coords[++i]);
       
  4148 				ctx.closePath();
       
  4149 				ctx.stroke();
       
  4150 				for (var i = 0; i < 8; i++)
       
  4151 					ctx.fillRect(coords[i] - half, coords[++i] - half,
       
  4152 							size, size);
       
  4153 			}
       
  4154 		}
       
  4155 	},
       
  4156 
       
  4157 	_canComposite: function() {
       
  4158 		return false;
       
  4159 	}
       
  4160 }, Base.each(['down', 'drag', 'up', 'move'], function(name) {
       
  4161 	this['removeOn' + Base.capitalize(name)] = function() {
       
  4162 		var hash = {};
       
  4163 		hash[name] = true;
       
  4164 		return this.removeOn(hash);
       
  4165 	};
       
  4166 }, {
       
  4167 
       
  4168 	removeOn: function(obj) {
       
  4169 		for (var name in obj) {
       
  4170 			if (obj[name]) {
       
  4171 				var key = 'mouse' + name,
       
  4172 					project = this._project,
       
  4173 					sets = project._removeSets = project._removeSets || {};
       
  4174 				sets[key] = sets[key] || {};
       
  4175 				sets[key][this._id] = this;
       
  4176 			}
       
  4177 		}
       
  4178 		return this;
       
  4179 	}
       
  4180 }));
       
  4181 
       
  4182 var Group = Item.extend({
       
  4183 	_class: 'Group',
       
  4184 	_selectChildren: true,
       
  4185 	_serializeFields: {
       
  4186 		children: []
       
  4187 	},
       
  4188 
       
  4189 	initialize: function Group(arg) {
       
  4190 		this._children = [];
       
  4191 		this._namedChildren = {};
       
  4192 		if (!this._initialize(arg))
       
  4193 			this.addChildren(Array.isArray(arg) ? arg : arguments);
       
  4194 	},
       
  4195 
       
  4196 	_changed: function _changed(flags) {
       
  4197 		_changed.base.call(this, flags);
       
  4198 		if (flags & 1026) {
       
  4199 			this._clipItem = undefined;
       
  4200 		}
       
  4201 	},
       
  4202 
       
  4203 	_getClipItem: function() {
       
  4204 		var clipItem = this._clipItem;
       
  4205 		if (clipItem === undefined) {
       
  4206 			clipItem = null;
       
  4207 			for (var i = 0, l = this._children.length; i < l; i++) {
       
  4208 				var child = this._children[i];
       
  4209 				if (child._clipMask) {
       
  4210 					clipItem = child;
       
  4211 					break;
       
  4212 				}
       
  4213 			}
       
  4214 			this._clipItem = clipItem;
       
  4215 		}
       
  4216 		return clipItem;
       
  4217 	},
       
  4218 
       
  4219 	isClipped: function() {
       
  4220 		return !!this._getClipItem();
       
  4221 	},
       
  4222 
       
  4223 	setClipped: function(clipped) {
       
  4224 		var child = this.getFirstChild();
       
  4225 		if (child)
       
  4226 			child.setClipMask(clipped);
       
  4227 	},
       
  4228 
       
  4229 	_draw: function(ctx, param) {
       
  4230 		var clip = param.clip,
       
  4231 			clipItem = !clip && this._getClipItem(),
       
  4232 			draw = true;
       
  4233 		param = param.extend({ clipItem: clipItem, clip: false });
       
  4234 		if (clip) {
       
  4235 			if (this._currentPath) {
       
  4236 				ctx.currentPath = this._currentPath;
       
  4237 				draw = false;
       
  4238 			} else {
       
  4239 				ctx.beginPath();
       
  4240 				param.dontStart = param.dontFinish = true;
       
  4241 			}
       
  4242 		} else if (clipItem) {
       
  4243 			clipItem.draw(ctx, param.extend({ clip: true }));
       
  4244 		}
       
  4245 		if (draw) {
       
  4246 			for (var i = 0, l = this._children.length; i < l; i++) {
       
  4247 				var item = this._children[i];
       
  4248 				if (item !== clipItem)
       
  4249 					item.draw(ctx, param);
       
  4250 			}
       
  4251 		}
       
  4252 		if (clip) {
       
  4253 			this._currentPath = ctx.currentPath;
       
  4254 		}
       
  4255 	}
       
  4256 });
       
  4257 
       
  4258 var Layer = Group.extend({
       
  4259 	_class: 'Layer',
       
  4260 
       
  4261 	initialize: function Layer(arg) {
       
  4262 		var props = Base.isPlainObject(arg)
       
  4263 				? new Base(arg)
       
  4264 				: { children: Array.isArray(arg) ? arg : arguments },
       
  4265 			insert = props.insert;
       
  4266 		props.insert = false;
       
  4267 		Group.call(this, props);
       
  4268 		if (insert || insert === undefined) {
       
  4269 			this._project.addChild(this);
       
  4270 			this.activate();
       
  4271 		}
       
  4272 	},
       
  4273 
       
  4274 	_remove: function _remove(notifySelf, notifyParent) {
       
  4275 		if (this._parent)
       
  4276 			return _remove.base.call(this, notifySelf, notifyParent);
       
  4277 		if (this._index != null) {
       
  4278 			var project = this._project;
       
  4279 			if (project._activeLayer === this)
       
  4280 				project._activeLayer = this.getNextSibling()
       
  4281 						|| this.getPreviousSibling();
       
  4282 			Base.splice(project.layers, null, this._index, 1);
       
  4283 			this._installEvents(false);
       
  4284 			if (notifySelf && project._changes)
       
  4285 				this._changed(5);
       
  4286 			if (notifyParent) {
       
  4287 				project._needsUpdate = true;
       
  4288 			}
       
  4289 			return true;
       
  4290 		}
       
  4291 		return false;
       
  4292 	},
       
  4293 
       
  4294 	getNextSibling: function getNextSibling() {
       
  4295 		return this._parent ? getNextSibling.base.call(this)
       
  4296 				: this._project.layers[this._index + 1] || null;
       
  4297 	},
       
  4298 
       
  4299 	getPreviousSibling: function getPreviousSibling() {
       
  4300 		return this._parent ? getPreviousSibling.base.call(this)
       
  4301 				: this._project.layers[this._index - 1] || null;
       
  4302 	},
       
  4303 
       
  4304 	isInserted: function isInserted() {
       
  4305 		return this._parent ? isInserted.base.call(this) : this._index != null;
       
  4306 	},
       
  4307 
       
  4308 	activate: function() {
       
  4309 		this._project._activeLayer = this;
       
  4310 	},
       
  4311 
       
  4312 	_insertSibling: function _insertSibling(index, item, _preserve) {
       
  4313 		return !this._parent
       
  4314 				? this._project.insertChild(index, item, _preserve)
       
  4315 				: _insertSibling.base.call(this, index, item, _preserve);
       
  4316 	}
       
  4317 });
       
  4318 
       
  4319 var Shape = Item.extend({
       
  4320 	_class: 'Shape',
       
  4321 	_applyMatrix: false,
       
  4322 	_canApplyMatrix: false,
       
  4323 	_boundsSelected: true,
       
  4324 	_serializeFields: {
       
  4325 		type: null,
       
  4326 		size: null,
       
  4327 		radius: null
       
  4328 	},
       
  4329 
       
  4330 	initialize: function Shape(props) {
       
  4331 		this._initialize(props);
       
  4332 	},
       
  4333 
       
  4334 	_equals: function(item) {
       
  4335 		return this._type === item._type
       
  4336 			&& this._size.equals(item._size)
       
  4337 			&& Base.equals(this._radius, item._radius);
       
  4338 	},
       
  4339 
       
  4340 	clone: function(insert) {
       
  4341 		var copy = new Shape(Item.NO_INSERT);
       
  4342 		copy.setType(this._type);
       
  4343 		copy.setSize(this._size);
       
  4344 		copy.setRadius(this._radius);
       
  4345 		return this._clone(copy, insert);
       
  4346 	},
       
  4347 
       
  4348 	getType: function() {
       
  4349 		return this._type;
       
  4350 	},
       
  4351 
       
  4352 	setType: function(type) {
       
  4353 		this._type = type;
       
  4354 	},
       
  4355 
       
  4356 	getShape: '#getType',
       
  4357 	setShape: '#setType',
       
  4358 
       
  4359 	getSize: function() {
       
  4360 		var size = this._size;
       
  4361 		return new LinkedSize(size.width, size.height, this, 'setSize');
       
  4362 	},
       
  4363 
       
  4364 	setSize: function() {
       
  4365 		var size = Size.read(arguments);
       
  4366 		if (!this._size) {
       
  4367 			this._size = size.clone();
       
  4368 		} else if (!this._size.equals(size)) {
       
  4369 			var type = this._type,
       
  4370 				width = size.width,
       
  4371 				height = size.height;
       
  4372 			if (type === 'rectangle') {
       
  4373 				var radius = Size.min(this._radius, size.divide(2));
       
  4374 				this._radius.set(radius.width, radius.height);
       
  4375 			} else if (type === 'circle') {
       
  4376 				width = height = (width + height) / 2;
       
  4377 				this._radius = width / 2;
       
  4378 			} else if (type === 'ellipse') {
       
  4379 				this._radius.set(width / 2, height / 2);
       
  4380 			}
       
  4381 			this._size.set(width, height);
       
  4382 			this._changed(9);
       
  4383 		}
       
  4384 	},
       
  4385 
       
  4386 	getRadius: function() {
       
  4387 		var rad = this._radius;
       
  4388 		return this._type === 'circle'
       
  4389 				? rad
       
  4390 				: new LinkedSize(rad.width, rad.height, this, 'setRadius');
       
  4391 	},
       
  4392 
       
  4393 	setRadius: function(radius) {
       
  4394 		var type = this._type;
       
  4395 		if (type === 'circle') {
       
  4396 			if (radius === this._radius)
       
  4397 				return;
       
  4398 			var size = radius * 2;
       
  4399 			this._radius = radius;
       
  4400 			this._size.set(size, size);
       
  4401 		} else {
       
  4402 			radius = Size.read(arguments);
       
  4403 			if (!this._radius) {
       
  4404 				this._radius = radius.clone();
       
  4405 			} else {
       
  4406 				if (this._radius.equals(radius))
       
  4407 					return;
       
  4408 				this._radius.set(radius.width, radius.height);
       
  4409 				if (type === 'rectangle') {
       
  4410 					var size = Size.max(this._size, radius.multiply(2));
       
  4411 					this._size.set(size.width, size.height);
       
  4412 				} else if (type === 'ellipse') {
       
  4413 					this._size.set(radius.width * 2, radius.height * 2);
       
  4414 				}
       
  4415 			}
       
  4416 		}
       
  4417 		this._changed(9);
       
  4418 	},
       
  4419 
       
  4420 	isEmpty: function() {
       
  4421 		return false;
       
  4422 	},
       
  4423 
       
  4424 	toPath: function(insert) {
       
  4425 		var path = new Path[Base.capitalize(this._type)]({
       
  4426 			center: new Point(),
       
  4427 			size: this._size,
       
  4428 			radius: this._radius,
       
  4429 			insert: false
       
  4430 		});
       
  4431 		path.setStyle(this._style);
       
  4432 		path.transform(this._matrix);
       
  4433 		if (insert || insert === undefined)
       
  4434 			path.insertAbove(this);
       
  4435 		return path;
       
  4436 	},
       
  4437 
       
  4438 	_draw: function(ctx, param, strokeMatrix) {
       
  4439 		var style = this._style,
       
  4440 			hasFill = style.hasFill(),
       
  4441 			hasStroke = style.hasStroke(),
       
  4442 			dontPaint = param.dontFinish || param.clip,
       
  4443 			untransformed = !strokeMatrix;
       
  4444 		if (hasFill || hasStroke || dontPaint) {
       
  4445 			var type = this._type,
       
  4446 				radius = this._radius,
       
  4447 				isCircle = type === 'circle';
       
  4448 			if (!param.dontStart)
       
  4449 				ctx.beginPath();
       
  4450 			if (untransformed && isCircle) {
       
  4451 				ctx.arc(0, 0, radius, 0, Math.PI * 2, true);
       
  4452 			} else {
       
  4453 				var rx = isCircle ? radius : radius.width,
       
  4454 					ry = isCircle ? radius : radius.height,
       
  4455 					size = this._size,
       
  4456 					width = size.width,
       
  4457 					height = size.height;
       
  4458 				if (untransformed && type === 'rect' && rx === 0 && ry === 0) {
       
  4459 					ctx.rect(-width / 2, -height / 2, width, height);
       
  4460 				} else {
       
  4461 					var x = width / 2,
       
  4462 						y = height / 2,
       
  4463 						kappa = 1 - 0.5522847498307936,
       
  4464 						cx = rx * kappa,
       
  4465 						cy = ry * kappa,
       
  4466 						c = [
       
  4467 							-x, -y + ry,
       
  4468 							-x, -y + cy,
       
  4469 							-x + cx, -y,
       
  4470 							-x + rx, -y,
       
  4471 							x - rx, -y,
       
  4472 							x - cx, -y,
       
  4473 							x, -y + cy,
       
  4474 							x, -y + ry,
       
  4475 							x, y - ry,
       
  4476 							x, y - cy,
       
  4477 							x - cx, y,
       
  4478 							x - rx, y,
       
  4479 							-x + rx, y,
       
  4480 							-x + cx, y,
       
  4481 							-x, y - cy,
       
  4482 							-x, y - ry
       
  4483 						];
       
  4484 					if (strokeMatrix)
       
  4485 						strokeMatrix.transform(c, c, 32);
       
  4486 					ctx.moveTo(c[0], c[1]);
       
  4487 					ctx.bezierCurveTo(c[2], c[3], c[4], c[5], c[6], c[7]);
       
  4488 					if (x !== rx)
       
  4489 						ctx.lineTo(c[8], c[9]);
       
  4490 					ctx.bezierCurveTo(c[10], c[11], c[12], c[13], c[14], c[15]);
       
  4491 					if (y !== ry)
       
  4492 						ctx.lineTo(c[16], c[17]);
       
  4493 					ctx.bezierCurveTo(c[18], c[19], c[20], c[21], c[22], c[23]);
       
  4494 					if (x !== rx)
       
  4495 						ctx.lineTo(c[24], c[25]);
       
  4496 					ctx.bezierCurveTo(c[26], c[27], c[28], c[29], c[30], c[31]);
       
  4497 				}
       
  4498 			}
       
  4499 			ctx.closePath();
       
  4500 		}
       
  4501 		if (!dontPaint && (hasFill || hasStroke)) {
       
  4502 			this._setStyles(ctx);
       
  4503 			if (hasFill) {
       
  4504 				ctx.fill(style.getWindingRule());
       
  4505 				ctx.shadowColor = 'rgba(0,0,0,0)';
       
  4506 			}
       
  4507 			if (hasStroke)
       
  4508 				ctx.stroke();
       
  4509 		}
       
  4510 	},
       
  4511 
       
  4512 	_canComposite: function() {
       
  4513 		return !(this.hasFill() && this.hasStroke());
       
  4514 	},
       
  4515 
       
  4516 	_getBounds: function(getter, matrix) {
       
  4517 		var rect = new Rectangle(this._size).setCenter(0, 0);
       
  4518 		if (getter !== 'getBounds' && this.hasStroke())
       
  4519 			rect = rect.expand(this.getStrokeWidth());
       
  4520 		return matrix ? matrix._transformBounds(rect) : rect;
       
  4521 	}
       
  4522 },
       
  4523 new function() {
       
  4524 
       
  4525 	function getCornerCenter(that, point, expand) {
       
  4526 		var radius = that._radius;
       
  4527 		if (!radius.isZero()) {
       
  4528 			var halfSize = that._size.divide(2);
       
  4529 			for (var i = 0; i < 4; i++) {
       
  4530 				var dir = new Point(i & 1 ? 1 : -1, i > 1 ? 1 : -1),
       
  4531 					corner = dir.multiply(halfSize),
       
  4532 					center = corner.subtract(dir.multiply(radius)),
       
  4533 					rect = new Rectangle(corner, center);
       
  4534 				if ((expand ? rect.expand(expand) : rect).contains(point))
       
  4535 					return center;
       
  4536 			}
       
  4537 		}
       
  4538 	}
       
  4539 
       
  4540 	function getEllipseRadius(point, radius) {
       
  4541 		var angle = point.getAngleInRadians(),
       
  4542 			width = radius.width * 2,
       
  4543 			height = radius.height * 2,
       
  4544 			x = width * Math.sin(angle),
       
  4545 			y = height * Math.cos(angle);
       
  4546 		return width * height / (2 * Math.sqrt(x * x + y * y));
       
  4547 	}
       
  4548 
       
  4549 	return {
       
  4550 		_contains: function _contains(point) {
       
  4551 			if (this._type === 'rectangle') {
       
  4552 				var center = getCornerCenter(this, point);
       
  4553 				return center
       
  4554 						? point.subtract(center).divide(this._radius)
       
  4555 							.getLength() <= 1
       
  4556 						: _contains.base.call(this, point);
       
  4557 			} else {
       
  4558 				return point.divide(this.size).getLength() <= 0.5;
       
  4559 			}
       
  4560 		},
       
  4561 
       
  4562 		_hitTestSelf: function _hitTestSelf(point, options) {
       
  4563 			var hit = false;
       
  4564 			if (this.hasStroke()) {
       
  4565 				var type = this._type,
       
  4566 					radius = this._radius,
       
  4567 					strokeWidth = this.getStrokeWidth() + 2 * options.tolerance;
       
  4568 				if (type === 'rectangle') {
       
  4569 					var center = getCornerCenter(this, point, strokeWidth);
       
  4570 					if (center) {
       
  4571 						var pt = point.subtract(center);
       
  4572 						hit = 2 * Math.abs(pt.getLength()
       
  4573 								- getEllipseRadius(pt, radius)) <= strokeWidth;
       
  4574 					} else {
       
  4575 						var rect = new Rectangle(this._size).setCenter(0, 0),
       
  4576 							outer = rect.expand(strokeWidth),
       
  4577 							inner = rect.expand(-strokeWidth);
       
  4578 						hit = outer._containsPoint(point)
       
  4579 								&& !inner._containsPoint(point);
       
  4580 					}
       
  4581 				} else {
       
  4582 					if (type === 'ellipse')
       
  4583 						radius = getEllipseRadius(point, radius);
       
  4584 					hit = 2 * Math.abs(point.getLength() - radius)
       
  4585 							<= strokeWidth;
       
  4586 				}
       
  4587 			}
       
  4588 			return hit
       
  4589 					? new HitResult('stroke', this)
       
  4590 					: _hitTestSelf.base.apply(this, arguments);
       
  4591 		}
       
  4592 	};
       
  4593 }, {
       
  4594 
       
  4595 statics: new function() {
       
  4596 	function createShape(type, point, size, radius, args) {
       
  4597 		var item = new Shape(Base.getNamed(args));
       
  4598 		item._type = type;
       
  4599 		item._size = size;
       
  4600 		item._radius = radius;
       
  4601 		return item.translate(point);
       
  4602 	}
       
  4603 
       
  4604 	return {
       
  4605 		Circle: function() {
       
  4606 			var center = Point.readNamed(arguments, 'center'),
       
  4607 				radius = Base.readNamed(arguments, 'radius');
       
  4608 			return createShape('circle', center, new Size(radius * 2), radius,
       
  4609 					arguments);
       
  4610 		},
       
  4611 
       
  4612 		Rectangle: function() {
       
  4613 			var rect = Rectangle.readNamed(arguments, 'rectangle'),
       
  4614 				radius = Size.min(Size.readNamed(arguments, 'radius'),
       
  4615 						rect.getSize(true).divide(2));
       
  4616 			return createShape('rectangle', rect.getCenter(true),
       
  4617 					rect.getSize(true), radius, arguments);
       
  4618 		},
       
  4619 
       
  4620 		Ellipse: function() {
       
  4621 			var ellipse = Shape._readEllipse(arguments),
       
  4622 				radius = ellipse.radius;
       
  4623 			return createShape('ellipse', ellipse.center, radius.multiply(2),
       
  4624 					radius, arguments);
       
  4625 		},
       
  4626 
       
  4627 		_readEllipse: function(args) {
       
  4628 			var center,
       
  4629 				radius;
       
  4630 			if (Base.hasNamed(args, 'radius')) {
       
  4631 				center = Point.readNamed(args, 'center');
       
  4632 				radius = Size.readNamed(args, 'radius');
       
  4633 			} else {
       
  4634 				var rect = Rectangle.readNamed(args, 'rectangle');
       
  4635 				center = rect.getCenter(true);
       
  4636 				radius = rect.getSize(true).divide(2);
       
  4637 			}
       
  4638 			return { center: center, radius: radius };
       
  4639 		}
       
  4640 	};
       
  4641 }});
       
  4642 
       
  4643 var Raster = Item.extend({
       
  4644 	_class: 'Raster',
       
  4645 	_applyMatrix: false,
       
  4646 	_canApplyMatrix: false,
       
  4647 	_boundsGetter: 'getBounds',
       
  4648 	_boundsSelected: true,
       
  4649 	_serializeFields: {
       
  4650 		source: null
       
  4651 	},
       
  4652 
       
  4653 	initialize: function Raster(object, position) {
       
  4654 		if (!this._initialize(object,
       
  4655 				position !== undefined && Point.read(arguments, 1))) {
       
  4656 			if (typeof object === 'string') {
       
  4657 				this.setSource(object);
       
  4658 			} else {
       
  4659 				this.setImage(object);
       
  4660 			}
       
  4661 		}
       
  4662 		if (!this._size) {
       
  4663 			this._size = new Size();
       
  4664 			this._loaded = false;
       
  4665 		}
       
  4666 	},
       
  4667 
       
  4668 	_equals: function(item) {
       
  4669 		return this.getSource() === item.getSource();
       
  4670 	},
       
  4671 
       
  4672 	clone: function(insert) {
       
  4673 		var copy = new Raster(Item.NO_INSERT),
       
  4674 			image = this._image,
       
  4675 			canvas = this._canvas;
       
  4676 		if (image) {
       
  4677 			copy.setImage(image);
       
  4678 		} else if (canvas) {
       
  4679 			var copyCanvas = CanvasProvider.getCanvas(this._size);
       
  4680 			copyCanvas.getContext('2d').drawImage(canvas, 0, 0);
       
  4681 			copy.setImage(copyCanvas);
       
  4682 		}
       
  4683 		return this._clone(copy, insert);
       
  4684 	},
       
  4685 
       
  4686 	getSize: function() {
       
  4687 		var size = this._size;
       
  4688 		return new LinkedSize(size ? size.width : 0, size ? size.height : 0,
       
  4689 				this, 'setSize');
       
  4690 	},
       
  4691 
       
  4692 	setSize: function() {
       
  4693 		var size = Size.read(arguments);
       
  4694 		if (!size.equals(this._size)) {
       
  4695 			if (size.width > 0 && size.height > 0) {
       
  4696 				var element = this.getElement();
       
  4697 				this.setImage(CanvasProvider.getCanvas(size));
       
  4698 				if (element)
       
  4699 					this.getContext(true).drawImage(element, 0, 0,
       
  4700 							size.width, size.height);
       
  4701 			} else {
       
  4702 				if (this._canvas)
       
  4703 					CanvasProvider.release(this._canvas);
       
  4704 				this._size = size.clone();
       
  4705 			}
       
  4706 		}
       
  4707 	},
       
  4708 
       
  4709 	getWidth: function() {
       
  4710 		return this._size ? this._size.width : 0;
       
  4711 	},
       
  4712 
       
  4713 	setWidth: function(width) {
       
  4714 		this.setSize(width, this.getHeight());
       
  4715 	},
       
  4716 
       
  4717 	getHeight: function() {
       
  4718 		return this._size ? this._size.height : 0;
       
  4719 	},
       
  4720 
       
  4721 	setHeight: function(height) {
       
  4722 		this.setSize(this.getWidth(), height);
       
  4723 	},
       
  4724 
       
  4725 	isEmpty: function() {
       
  4726 		var size = this._size;
       
  4727 		return !size || size.width === 0 && size.height === 0;
       
  4728 	},
       
  4729 
       
  4730 	getResolution: function() {
       
  4731 		var matrix = this._matrix,
       
  4732 			orig = new Point(0, 0).transform(matrix),
       
  4733 			u = new Point(1, 0).transform(matrix).subtract(orig),
       
  4734 			v = new Point(0, 1).transform(matrix).subtract(orig);
       
  4735 		return new Size(
       
  4736 			72 / u.getLength(),
       
  4737 			72 / v.getLength()
       
  4738 		);
       
  4739 	},
       
  4740 
       
  4741 	getPpi: '#getResolution',
       
  4742 
       
  4743 	getImage: function() {
       
  4744 		return this._image;
       
  4745 	},
       
  4746 
       
  4747 	setImage: function(image) {
       
  4748 		if (this._canvas)
       
  4749 			CanvasProvider.release(this._canvas);
       
  4750 		if (image && image.getContext) {
       
  4751 			this._image = null;
       
  4752 			this._canvas = image;
       
  4753 			this._loaded = true;
       
  4754 		} else {
       
  4755 			this._image = image;
       
  4756 			this._canvas = null;
       
  4757 			this._loaded = image && image.complete;
       
  4758 		}
       
  4759 		this._size = new Size(
       
  4760 				image ? image.naturalWidth || image.width : 0,
       
  4761 				image ? image.naturalHeight || image.height : 0);
       
  4762 		this._context = null;
       
  4763 		this._changed(521);
       
  4764 	},
       
  4765 
       
  4766 	getCanvas: function() {
       
  4767 		if (!this._canvas) {
       
  4768 			var ctx = CanvasProvider.getContext(this._size);
       
  4769 			try {
       
  4770 				if (this._image)
       
  4771 					ctx.drawImage(this._image, 0, 0);
       
  4772 				this._canvas = ctx.canvas;
       
  4773 			} catch (e) {
       
  4774 				CanvasProvider.release(ctx);
       
  4775 			}
       
  4776 		}
       
  4777 		return this._canvas;
       
  4778 	},
       
  4779 
       
  4780 	setCanvas: '#setImage',
       
  4781 
       
  4782 	getContext: function(modify) {
       
  4783 		if (!this._context)
       
  4784 			this._context = this.getCanvas().getContext('2d');
       
  4785 		if (modify) {
       
  4786 			this._image = null;
       
  4787 			this._changed(513);
       
  4788 		}
       
  4789 		return this._context;
       
  4790 	},
       
  4791 
       
  4792 	setContext: function(context) {
       
  4793 		this._context = context;
       
  4794 	},
       
  4795 
       
  4796 	getSource: function() {
       
  4797 		return this._image && this._image.src || this.toDataURL();
       
  4798 	},
       
  4799 
       
  4800 	setSource: function(src) {
       
  4801 		var that = this,
       
  4802 			image;
       
  4803 
       
  4804 		function loaded() {
       
  4805 			var view = that.getView();
       
  4806 			if (view) {
       
  4807 				paper = view._scope;
       
  4808 				that.setImage(image);
       
  4809 				that.emit('load');
       
  4810 				view.update();
       
  4811 			}
       
  4812 		}
       
  4813 
       
  4814 			image = document.getElementById(src) || new Image();
       
  4815 
       
  4816 		if (image.naturalWidth && image.naturalHeight) {
       
  4817 			setTimeout(loaded, 0);
       
  4818 		} else {
       
  4819 			DomEvent.add(image, {
       
  4820 				load: loaded
       
  4821 			});
       
  4822 			if (!image.src)
       
  4823 				image.src = src;
       
  4824 		}
       
  4825 		this.setImage(image);
       
  4826 	},
       
  4827 
       
  4828 	getElement: function() {
       
  4829 		return this._canvas || this._loaded && this._image;
       
  4830 	}
       
  4831 }, {
       
  4832 	beans: false,
       
  4833 
       
  4834 	getSubCanvas: function() {
       
  4835 		var rect = Rectangle.read(arguments),
       
  4836 			ctx = CanvasProvider.getContext(rect.getSize());
       
  4837 		ctx.drawImage(this.getCanvas(), rect.x, rect.y,
       
  4838 				rect.width, rect.height, 0, 0, rect.width, rect.height);
       
  4839 		return ctx.canvas;
       
  4840 	},
       
  4841 
       
  4842 	getSubRaster: function() {
       
  4843 		var rect = Rectangle.read(arguments),
       
  4844 			raster = new Raster(Item.NO_INSERT);
       
  4845 		raster.setImage(this.getSubCanvas(rect));
       
  4846 		raster.translate(rect.getCenter().subtract(this.getSize().divide(2)));
       
  4847 		raster._matrix.preConcatenate(this._matrix);
       
  4848 		raster.insertAbove(this);
       
  4849 		return raster;
       
  4850 	},
       
  4851 
       
  4852 	toDataURL: function() {
       
  4853 		var src = this._image && this._image.src;
       
  4854 		if (/^data:/.test(src))
       
  4855 			return src;
       
  4856 		var canvas = this.getCanvas();
       
  4857 		return canvas ? canvas.toDataURL() : null;
       
  4858 	},
       
  4859 
       
  4860 	drawImage: function(image ) {
       
  4861 		var point = Point.read(arguments, 1);
       
  4862 		this.getContext(true).drawImage(image, point.x, point.y);
       
  4863 	},
       
  4864 
       
  4865 	getAverageColor: function(object) {
       
  4866 		var bounds, path;
       
  4867 		if (!object) {
       
  4868 			bounds = this.getBounds();
       
  4869 		} else if (object instanceof PathItem) {
       
  4870 			path = object;
       
  4871 			bounds = object.getBounds();
       
  4872 		} else if (object.width) {
       
  4873 			bounds = new Rectangle(object);
       
  4874 		} else if (object.x) {
       
  4875 			bounds = new Rectangle(object.x - 0.5, object.y - 0.5, 1, 1);
       
  4876 		}
       
  4877 		var sampleSize = 32,
       
  4878 			width = Math.min(bounds.width, sampleSize),
       
  4879 			height = Math.min(bounds.height, sampleSize);
       
  4880 		var ctx = Raster._sampleContext;
       
  4881 		if (!ctx) {
       
  4882 			ctx = Raster._sampleContext = CanvasProvider.getContext(
       
  4883 					new Size(sampleSize));
       
  4884 		} else {
       
  4885 			ctx.clearRect(0, 0, sampleSize + 1, sampleSize + 1);
       
  4886 		}
       
  4887 		ctx.save();
       
  4888 		var matrix = new Matrix()
       
  4889 				.scale(width / bounds.width, height / bounds.height)
       
  4890 				.translate(-bounds.x, -bounds.y);
       
  4891 		matrix.applyToContext(ctx);
       
  4892 		if (path)
       
  4893 			path.draw(ctx, new Base({ clip: true, matrices: [matrix] }));
       
  4894 		this._matrix.applyToContext(ctx);
       
  4895 		var element = this.getElement(),
       
  4896 			size = this._size;
       
  4897 		if (element)
       
  4898 			ctx.drawImage(element, -size.width / 2, -size.height / 2);
       
  4899 		ctx.restore();
       
  4900 		var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width),
       
  4901 				Math.ceil(height)).data,
       
  4902 			channels = [0, 0, 0],
       
  4903 			total = 0;
       
  4904 		for (var i = 0, l = pixels.length; i < l; i += 4) {
       
  4905 			var alpha = pixels[i + 3];
       
  4906 			total += alpha;
       
  4907 			alpha /= 255;
       
  4908 			channels[0] += pixels[i] * alpha;
       
  4909 			channels[1] += pixels[i + 1] * alpha;
       
  4910 			channels[2] += pixels[i + 2] * alpha;
       
  4911 		}
       
  4912 		for (var i = 0; i < 3; i++)
       
  4913 			channels[i] /= total;
       
  4914 		return total ? Color.read(channels) : null;
       
  4915 	},
       
  4916 
       
  4917 	getPixel: function() {
       
  4918 		var point = Point.read(arguments);
       
  4919 		var data = this.getContext().getImageData(point.x, point.y, 1, 1).data;
       
  4920 		return new Color('rgb', [data[0] / 255, data[1] / 255, data[2] / 255],
       
  4921 				data[3] / 255);
       
  4922 	},
       
  4923 
       
  4924 	setPixel: function() {
       
  4925 		var point = Point.read(arguments),
       
  4926 			color = Color.read(arguments),
       
  4927 			components = color._convert('rgb'),
       
  4928 			alpha = color._alpha,
       
  4929 			ctx = this.getContext(true),
       
  4930 			imageData = ctx.createImageData(1, 1),
       
  4931 			data = imageData.data;
       
  4932 		data[0] = components[0] * 255;
       
  4933 		data[1] = components[1] * 255;
       
  4934 		data[2] = components[2] * 255;
       
  4935 		data[3] = alpha != null ? alpha * 255 : 255;
       
  4936 		ctx.putImageData(imageData, point.x, point.y);
       
  4937 	},
       
  4938 
       
  4939 	createImageData: function() {
       
  4940 		var size = Size.read(arguments);
       
  4941 		return this.getContext().createImageData(size.width, size.height);
       
  4942 	},
       
  4943 
       
  4944 	getImageData: function() {
       
  4945 		var rect = Rectangle.read(arguments);
       
  4946 		if (rect.isEmpty())
       
  4947 			rect = new Rectangle(this._size);
       
  4948 		return this.getContext().getImageData(rect.x, rect.y,
       
  4949 				rect.width, rect.height);
       
  4950 	},
       
  4951 
       
  4952 	setImageData: function(data ) {
       
  4953 		var point = Point.read(arguments, 1);
       
  4954 		this.getContext(true).putImageData(data, point.x, point.y);
       
  4955 	},
       
  4956 
       
  4957 	_getBounds: function(getter, matrix) {
       
  4958 		var rect = new Rectangle(this._size).setCenter(0, 0);
       
  4959 		return matrix ? matrix._transformBounds(rect) : rect;
       
  4960 	},
       
  4961 
       
  4962 	_hitTestSelf: function(point) {
       
  4963 		if (this._contains(point)) {
       
  4964 			var that = this;
       
  4965 			return new HitResult('pixel', that, {
       
  4966 				offset: point.add(that._size.divide(2)).round(),
       
  4967 				color: {
       
  4968 					get: function() {
       
  4969 						return that.getPixel(this.offset);
       
  4970 					}
       
  4971 				}
       
  4972 			});
       
  4973 		}
       
  4974 	},
       
  4975 
       
  4976 	_draw: function(ctx) {
       
  4977 		var element = this.getElement();
       
  4978 		if (element) {
       
  4979 			ctx.globalAlpha = this._opacity;
       
  4980 			ctx.drawImage(element,
       
  4981 					-this._size.width / 2, -this._size.height / 2);
       
  4982 		}
       
  4983 	},
       
  4984 
       
  4985 	_canComposite: function() {
       
  4986 		return true;
       
  4987 	}
       
  4988 });
       
  4989 
       
  4990 var PlacedSymbol = Item.extend({
       
  4991 	_class: 'PlacedSymbol',
       
  4992 	_applyMatrix: false,
       
  4993 	_canApplyMatrix: false,
       
  4994 	_boundsGetter: { getBounds: 'getStrokeBounds' },
       
  4995 	_boundsSelected: true,
       
  4996 	_serializeFields: {
       
  4997 		symbol: null
       
  4998 	},
       
  4999 
       
  5000 	initialize: function PlacedSymbol(arg0, arg1) {
       
  5001 		if (!this._initialize(arg0,
       
  5002 				arg1 !== undefined && Point.read(arguments, 1)))
       
  5003 			this.setSymbol(arg0 instanceof Symbol ? arg0 : new Symbol(arg0));
       
  5004 	},
       
  5005 
       
  5006 	_equals: function(item) {
       
  5007 		return this._symbol === item._symbol;
       
  5008 	},
       
  5009 
       
  5010 	getSymbol: function() {
       
  5011 		return this._symbol;
       
  5012 	},
       
  5013 
       
  5014 	setSymbol: function(symbol) {
       
  5015 		this._symbol = symbol;
       
  5016 		this._changed(9);
       
  5017 	},
       
  5018 
       
  5019 	clone: function(insert) {
       
  5020 		var copy = new PlacedSymbol(Item.NO_INSERT);
       
  5021 		copy.setSymbol(this._symbol);
       
  5022 		return this._clone(copy, insert);
       
  5023 	},
       
  5024 
       
  5025 	isEmpty: function() {
       
  5026 		return this._symbol._definition.isEmpty();
       
  5027 	},
       
  5028 
       
  5029 	_getBounds: function(getter, matrix, cacheItem) {
       
  5030 		var definition = this.symbol._definition;
       
  5031 		return definition._getCachedBounds(getter,
       
  5032 				matrix && matrix.chain(definition._matrix), cacheItem);
       
  5033 	},
       
  5034 
       
  5035 	_hitTestSelf: function(point, options) {
       
  5036 		var res = this._symbol._definition._hitTest(point, options);
       
  5037 		if (res)
       
  5038 			res.item = this;
       
  5039 		return res;
       
  5040 	},
       
  5041 
       
  5042 	_draw: function(ctx, param) {
       
  5043 		this.symbol._definition.draw(ctx, param);
       
  5044 	}
       
  5045 
       
  5046 });
       
  5047 
       
  5048 var HitResult = Base.extend({
       
  5049 	_class: 'HitResult',
       
  5050 
       
  5051 	initialize: function HitResult(type, item, values) {
       
  5052 		this.type = type;
       
  5053 		this.item = item;
       
  5054 		if (values) {
       
  5055 			values.enumerable = true;
       
  5056 			this.inject(values);
       
  5057 		}
       
  5058 	},
       
  5059 
       
  5060 	statics: {
       
  5061 		getOptions: function(options) {
       
  5062 			return new Base({
       
  5063 				type: null,
       
  5064 				tolerance: paper.settings.hitTolerance,
       
  5065 				fill: !options,
       
  5066 				stroke: !options,
       
  5067 				segments: !options,
       
  5068 				handles: false,
       
  5069 				ends: false,
       
  5070 				center: false,
       
  5071 				bounds: false,
       
  5072 				guides: false,
       
  5073 				selected: false
       
  5074 			}, options);
       
  5075 		}
       
  5076 	}
       
  5077 });
       
  5078 
       
  5079 var Segment = Base.extend({
       
  5080 	_class: 'Segment',
       
  5081 	beans: true,
       
  5082 
       
  5083 	initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) {
       
  5084 		var count = arguments.length,
       
  5085 			point, handleIn, handleOut;
       
  5086 		if (count === 0) {
       
  5087 		} else if (count === 1) {
       
  5088 			if (arg0.point) {
       
  5089 				point = arg0.point;
       
  5090 				handleIn = arg0.handleIn;
       
  5091 				handleOut = arg0.handleOut;
       
  5092 			} else {
       
  5093 				point = arg0;
       
  5094 			}
       
  5095 		} else if (count === 2 && typeof arg0 === 'number') {
       
  5096 			point = arguments;
       
  5097 		} else if (count <= 3) {
       
  5098 			point = arg0;
       
  5099 			handleIn = arg1;
       
  5100 			handleOut = arg2;
       
  5101 		} else {
       
  5102 			point = arg0 !== undefined ? [ arg0, arg1 ] : null;
       
  5103 			handleIn = arg2 !== undefined ? [ arg2, arg3 ] : null;
       
  5104 			handleOut = arg4 !== undefined ? [ arg4, arg5 ] : null;
       
  5105 		}
       
  5106 		new SegmentPoint(point, this, '_point');
       
  5107 		new SegmentPoint(handleIn, this, '_handleIn');
       
  5108 		new SegmentPoint(handleOut, this, '_handleOut');
       
  5109 	},
       
  5110 
       
  5111 	_serialize: function(options) {
       
  5112 		return Base.serialize(this.isLinear() ? this._point
       
  5113 				: [this._point, this._handleIn, this._handleOut],
       
  5114 				options, true);
       
  5115 	},
       
  5116 
       
  5117 	_changed: function(point) {
       
  5118 		var path = this._path;
       
  5119 		if (!path)
       
  5120 			return;
       
  5121 		var curves = path._curves,
       
  5122 			index = this._index,
       
  5123 			curve;
       
  5124 		if (curves) {
       
  5125 			if ((!point || point === this._point || point === this._handleIn)
       
  5126 					&& (curve = index > 0 ? curves[index - 1] : path._closed
       
  5127 						? curves[curves.length - 1] : null))
       
  5128 				curve._changed();
       
  5129 			if ((!point || point === this._point || point === this._handleOut)
       
  5130 					&& (curve = curves[index]))
       
  5131 				curve._changed();
       
  5132 		}
       
  5133 		path._changed(25);
       
  5134 	},
       
  5135 
       
  5136 	getPoint: function() {
       
  5137 		return this._point;
       
  5138 	},
       
  5139 
       
  5140 	setPoint: function() {
       
  5141 		var point = Point.read(arguments);
       
  5142 		this._point.set(point.x, point.y);
       
  5143 	},
       
  5144 
       
  5145 	getHandleIn: function() {
       
  5146 		return this._handleIn;
       
  5147 	},
       
  5148 
       
  5149 	setHandleIn: function() {
       
  5150 		var point = Point.read(arguments);
       
  5151 		this._handleIn.set(point.x, point.y);
       
  5152 	},
       
  5153 
       
  5154 	getHandleOut: function() {
       
  5155 		return this._handleOut;
       
  5156 	},
       
  5157 
       
  5158 	setHandleOut: function() {
       
  5159 		var point = Point.read(arguments);
       
  5160 		this._handleOut.set(point.x, point.y);
       
  5161 	},
       
  5162 
       
  5163 	isLinear: function() {
       
  5164 		return this._handleIn.isZero() && this._handleOut.isZero();
       
  5165 	},
       
  5166 
       
  5167 	setLinear: function(linear) {
       
  5168 		if (linear) {
       
  5169 			this._handleIn.set(0, 0);
       
  5170 			this._handleOut.set(0, 0);
       
  5171 		} else {
       
  5172 		}
       
  5173 	},
       
  5174 
       
  5175 	isColinear: function(segment) {
       
  5176 		var next1 = this.getNext(),
       
  5177 			next2 = segment.getNext();
       
  5178 		return this._handleOut.isZero() && next1._handleIn.isZero()
       
  5179 				&& segment._handleOut.isZero() && next2._handleIn.isZero()
       
  5180 				&& next1._point.subtract(this._point).isColinear(
       
  5181 					next2._point.subtract(segment._point));
       
  5182 	},
       
  5183 
       
  5184 	isOrthogonal: function() {
       
  5185 		var prev = this.getPrevious(),
       
  5186 			next = this.getNext();
       
  5187 		return prev._handleOut.isZero() && this._handleIn.isZero()
       
  5188 			&& this._handleOut.isZero() && next._handleIn.isZero()
       
  5189 			&& this._point.subtract(prev._point).isOrthogonal(
       
  5190 					next._point.subtract(this._point));
       
  5191 	},
       
  5192 
       
  5193 	isArc: function() {
       
  5194 		var next = this.getNext(),
       
  5195 			handle1 = this._handleOut,
       
  5196 			handle2 = next._handleIn,
       
  5197 			kappa = 0.5522847498307936;
       
  5198 		if (handle1.isOrthogonal(handle2)) {
       
  5199 			var from = this._point,
       
  5200 				to = next._point,
       
  5201 				corner = new Line(from, handle1, true).intersect(
       
  5202 						new Line(to, handle2, true), true);
       
  5203 			return corner && Numerical.isZero(handle1.getLength() /
       
  5204 					corner.subtract(from).getLength() - kappa)
       
  5205 				&& Numerical.isZero(handle2.getLength() /
       
  5206 					corner.subtract(to).getLength() - kappa);
       
  5207 		}
       
  5208 		return false;
       
  5209 	},
       
  5210 
       
  5211 	_selectionState: 0,
       
  5212 
       
  5213 	isSelected: function(_point) {
       
  5214 		var state = this._selectionState;
       
  5215 		return !_point ? !!(state & 7)
       
  5216 			: _point === this._point ? !!(state & 4)
       
  5217 			: _point === this._handleIn ? !!(state & 1)
       
  5218 			: _point === this._handleOut ? !!(state & 2)
       
  5219 			: false;
       
  5220 	},
       
  5221 
       
  5222 	setSelected: function(selected, _point) {
       
  5223 		var path = this._path,
       
  5224 			selected = !!selected,
       
  5225 			state = this._selectionState,
       
  5226 			oldState = state,
       
  5227 			flag = !_point ? 7
       
  5228 					: _point === this._point ? 4
       
  5229 					: _point === this._handleIn ? 1
       
  5230 					: _point === this._handleOut ? 2
       
  5231 					: 0;
       
  5232 		if (selected) {
       
  5233 			state |= flag;
       
  5234 		} else {
       
  5235 			state &= ~flag;
       
  5236 		}
       
  5237 		this._selectionState = state;
       
  5238 		if (path && state !== oldState) {
       
  5239 			path._updateSelection(this, oldState, state);
       
  5240 			path._changed(129);
       
  5241 		}
       
  5242 	},
       
  5243 
       
  5244 	getIndex: function() {
       
  5245 		return this._index !== undefined ? this._index : null;
       
  5246 	},
       
  5247 
       
  5248 	getPath: function() {
       
  5249 		return this._path || null;
       
  5250 	},
       
  5251 
       
  5252 	getCurve: function() {
       
  5253 		var path = this._path,
       
  5254 			index = this._index;
       
  5255 		if (path) {
       
  5256 			if (index > 0 && !path._closed
       
  5257 					&& index === path._segments.length - 1)
       
  5258 				index--;
       
  5259 			return path.getCurves()[index] || null;
       
  5260 		}
       
  5261 		return null;
       
  5262 	},
       
  5263 
       
  5264 	getLocation: function() {
       
  5265 		var curve = this.getCurve();
       
  5266 		return curve
       
  5267 				? new CurveLocation(curve, this === curve._segment1 ? 0 : 1)
       
  5268 				: null;
       
  5269 	},
       
  5270 
       
  5271 	getNext: function() {
       
  5272 		var segments = this._path && this._path._segments;
       
  5273 		return segments && (segments[this._index + 1]
       
  5274 				|| this._path._closed && segments[0]) || null;
       
  5275 	},
       
  5276 
       
  5277 	getPrevious: function() {
       
  5278 		var segments = this._path && this._path._segments;
       
  5279 		return segments && (segments[this._index - 1]
       
  5280 				|| this._path._closed && segments[segments.length - 1]) || null;
       
  5281 	},
       
  5282 
       
  5283 	reverse: function() {
       
  5284 		return new Segment(this._point, this._handleOut, this._handleIn);
       
  5285 	},
       
  5286 
       
  5287 	remove: function() {
       
  5288 		return this._path ? !!this._path.removeSegment(this._index) : false;
       
  5289 	},
       
  5290 
       
  5291 	clone: function() {
       
  5292 		return new Segment(this._point, this._handleIn, this._handleOut);
       
  5293 	},
       
  5294 
       
  5295 	equals: function(segment) {
       
  5296 		return segment === this || segment && this._class === segment._class
       
  5297 				&& this._point.equals(segment._point)
       
  5298 				&& this._handleIn.equals(segment._handleIn)
       
  5299 				&& this._handleOut.equals(segment._handleOut)
       
  5300 				|| false;
       
  5301 	},
       
  5302 
       
  5303 	toString: function() {
       
  5304 		var parts = [ 'point: ' + this._point ];
       
  5305 		if (!this._handleIn.isZero())
       
  5306 			parts.push('handleIn: ' + this._handleIn);
       
  5307 		if (!this._handleOut.isZero())
       
  5308 			parts.push('handleOut: ' + this._handleOut);
       
  5309 		return '{ ' + parts.join(', ') + ' }';
       
  5310 	},
       
  5311 
       
  5312 	transform: function(matrix) {
       
  5313 		this._transformCoordinates(matrix, new Array(6), true);
       
  5314 		this._changed();
       
  5315 	},
       
  5316 
       
  5317 	_transformCoordinates: function(matrix, coords, change) {
       
  5318 		var point = this._point,
       
  5319 			handleIn = !change || !this._handleIn.isZero()
       
  5320 					? this._handleIn : null,
       
  5321 			handleOut = !change || !this._handleOut.isZero()
       
  5322 					? this._handleOut : null,
       
  5323 			x = point._x,
       
  5324 			y = point._y,
       
  5325 			i = 2;
       
  5326 		coords[0] = x;
       
  5327 		coords[1] = y;
       
  5328 		if (handleIn) {
       
  5329 			coords[i++] = handleIn._x + x;
       
  5330 			coords[i++] = handleIn._y + y;
       
  5331 		}
       
  5332 		if (handleOut) {
       
  5333 			coords[i++] = handleOut._x + x;
       
  5334 			coords[i++] = handleOut._y + y;
       
  5335 		}
       
  5336 		if (matrix) {
       
  5337 			matrix._transformCoordinates(coords, coords, i / 2);
       
  5338 			x = coords[0];
       
  5339 			y = coords[1];
       
  5340 			if (change) {
       
  5341 				point._x = x;
       
  5342 				point._y = y;
       
  5343 				i  = 2;
       
  5344 				if (handleIn) {
       
  5345 					handleIn._x = coords[i++] - x;
       
  5346 					handleIn._y = coords[i++] - y;
       
  5347 				}
       
  5348 				if (handleOut) {
       
  5349 					handleOut._x = coords[i++] - x;
       
  5350 					handleOut._y = coords[i++] - y;
       
  5351 				}
       
  5352 			} else {
       
  5353 				if (!handleIn) {
       
  5354 					coords[i++] = x;
       
  5355 					coords[i++] = y;
       
  5356 				}
       
  5357 				if (!handleOut) {
       
  5358 					coords[i++] = x;
       
  5359 					coords[i++] = y;
       
  5360 				}
       
  5361 			}
       
  5362 		}
       
  5363 		return coords;
       
  5364 	}
       
  5365 });
       
  5366 
       
  5367 var SegmentPoint = Point.extend({
       
  5368 	initialize: function SegmentPoint(point, owner, key) {
       
  5369 		var x, y, selected;
       
  5370 		if (!point) {
       
  5371 			x = y = 0;
       
  5372 		} else if ((x = point[0]) !== undefined) {
       
  5373 			y = point[1];
       
  5374 		} else {
       
  5375 			var pt = point;
       
  5376 			if ((x = pt.x) === undefined) {
       
  5377 				pt = Point.read(arguments);
       
  5378 				x = pt.x;
       
  5379 			}
       
  5380 			y = pt.y;
       
  5381 			selected = pt.selected;
       
  5382 		}
       
  5383 		this._x = x;
       
  5384 		this._y = y;
       
  5385 		this._owner = owner;
       
  5386 		owner[key] = this;
       
  5387 		if (selected)
       
  5388 			this.setSelected(true);
       
  5389 	},
       
  5390 
       
  5391 	set: function(x, y) {
       
  5392 		this._x = x;
       
  5393 		this._y = y;
       
  5394 		this._owner._changed(this);
       
  5395 		return this;
       
  5396 	},
       
  5397 
       
  5398 	_serialize: function(options) {
       
  5399 		var f = options.formatter,
       
  5400 			x = f.number(this._x),
       
  5401 			y = f.number(this._y);
       
  5402 		return this.isSelected()
       
  5403 				? { x: x, y: y, selected: true }
       
  5404 				: [x, y];
       
  5405 	},
       
  5406 
       
  5407 	getX: function() {
       
  5408 		return this._x;
       
  5409 	},
       
  5410 
       
  5411 	setX: function(x) {
       
  5412 		this._x = x;
       
  5413 		this._owner._changed(this);
       
  5414 	},
       
  5415 
       
  5416 	getY: function() {
       
  5417 		return this._y;
       
  5418 	},
       
  5419 
       
  5420 	setY: function(y) {
       
  5421 		this._y = y;
       
  5422 		this._owner._changed(this);
       
  5423 	},
       
  5424 
       
  5425 	isZero: function() {
       
  5426 		return Numerical.isZero(this._x) && Numerical.isZero(this._y);
       
  5427 	},
       
  5428 
       
  5429 	setSelected: function(selected) {
       
  5430 		this._owner.setSelected(selected, this);
       
  5431 	},
       
  5432 
       
  5433 	isSelected: function() {
       
  5434 		return this._owner.isSelected(this);
       
  5435 	}
       
  5436 });
       
  5437 
       
  5438 var Curve = Base.extend({
       
  5439 	_class: 'Curve',
       
  5440 
       
  5441 	initialize: function Curve(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
       
  5442 		var count = arguments.length;
       
  5443 		if (count === 3) {
       
  5444 			this._path = arg0;
       
  5445 			this._segment1 = arg1;
       
  5446 			this._segment2 = arg2;
       
  5447 		} else if (count === 0) {
       
  5448 			this._segment1 = new Segment();
       
  5449 			this._segment2 = new Segment();
       
  5450 		} else if (count === 1) {
       
  5451 			this._segment1 = new Segment(arg0.segment1);
       
  5452 			this._segment2 = new Segment(arg0.segment2);
       
  5453 		} else if (count === 2) {
       
  5454 			this._segment1 = new Segment(arg0);
       
  5455 			this._segment2 = new Segment(arg1);
       
  5456 		} else {
       
  5457 			var point1, handle1, handle2, point2;
       
  5458 			if (count === 4) {
       
  5459 				point1 = arg0;
       
  5460 				handle1 = arg1;
       
  5461 				handle2 = arg2;
       
  5462 				point2 = arg3;
       
  5463 			} else if (count === 8) {
       
  5464 				point1 = [arg0, arg1];
       
  5465 				point2 = [arg6, arg7];
       
  5466 				handle1 = [arg2 - arg0, arg3 - arg1];
       
  5467 				handle2 = [arg4 - arg6, arg5 - arg7];
       
  5468 			}
       
  5469 			this._segment1 = new Segment(point1, null, handle1);
       
  5470 			this._segment2 = new Segment(point2, handle2, null);
       
  5471 		}
       
  5472 	},
       
  5473 
       
  5474 	_changed: function() {
       
  5475 		this._length = this._bounds = undefined;
       
  5476 	},
       
  5477 
       
  5478 	getPoint1: function() {
       
  5479 		return this._segment1._point;
       
  5480 	},
       
  5481 
       
  5482 	setPoint1: function() {
       
  5483 		var point = Point.read(arguments);
       
  5484 		this._segment1._point.set(point.x, point.y);
       
  5485 	},
       
  5486 
       
  5487 	getPoint2: function() {
       
  5488 		return this._segment2._point;
       
  5489 	},
       
  5490 
       
  5491 	setPoint2: function() {
       
  5492 		var point = Point.read(arguments);
       
  5493 		this._segment2._point.set(point.x, point.y);
       
  5494 	},
       
  5495 
       
  5496 	getHandle1: function() {
       
  5497 		return this._segment1._handleOut;
       
  5498 	},
       
  5499 
       
  5500 	setHandle1: function() {
       
  5501 		var point = Point.read(arguments);
       
  5502 		this._segment1._handleOut.set(point.x, point.y);
       
  5503 	},
       
  5504 
       
  5505 	getHandle2: function() {
       
  5506 		return this._segment2._handleIn;
       
  5507 	},
       
  5508 
       
  5509 	setHandle2: function() {
       
  5510 		var point = Point.read(arguments);
       
  5511 		this._segment2._handleIn.set(point.x, point.y);
       
  5512 	},
       
  5513 
       
  5514 	getSegment1: function() {
       
  5515 		return this._segment1;
       
  5516 	},
       
  5517 
       
  5518 	getSegment2: function() {
       
  5519 		return this._segment2;
       
  5520 	},
       
  5521 
       
  5522 	getPath: function() {
       
  5523 		return this._path;
       
  5524 	},
       
  5525 
       
  5526 	getIndex: function() {
       
  5527 		return this._segment1._index;
       
  5528 	},
       
  5529 
       
  5530 	getNext: function() {
       
  5531 		var curves = this._path && this._path._curves;
       
  5532 		return curves && (curves[this._segment1._index + 1]
       
  5533 				|| this._path._closed && curves[0]) || null;
       
  5534 	},
       
  5535 
       
  5536 	getPrevious: function() {
       
  5537 		var curves = this._path && this._path._curves;
       
  5538 		return curves && (curves[this._segment1._index - 1]
       
  5539 				|| this._path._closed && curves[curves.length - 1]) || null;
       
  5540 	},
       
  5541 
       
  5542 	isSelected: function() {
       
  5543 		return this.getPoint1().isSelected()
       
  5544 				&& this.getHandle2().isSelected()
       
  5545 				&& this.getHandle2().isSelected()
       
  5546 				&& this.getPoint2().isSelected();
       
  5547 	},
       
  5548 
       
  5549 	setSelected: function(selected) {
       
  5550 		this.getPoint1().setSelected(selected);
       
  5551 		this.getHandle1().setSelected(selected);
       
  5552 		this.getHandle2().setSelected(selected);
       
  5553 		this.getPoint2().setSelected(selected);
       
  5554 	},
       
  5555 
       
  5556 	getValues: function(matrix) {
       
  5557 		return Curve.getValues(this._segment1, this._segment2, matrix);
       
  5558 	},
       
  5559 
       
  5560 	getPoints: function() {
       
  5561 		var coords = this.getValues(),
       
  5562 			points = [];
       
  5563 		for (var i = 0; i < 8; i += 2)
       
  5564 			points.push(new Point(coords[i], coords[i + 1]));
       
  5565 		return points;
       
  5566 	},
       
  5567 
       
  5568 	getLength: function() {
       
  5569 		if (this._length == null) {
       
  5570 			this._length = this.isLinear()
       
  5571 				? this._segment2._point.getDistance(this._segment1._point)
       
  5572 				: Curve.getLength(this.getValues(), 0, 1);
       
  5573 		}
       
  5574 		return this._length;
       
  5575 	},
       
  5576 
       
  5577 	getArea: function() {
       
  5578 		return Curve.getArea(this.getValues());
       
  5579 	},
       
  5580 
       
  5581 	getPart: function(from, to) {
       
  5582 		return new Curve(Curve.getPart(this.getValues(), from, to));
       
  5583 	},
       
  5584 
       
  5585 	getPartLength: function(from, to) {
       
  5586 		return Curve.getLength(this.getValues(), from, to);
       
  5587 	},
       
  5588 
       
  5589 	isLinear: function() {
       
  5590 		return this._segment1._handleOut.isZero()
       
  5591 				&& this._segment2._handleIn.isZero();
       
  5592 	},
       
  5593 
       
  5594 	getIntersections: function(curve) {
       
  5595 		return Curve.filterIntersections(Curve.getIntersections(
       
  5596 				this.getValues(), curve.getValues(), this, curve, []));
       
  5597 	},
       
  5598 
       
  5599 	_getParameter: function(offset, isParameter) {
       
  5600 		return isParameter
       
  5601 				? offset
       
  5602 				: offset && offset.curve === this
       
  5603 					? offset.parameter
       
  5604 					: offset === undefined && isParameter === undefined
       
  5605 						? 0.5
       
  5606 						: this.getParameterAt(offset, 0);
       
  5607 	},
       
  5608 
       
  5609 	divide: function(offset, isParameter, ignoreLinear) {
       
  5610 		var parameter = this._getParameter(offset, isParameter),
       
  5611 			tolerance = 0.000001,
       
  5612 			res = null;
       
  5613 		if (parameter > tolerance && parameter < 1 - tolerance) {
       
  5614 			var parts = Curve.subdivide(this.getValues(), parameter),
       
  5615 				isLinear = ignoreLinear ? false : this.isLinear(),
       
  5616 				left = parts[0],
       
  5617 				right = parts[1];
       
  5618 
       
  5619 			if (!isLinear) {
       
  5620 				this._segment1._handleOut.set(left[2] - left[0],
       
  5621 						left[3] - left[1]);
       
  5622 				this._segment2._handleIn.set(right[4] - right[6],
       
  5623 						right[5] - right[7]);
       
  5624 			}
       
  5625 
       
  5626 			var x = left[6], y = left[7],
       
  5627 				segment = new Segment(new Point(x, y),
       
  5628 						!isLinear && new Point(left[4] - x, left[5] - y),
       
  5629 						!isLinear && new Point(right[2] - x, right[3] - y));
       
  5630 
       
  5631 			if (this._path) {
       
  5632 				if (this._segment1._index > 0 && this._segment2._index === 0) {
       
  5633 					this._path.add(segment);
       
  5634 				} else {
       
  5635 					this._path.insert(this._segment2._index, segment);
       
  5636 				}
       
  5637 				res = this;
       
  5638 			} else {
       
  5639 				var end = this._segment2;
       
  5640 				this._segment2 = segment;
       
  5641 				res = new Curve(segment, end);
       
  5642 			}
       
  5643 		}
       
  5644 		return res;
       
  5645 	},
       
  5646 
       
  5647 	split: function(offset, isParameter) {
       
  5648 		return this._path
       
  5649 			? this._path.split(this._segment1._index,
       
  5650 					this._getParameter(offset, isParameter))
       
  5651 			: null;
       
  5652 	},
       
  5653 
       
  5654 	reverse: function() {
       
  5655 		return new Curve(this._segment2.reverse(), this._segment1.reverse());
       
  5656 	},
       
  5657 
       
  5658 	remove: function() {
       
  5659 		var removed = false;
       
  5660 		if (this._path) {
       
  5661 			var segment2 = this._segment2,
       
  5662 				handleOut = segment2._handleOut;
       
  5663 			removed = segment2.remove();
       
  5664 			if (removed)
       
  5665 				this._segment1._handleOut.set(handleOut.x, handleOut.y);
       
  5666 		}
       
  5667 		return removed;
       
  5668 	},
       
  5669 
       
  5670 	clone: function() {
       
  5671 		return new Curve(this._segment1, this._segment2);
       
  5672 	},
       
  5673 
       
  5674 	toString: function() {
       
  5675 		var parts = [ 'point1: ' + this._segment1._point ];
       
  5676 		if (!this._segment1._handleOut.isZero())
       
  5677 			parts.push('handle1: ' + this._segment1._handleOut);
       
  5678 		if (!this._segment2._handleIn.isZero())
       
  5679 			parts.push('handle2: ' + this._segment2._handleIn);
       
  5680 		parts.push('point2: ' + this._segment2._point);
       
  5681 		return '{ ' + parts.join(', ') + ' }';
       
  5682 	},
       
  5683 
       
  5684 statics: {
       
  5685 	getValues: function(segment1, segment2, matrix) {
       
  5686 		var p1 = segment1._point,
       
  5687 			h1 = segment1._handleOut,
       
  5688 			h2 = segment2._handleIn,
       
  5689 			p2 = segment2._point,
       
  5690 			values = [
       
  5691 				p1._x, p1._y,
       
  5692 				p1._x + h1._x, p1._y + h1._y,
       
  5693 				p2._x + h2._x, p2._y + h2._y,
       
  5694 				p2._x, p2._y
       
  5695 			];
       
  5696 		if (matrix)
       
  5697 			matrix._transformCoordinates(values, values, 4);
       
  5698 		return values;
       
  5699 	},
       
  5700 
       
  5701 	evaluate: function(v, t, type) {
       
  5702 		var p1x = v[0], p1y = v[1],
       
  5703 			c1x = v[2], c1y = v[3],
       
  5704 			c2x = v[4], c2y = v[5],
       
  5705 			p2x = v[6], p2y = v[7],
       
  5706 			tolerance = 0.000001,
       
  5707 			x, y;
       
  5708 
       
  5709 		if (type === 0 && (t < tolerance || t > 1 - tolerance)) {
       
  5710 			var isZero = t < tolerance;
       
  5711 			x = isZero ? p1x : p2x;
       
  5712 			y = isZero ? p1y : p2y;
       
  5713 		} else {
       
  5714 			var cx = 3 * (c1x - p1x),
       
  5715 				bx = 3 * (c2x - c1x) - cx,
       
  5716 				ax = p2x - p1x - cx - bx,
       
  5717 
       
  5718 				cy = 3 * (c1y - p1y),
       
  5719 				by = 3 * (c2y - c1y) - cy,
       
  5720 				ay = p2y - p1y - cy - by;
       
  5721 			if (type === 0) {
       
  5722 				x = ((ax * t + bx) * t + cx) * t + p1x;
       
  5723 				y = ((ay * t + by) * t + cy) * t + p1y;
       
  5724 			} else {
       
  5725 				if (t < tolerance && c1x === p1x && c1y === p1y
       
  5726 						|| t > 1 - tolerance && c2x === p2x && c2y === p2y) {
       
  5727 					x = c2x - c1x;
       
  5728 					y = c2y - c1y;
       
  5729 				} else if (t < tolerance) {
       
  5730 					x = cx;
       
  5731 					y = cy;
       
  5732 				} else if (t > 1 - tolerance) {
       
  5733 					x = 3 * (p2x - c2x);
       
  5734 					y = 3 * (p2y - c2y);
       
  5735 				} else {
       
  5736 					x = (3 * ax * t + 2 * bx) * t + cx;
       
  5737 					y = (3 * ay * t + 2 * by) * t + cy;
       
  5738 				}
       
  5739 				if (type === 3) {
       
  5740 					var x2 = 6 * ax * t + 2 * bx,
       
  5741 						y2 = 6 * ay * t + 2 * by;
       
  5742 					return (x * y2 - y * x2) / Math.pow(x * x + y * y, 3 / 2);
       
  5743 				}
       
  5744 			}
       
  5745 		}
       
  5746 		return type === 2 ? new Point(y, -x) : new Point(x, y);
       
  5747 	},
       
  5748 
       
  5749 	subdivide: function(v, t) {
       
  5750 		var p1x = v[0], p1y = v[1],
       
  5751 			c1x = v[2], c1y = v[3],
       
  5752 			c2x = v[4], c2y = v[5],
       
  5753 			p2x = v[6], p2y = v[7];
       
  5754 		if (t === undefined)
       
  5755 			t = 0.5;
       
  5756 		var u = 1 - t,
       
  5757 			p3x = u * p1x + t * c1x, p3y = u * p1y + t * c1y,
       
  5758 			p4x = u * c1x + t * c2x, p4y = u * c1y + t * c2y,
       
  5759 			p5x = u * c2x + t * p2x, p5y = u * c2y + t * p2y,
       
  5760 			p6x = u * p3x + t * p4x, p6y = u * p3y + t * p4y,
       
  5761 			p7x = u * p4x + t * p5x, p7y = u * p4y + t * p5y,
       
  5762 			p8x = u * p6x + t * p7x, p8y = u * p6y + t * p7y;
       
  5763 		return [
       
  5764 			[p1x, p1y, p3x, p3y, p6x, p6y, p8x, p8y],
       
  5765 			[p8x, p8y, p7x, p7y, p5x, p5y, p2x, p2y]
       
  5766 		];
       
  5767 	},
       
  5768 
       
  5769 	solveCubic: function (v, coord, val, roots, min, max) {
       
  5770 		var p1 = v[coord],
       
  5771 			c1 = v[coord + 2],
       
  5772 			c2 = v[coord + 4],
       
  5773 			p2 = v[coord + 6],
       
  5774 			c = 3 * (c1 - p1),
       
  5775 			b = 3 * (c2 - c1) - c,
       
  5776 			a = p2 - p1 - c - b,
       
  5777 			isZero = Numerical.isZero;
       
  5778 		if (isZero(a) && isZero(b))
       
  5779 			a = b = 0;
       
  5780 		return Numerical.solveCubic(a, b, c, p1 - val, roots, min, max);
       
  5781 	},
       
  5782 
       
  5783 	getParameterOf: function(v, x, y) {
       
  5784 		var tolerance = 0.000001;
       
  5785 		if (Math.abs(v[0] - x) < tolerance && Math.abs(v[1] - y) < tolerance)
       
  5786 			return 0;
       
  5787 		if (Math.abs(v[6] - x) < tolerance && Math.abs(v[7] - y) < tolerance)
       
  5788 			return 1;
       
  5789 		var txs = [],
       
  5790 			tys = [],
       
  5791 			sx = Curve.solveCubic(v, 0, x, txs, 0, 1),
       
  5792 			sy = Curve.solveCubic(v, 1, y, tys, 0, 1),
       
  5793 			tx, ty;
       
  5794 		for (var cx = 0;  sx == -1 || cx < sx;) {
       
  5795 			if (sx == -1 || (tx = txs[cx++]) >= 0 && tx <= 1) {
       
  5796 				for (var cy = 0; sy == -1 || cy < sy;) {
       
  5797 					if (sy == -1 || (ty = tys[cy++]) >= 0 && ty <= 1) {
       
  5798 						if (sx == -1) tx = ty;
       
  5799 						else if (sy == -1) ty = tx;
       
  5800 						if (Math.abs(tx - ty) < tolerance)
       
  5801 							return (tx + ty) * 0.5;
       
  5802 					}
       
  5803 				}
       
  5804 				if (sx == -1)
       
  5805 					break;
       
  5806 			}
       
  5807 		}
       
  5808 		return null;
       
  5809 	},
       
  5810 
       
  5811 	getPart: function(v, from, to) {
       
  5812 		if (from > 0)
       
  5813 			v = Curve.subdivide(v, from)[1];
       
  5814 		if (to < 1)
       
  5815 			v = Curve.subdivide(v, (to - from) / (1 - from))[0];
       
  5816 		return v;
       
  5817 	},
       
  5818 
       
  5819 	isLinear: function(v) {
       
  5820 		var isZero = Numerical.isZero;
       
  5821 		return isZero(v[0] - v[2]) && isZero(v[1] - v[3])
       
  5822 				&& isZero(v[4] - v[6]) && isZero(v[5] - v[7]);
       
  5823 	},
       
  5824 
       
  5825 	isFlatEnough: function(v, tolerance) {
       
  5826 		var p1x = v[0], p1y = v[1],
       
  5827 			c1x = v[2], c1y = v[3],
       
  5828 			c2x = v[4], c2y = v[5],
       
  5829 			p2x = v[6], p2y = v[7],
       
  5830 			ux = 3 * c1x - 2 * p1x - p2x,
       
  5831 			uy = 3 * c1y - 2 * p1y - p2y,
       
  5832 			vx = 3 * c2x - 2 * p2x - p1x,
       
  5833 			vy = 3 * c2y - 2 * p2y - p1y;
       
  5834 		return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy)
       
  5835 				< 10 * tolerance * tolerance;
       
  5836 	},
       
  5837 
       
  5838 	getArea: function(v) {
       
  5839 		var p1x = v[0], p1y = v[1],
       
  5840 			c1x = v[2], c1y = v[3],
       
  5841 			c2x = v[4], c2y = v[5],
       
  5842 			p2x = v[6], p2y = v[7];
       
  5843 		return (  3.0 * c1y * p1x - 1.5 * c1y * c2x
       
  5844 				- 1.5 * c1y * p2x - 3.0 * p1y * c1x
       
  5845 				- 1.5 * p1y * c2x - 0.5 * p1y * p2x
       
  5846 				+ 1.5 * c2y * p1x + 1.5 * c2y * c1x
       
  5847 				- 3.0 * c2y * p2x + 0.5 * p2y * p1x
       
  5848 				+ 1.5 * p2y * c1x + 3.0 * p2y * c2x) / 10;
       
  5849 	},
       
  5850 
       
  5851 	getEdgeSum: function(v) {
       
  5852 		return	  (v[0] - v[2]) * (v[3] + v[1])
       
  5853 				+ (v[2] - v[4]) * (v[5] + v[3])
       
  5854 				+ (v[4] - v[6]) * (v[7] + v[5]);
       
  5855 	},
       
  5856 
       
  5857 	getBounds: function(v) {
       
  5858 		var min = v.slice(0, 2),
       
  5859 			max = min.slice(),
       
  5860 			roots = [0, 0];
       
  5861 		for (var i = 0; i < 2; i++)
       
  5862 			Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6],
       
  5863 					i, 0, min, max, roots);
       
  5864 		return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]);
       
  5865 	},
       
  5866 
       
  5867 	_addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) {
       
  5868 		function add(value, padding) {
       
  5869 			var left = value - padding,
       
  5870 				right = value + padding;
       
  5871 			if (left < min[coord])
       
  5872 				min[coord] = left;
       
  5873 			if (right > max[coord])
       
  5874 				max[coord] = right;
       
  5875 		}
       
  5876 		var a = 3 * (v1 - v2) - v0 + v3,
       
  5877 			b = 2 * (v0 + v2) - 4 * v1,
       
  5878 			c = v1 - v0,
       
  5879 			count = Numerical.solveQuadratic(a, b, c, roots),
       
  5880 			tMin = 0.000001,
       
  5881 			tMax = 1 - tMin;
       
  5882 		add(v3, 0);
       
  5883 		for (var i = 0; i < count; i++) {
       
  5884 			var t = roots[i],
       
  5885 				u = 1 - t;
       
  5886 			if (tMin < t && t < tMax)
       
  5887 				add(u * u * u * v0
       
  5888 					+ 3 * u * u * t * v1
       
  5889 					+ 3 * u * t * t * v2
       
  5890 					+ t * t * t * v3,
       
  5891 					padding);
       
  5892 		}
       
  5893 	}
       
  5894 }}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', 'getRoughBounds'],
       
  5895 	function(name) {
       
  5896 		this[name] = function() {
       
  5897 			if (!this._bounds)
       
  5898 				this._bounds = {};
       
  5899 			var bounds = this._bounds[name];
       
  5900 			if (!bounds) {
       
  5901 				bounds = this._bounds[name] = Path[name]([this._segment1,
       
  5902 						this._segment2], false, this._path.getStyle());
       
  5903 			}
       
  5904 			return bounds.clone();
       
  5905 		};
       
  5906 	},
       
  5907 {
       
  5908 
       
  5909 }), Base.each(['getPoint', 'getTangent', 'getNormal', 'getCurvature'],
       
  5910 	function(name, index) {
       
  5911 		this[name + 'At'] = function(offset, isParameter) {
       
  5912 			var values = this.getValues();
       
  5913 			return Curve.evaluate(values, isParameter
       
  5914 					? offset : Curve.getParameterAt(values, offset, 0), index);
       
  5915 		};
       
  5916 		this[name] = function(parameter) {
       
  5917 			return Curve.evaluate(this.getValues(), parameter, index);
       
  5918 		};
       
  5919 	},
       
  5920 {
       
  5921 	beans: false,
       
  5922 
       
  5923 	getParameterAt: function(offset, start) {
       
  5924 		return Curve.getParameterAt(this.getValues(), offset, start);
       
  5925 	},
       
  5926 
       
  5927 	getParameterOf: function() {
       
  5928 		var point = Point.read(arguments);
       
  5929 		return Curve.getParameterOf(this.getValues(), point.x, point.y);
       
  5930 	},
       
  5931 
       
  5932 	getLocationAt: function(offset, isParameter) {
       
  5933 		if (!isParameter)
       
  5934 			offset = this.getParameterAt(offset);
       
  5935 		return offset >= 0 && offset <= 1 && new CurveLocation(this, offset);
       
  5936 	},
       
  5937 
       
  5938 	getLocationOf: function() {
       
  5939 		return this.getLocationAt(this.getParameterOf(Point.read(arguments)),
       
  5940 				true);
       
  5941 	},
       
  5942 
       
  5943 	getOffsetOf: function() {
       
  5944 		var loc = this.getLocationOf.apply(this, arguments);
       
  5945 		return loc ? loc.getOffset() : null;
       
  5946 	},
       
  5947 
       
  5948 	getNearestLocation: function() {
       
  5949 		var point = Point.read(arguments),
       
  5950 			values = this.getValues(),
       
  5951 			count = 100,
       
  5952 			minDist = Infinity,
       
  5953 			minT = 0;
       
  5954 
       
  5955 		function refine(t) {
       
  5956 			if (t >= 0 && t <= 1) {
       
  5957 				var dist = point.getDistance(
       
  5958 						Curve.evaluate(values, t, 0), true);
       
  5959 				if (dist < minDist) {
       
  5960 					minDist = dist;
       
  5961 					minT = t;
       
  5962 					return true;
       
  5963 				}
       
  5964 			}
       
  5965 		}
       
  5966 
       
  5967 		for (var i = 0; i <= count; i++)
       
  5968 			refine(i / count);
       
  5969 
       
  5970 		var step = 1 / (count * 2);
       
  5971 		while (step > 0.000001) {
       
  5972 			if (!refine(minT - step) && !refine(minT + step))
       
  5973 				step /= 2;
       
  5974 		}
       
  5975 		var pt = Curve.evaluate(values, minT, 0);
       
  5976 		return new CurveLocation(this, minT, pt, null, null, null,
       
  5977 				point.getDistance(pt));
       
  5978 	},
       
  5979 
       
  5980 	getNearestPoint: function() {
       
  5981 		return this.getNearestLocation.apply(this, arguments).getPoint();
       
  5982 	}
       
  5983 
       
  5984 }),
       
  5985 new function() {
       
  5986 
       
  5987 	function getLengthIntegrand(v) {
       
  5988 		var p1x = v[0], p1y = v[1],
       
  5989 			c1x = v[2], c1y = v[3],
       
  5990 			c2x = v[4], c2y = v[5],
       
  5991 			p2x = v[6], p2y = v[7],
       
  5992 
       
  5993 			ax = 9 * (c1x - c2x) + 3 * (p2x - p1x),
       
  5994 			bx = 6 * (p1x + c2x) - 12 * c1x,
       
  5995 			cx = 3 * (c1x - p1x),
       
  5996 
       
  5997 			ay = 9 * (c1y - c2y) + 3 * (p2y - p1y),
       
  5998 			by = 6 * (p1y + c2y) - 12 * c1y,
       
  5999 			cy = 3 * (c1y - p1y);
       
  6000 
       
  6001 		return function(t) {
       
  6002 			var dx = (ax * t + bx) * t + cx,
       
  6003 				dy = (ay * t + by) * t + cy;
       
  6004 			return Math.sqrt(dx * dx + dy * dy);
       
  6005 		};
       
  6006 	}
       
  6007 
       
  6008 	function getIterations(a, b) {
       
  6009 		return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32)));
       
  6010 	}
       
  6011 
       
  6012 	return {
       
  6013 		statics: true,
       
  6014 
       
  6015 		getLength: function(v, a, b) {
       
  6016 			if (a === undefined)
       
  6017 				a = 0;
       
  6018 			if (b === undefined)
       
  6019 				b = 1;
       
  6020 			var isZero = Numerical.isZero;
       
  6021 			if (a === 0 && b === 1
       
  6022 					&& isZero(v[0] - v[2]) && isZero(v[1] - v[3])
       
  6023 					&& isZero(v[6] - v[4]) && isZero(v[7] - v[5])) {
       
  6024 				var dx = v[6] - v[0],
       
  6025 					dy = v[7] - v[1];
       
  6026 				return Math.sqrt(dx * dx + dy * dy);
       
  6027 			}
       
  6028 			var ds = getLengthIntegrand(v);
       
  6029 			return Numerical.integrate(ds, a, b, getIterations(a, b));
       
  6030 		},
       
  6031 
       
  6032 		getParameterAt: function(v, offset, start) {
       
  6033 			if (start === undefined)
       
  6034 				start = offset < 0 ? 1 : 0
       
  6035 			if (offset === 0)
       
  6036 				return start;
       
  6037 			var forward = offset > 0,
       
  6038 				a = forward ? start : 0,
       
  6039 				b = forward ? 1 : start,
       
  6040 				ds = getLengthIntegrand(v),
       
  6041 				rangeLength = Numerical.integrate(ds, a, b,
       
  6042 						getIterations(a, b));
       
  6043 			if (Math.abs(offset) >= rangeLength)
       
  6044 				return forward ? b : a;
       
  6045 			var guess = offset / rangeLength,
       
  6046 				length = 0;
       
  6047 			function f(t) {
       
  6048 				length += Numerical.integrate(ds, start, t,
       
  6049 						getIterations(start, t));
       
  6050 				start = t;
       
  6051 				return length - offset;
       
  6052 			}
       
  6053 			return Numerical.findRoot(f, ds, start + guess, a, b, 16,
       
  6054 					0.000001);
       
  6055 		}
       
  6056 	};
       
  6057 }, new function() {
       
  6058 	function addLocation(locations, include, curve1, t1, point1, curve2, t2,
       
  6059 			point2) {
       
  6060 		var loc = new CurveLocation(curve1, t1, point1, curve2, t2, point2);
       
  6061 		if (!include || include(loc))
       
  6062 			locations.push(loc);
       
  6063 	}
       
  6064 
       
  6065 	function addCurveIntersections(v1, v2, curve1, curve2, locations, include,
       
  6066 			tMin, tMax, uMin, uMax, oldTDiff, reverse, recursion) {
       
  6067 		if (recursion > 32)
       
  6068 			return;
       
  6069 		var q0x = v2[0], q0y = v2[1], q3x = v2[6], q3y = v2[7],
       
  6070 			tolerance = 0.000001,
       
  6071 			getSignedDistance = Line.getSignedDistance,
       
  6072 			d1 = getSignedDistance(q0x, q0y, q3x, q3y, v2[2], v2[3]) || 0,
       
  6073 			d2 = getSignedDistance(q0x, q0y, q3x, q3y, v2[4], v2[5]) || 0,
       
  6074 			factor = d1 * d2 > 0 ? 3 / 4 : 4 / 9,
       
  6075 			dMin = factor * Math.min(0, d1, d2),
       
  6076 			dMax = factor * Math.max(0, d1, d2),
       
  6077 			dp0 = getSignedDistance(q0x, q0y, q3x, q3y, v1[0], v1[1]),
       
  6078 			dp1 = getSignedDistance(q0x, q0y, q3x, q3y, v1[2], v1[3]),
       
  6079 			dp2 = getSignedDistance(q0x, q0y, q3x, q3y, v1[4], v1[5]),
       
  6080 			dp3 = getSignedDistance(q0x, q0y, q3x, q3y, v1[6], v1[7]),
       
  6081 			tMinNew, tMaxNew, tDiff;
       
  6082 		if (q0x === q3x && uMax - uMin <= tolerance && recursion > 3) {
       
  6083 			tMaxNew = tMinNew = (tMax + tMin) / 2;
       
  6084 			tDiff = 0;
       
  6085 		} else {
       
  6086 			var hull = getConvexHull(dp0, dp1, dp2, dp3),
       
  6087 				top = hull[0],
       
  6088 				bottom = hull[1],
       
  6089 				tMinClip, tMaxClip;
       
  6090 			tMinClip = clipConvexHull(top, bottom, dMin, dMax);
       
  6091 			top.reverse();
       
  6092 			bottom.reverse();
       
  6093 			tMaxClip = clipConvexHull(top, bottom, dMin, dMax);
       
  6094 			if (tMinClip == null || tMaxClip == null)
       
  6095 				return;
       
  6096 			v1 = Curve.getPart(v1, tMinClip, tMaxClip);
       
  6097 			tDiff = tMaxClip - tMinClip;
       
  6098 			tMinNew = tMax * tMinClip + tMin * (1 - tMinClip);
       
  6099 			tMaxNew = tMax * tMaxClip + tMin * (1 - tMaxClip);
       
  6100 		}
       
  6101 		if (oldTDiff > 0.5 && tDiff > 0.5) {
       
  6102 			if (tMaxNew - tMinNew > uMax - uMin) {
       
  6103 				var parts = Curve.subdivide(v1, 0.5),
       
  6104 					t = tMinNew + (tMaxNew - tMinNew) / 2;
       
  6105 				addCurveIntersections(
       
  6106 					v2, parts[0], curve2, curve1, locations, include,
       
  6107 					uMin, uMax, tMinNew, t, tDiff, !reverse, ++recursion);
       
  6108 				addCurveIntersections(
       
  6109 					v2, parts[1], curve2, curve1, locations, include,
       
  6110 					uMin, uMax, t, tMaxNew, tDiff, !reverse, recursion);
       
  6111 			} else {
       
  6112 				var parts = Curve.subdivide(v2, 0.5),
       
  6113 					t = uMin + (uMax - uMin) / 2;
       
  6114 				addCurveIntersections(
       
  6115 					parts[0], v1, curve2, curve1, locations, include,
       
  6116 					uMin, t, tMinNew, tMaxNew, tDiff, !reverse, ++recursion);
       
  6117 				addCurveIntersections(
       
  6118 					parts[1], v1, curve2, curve1, locations, include,
       
  6119 					t, uMax, tMinNew, tMaxNew, tDiff, !reverse, recursion);
       
  6120 			}
       
  6121 		} else if (Math.max(uMax - uMin, tMaxNew - tMinNew) < tolerance) {
       
  6122 			var t1 = tMinNew + (tMaxNew - tMinNew) / 2,
       
  6123 				t2 = uMin + (uMax - uMin) / 2;
       
  6124 			if (reverse) {
       
  6125 				addLocation(locations, include,
       
  6126 						curve2, t2, Curve.evaluate(v2, t2, 0),
       
  6127 						curve1, t1, Curve.evaluate(v1, t1, 0));
       
  6128 			} else {
       
  6129 				addLocation(locations, include,
       
  6130 						curve1, t1, Curve.evaluate(v1, t1, 0),
       
  6131 						curve2, t2, Curve.evaluate(v2, t2, 0));
       
  6132 			}
       
  6133 		} else if (tDiff > 0) {
       
  6134 			addCurveIntersections(v2, v1, curve2, curve1, locations, include,
       
  6135 					uMin, uMax, tMinNew, tMaxNew, tDiff, !reverse, ++recursion);
       
  6136 		}
       
  6137 	}
       
  6138 
       
  6139 	function getConvexHull(dq0, dq1, dq2, dq3) {
       
  6140 		var p0 = [ 0, dq0 ],
       
  6141 			p1 = [ 1 / 3, dq1 ],
       
  6142 			p2 = [ 2 / 3, dq2 ],
       
  6143 			p3 = [ 1, dq3 ],
       
  6144 			getSignedDistance = Line.getSignedDistance,
       
  6145 			dist1 = getSignedDistance(0, dq0, 1, dq3, 1 / 3, dq1),
       
  6146 			dist2 = getSignedDistance(0, dq0, 1, dq3, 2 / 3, dq2),
       
  6147 			flip = false,
       
  6148 			hull;
       
  6149 		if (dist1 * dist2 < 0) {
       
  6150 			hull = [[p0, p1, p3], [p0, p2, p3]];
       
  6151 			flip = dist1 < 0;
       
  6152 		} else {
       
  6153 			var pmax, cross = 0,
       
  6154 				distZero = dist1 === 0 || dist2 === 0;
       
  6155 			if (Math.abs(dist1) > Math.abs(dist2)) {
       
  6156 				pmax = p1;
       
  6157 				cross = (dq3 - dq2 - (dq3 - dq0) / 3)
       
  6158 						* (2 * (dq3 - dq2) - dq3 + dq1) / 3;
       
  6159 			} else {
       
  6160 				pmax = p2;
       
  6161 				cross = (dq1 - dq0 + (dq0 - dq3) / 3)
       
  6162 						* (-2 * (dq0 - dq1) + dq0 - dq2) / 3;
       
  6163 			}
       
  6164 			hull = cross < 0 || distZero
       
  6165 					? [[p0, pmax, p3], [p0, p3]]
       
  6166 					: [[p0, p1, p2, p3], [p0, p3]];
       
  6167 			flip = dist1 ? dist1 < 0 : dist2 < 0;
       
  6168 		}
       
  6169 		return flip ? hull.reverse() : hull;
       
  6170 	}
       
  6171 
       
  6172 	function clipConvexHull(hullTop, hullBottom, dMin, dMax) {
       
  6173 		if (hullTop[0][1] < dMin) {
       
  6174 			return clipConvexHullPart(hullTop, true, dMin);
       
  6175 		} else if (hullBottom[0][1] > dMax) {
       
  6176 			return clipConvexHullPart(hullBottom, false, dMax);
       
  6177 		} else {
       
  6178 			return hullTop[0][0];
       
  6179 		}
       
  6180 	}
       
  6181 
       
  6182 	function clipConvexHullPart(part, top, threshold) {
       
  6183 		var px = part[0][0],
       
  6184 			py = part[0][1];
       
  6185 		for (var i = 1, l = part.length; i < l; i++) {
       
  6186 			var qx = part[i][0],
       
  6187 				qy = part[i][1];
       
  6188 			if (top ? qy >= threshold : qy <= threshold)
       
  6189 				return px + (threshold - py) * (qx - px) / (qy - py);
       
  6190 			px = qx;
       
  6191 			py = qy;
       
  6192 		}
       
  6193 		return null;
       
  6194 	}
       
  6195 
       
  6196 	function addCurveLineIntersections(v1, v2, curve1, curve2, locations,
       
  6197 			include) {
       
  6198 		var flip = Curve.isLinear(v1),
       
  6199 			vc = flip ? v2 : v1,
       
  6200 			vl = flip ? v1 : v2,
       
  6201 			lx1 = vl[0], ly1 = vl[1],
       
  6202 			lx2 = vl[6], ly2 = vl[7],
       
  6203 			ldx = lx2 - lx1,
       
  6204 			ldy = ly2 - ly1,
       
  6205 			angle = Math.atan2(-ldy, ldx),
       
  6206 			sin = Math.sin(angle),
       
  6207 			cos = Math.cos(angle),
       
  6208 			rlx2 = ldx * cos - ldy * sin,
       
  6209 			rvl = [0, 0, 0, 0, rlx2, 0, rlx2, 0],
       
  6210 			rvc = [];
       
  6211 		for(var i = 0; i < 8; i += 2) {
       
  6212 			var x = vc[i] - lx1,
       
  6213 				y = vc[i + 1] - ly1;
       
  6214 			rvc.push(
       
  6215 				x * cos - y * sin,
       
  6216 				y * cos + x * sin);
       
  6217 		}
       
  6218 		var roots = [],
       
  6219 			count = Curve.solveCubic(rvc, 1, 0, roots, 0, 1);
       
  6220 		for (var i = 0; i < count; i++) {
       
  6221 			var tc = roots[i],
       
  6222 				x = Curve.evaluate(rvc, tc, 0).x;
       
  6223 			if (x >= 0 && x <= rlx2) {
       
  6224 				var tl = Curve.getParameterOf(rvl, x, 0),
       
  6225 					t1 = flip ? tl : tc,
       
  6226 					t2 = flip ? tc : tl;
       
  6227 				addLocation(locations, include,
       
  6228 						curve1, t1, Curve.evaluate(v1, t1, 0),
       
  6229 						curve2, t2, Curve.evaluate(v2, t2, 0));
       
  6230 			}
       
  6231 		}
       
  6232 	}
       
  6233 
       
  6234 	function addLineIntersection(v1, v2, curve1, curve2, locations, include) {
       
  6235 		var point = Line.intersect(
       
  6236 				v1[0], v1[1], v1[6], v1[7],
       
  6237 				v2[0], v2[1], v2[6], v2[7]);
       
  6238 		if (point) {
       
  6239 			var x = point.x,
       
  6240 				y = point.y;
       
  6241 			addLocation(locations, include,
       
  6242 					curve1, Curve.getParameterOf(v1, x, y), point,
       
  6243 					curve2, Curve.getParameterOf(v2, x, y), point);
       
  6244 		}
       
  6245 	}
       
  6246 
       
  6247 	return { statics: {
       
  6248 		getIntersections: function(v1, v2, c1, c2, locations, include) {
       
  6249 			var linear1 = Curve.isLinear(v1),
       
  6250 				linear2 = Curve.isLinear(v2),
       
  6251 				c1p1 = c1.getPoint1(),
       
  6252 				c1p2 = c1.getPoint2(),
       
  6253 				c2p1 = c2.getPoint1(),
       
  6254 				c2p2 = c2.getPoint2(),
       
  6255 				tolerance = 0.000001;
       
  6256 			if (c1p1.isClose(c2p1, tolerance))
       
  6257 				addLocation(locations, include, c1, 0, c1p1, c2, 0, c1p1);
       
  6258 			if (c1p1.isClose(c2p2, tolerance))
       
  6259 				addLocation(locations, include, c1, 0, c1p1, c2, 1, c1p1);
       
  6260 			(linear1 && linear2
       
  6261 				? addLineIntersection
       
  6262 				: linear1 || linear2
       
  6263 					? addCurveLineIntersections
       
  6264 					: addCurveIntersections)(
       
  6265 						v1, v2, c1, c2, locations, include,
       
  6266 						0, 1, 0, 1, 0, false, 0);
       
  6267 			if (c1p2.isClose(c2p1, tolerance))
       
  6268 				addLocation(locations, include, c1, 1, c1p2, c2, 0, c1p2);
       
  6269 			if (c1p2.isClose(c2p2, tolerance))
       
  6270 				addLocation(locations, include, c1, 1, c1p2, c2, 1, c1p2);
       
  6271 			return locations;
       
  6272 		},
       
  6273 
       
  6274 		filterIntersections: function(locations, _expand) {
       
  6275 			var last = locations.length - 1,
       
  6276 				tMax = 1 - 0.000001;
       
  6277 			for (var i = last; i >= 0; i--) {
       
  6278 				var loc = locations[i],
       
  6279 					next = loc._curve.getNext(),
       
  6280 					next2 = loc._curve2.getNext();
       
  6281 				if (next && loc._parameter >= tMax) {
       
  6282 					loc._parameter = 0;
       
  6283 					loc._curve = next;
       
  6284 				}
       
  6285 				if (next2 && loc._parameter2 >= tMax) {
       
  6286 					loc._parameter2 = 0;
       
  6287 					loc._curve2 = next2;
       
  6288 				}
       
  6289 			}
       
  6290 
       
  6291 			function compare(loc1, loc2) {
       
  6292 				var path1 = loc1.getPath(),
       
  6293 					path2 = loc2.getPath();
       
  6294 				return path1 === path2
       
  6295 						? (loc1.getIndex() + loc1.getParameter())
       
  6296 								- (loc2.getIndex() + loc2.getParameter())
       
  6297 						: path1._id - path2._id;
       
  6298 			}
       
  6299 
       
  6300 			if (last > 0) {
       
  6301 				locations.sort(compare);
       
  6302 				for (var i = last; i > 0; i--) {
       
  6303 					if (locations[i].equals(locations[i - 1])) {
       
  6304 						locations.splice(i, 1);
       
  6305 						last--;
       
  6306 					}
       
  6307 				}
       
  6308 			}
       
  6309 			if (_expand) {
       
  6310 				for (var i = last; i >= 0; i--)
       
  6311 					locations.push(locations[i].getIntersection());
       
  6312 				locations.sort(compare);
       
  6313 			}
       
  6314 			return locations;
       
  6315 		}
       
  6316 	}};
       
  6317 });
       
  6318 
       
  6319 var CurveLocation = Base.extend({
       
  6320 	_class: 'CurveLocation',
       
  6321 	beans: true,
       
  6322 
       
  6323 	initialize: function CurveLocation(curve, parameter, point, _curve2,
       
  6324 			_parameter2, _point2, _distance) {
       
  6325 		this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
       
  6326 		this._curve = curve;
       
  6327 		this._segment1 = curve._segment1;
       
  6328 		this._segment2 = curve._segment2;
       
  6329 		this._parameter = parameter;
       
  6330 		this._point = point;
       
  6331 		this._curve2 = _curve2;
       
  6332 		this._parameter2 = _parameter2;
       
  6333 		this._point2 = _point2;
       
  6334 		this._distance = _distance;
       
  6335 	},
       
  6336 
       
  6337 	getSegment: function(_preferFirst) {
       
  6338 		if (!this._segment) {
       
  6339 			var curve = this.getCurve(),
       
  6340 				parameter = this.getParameter();
       
  6341 			if (parameter === 1) {
       
  6342 				this._segment = curve._segment2;
       
  6343 			} else if (parameter === 0 || _preferFirst) {
       
  6344 				this._segment = curve._segment1;
       
  6345 			} else if (parameter == null) {
       
  6346 				return null;
       
  6347 			} else {
       
  6348 				this._segment = curve.getPartLength(0, parameter)
       
  6349 					< curve.getPartLength(parameter, 1)
       
  6350 						? curve._segment1
       
  6351 						: curve._segment2;
       
  6352 			}
       
  6353 		}
       
  6354 		return this._segment;
       
  6355 	},
       
  6356 
       
  6357 	getCurve: function(_uncached) {
       
  6358 		if (!this._curve || _uncached) {
       
  6359 			this._curve = this._segment1.getCurve();
       
  6360 			if (this._curve.getParameterOf(this._point) == null)
       
  6361 				this._curve = this._segment2.getPrevious().getCurve();
       
  6362 		}
       
  6363 		return this._curve;
       
  6364 	},
       
  6365 
       
  6366 	getIntersection: function() {
       
  6367 		var intersection = this._intersection;
       
  6368 		if (!intersection && this._curve2) {
       
  6369 			var param = this._parameter2;
       
  6370 			this._intersection = intersection = new CurveLocation(
       
  6371 					this._curve2, param, this._point2 || this._point, this);
       
  6372 			intersection._intersection = this;
       
  6373 		}
       
  6374 		return intersection;
       
  6375 	},
       
  6376 
       
  6377 	getPath: function() {
       
  6378 		var curve = this.getCurve();
       
  6379 		return curve && curve._path;
       
  6380 	},
       
  6381 
       
  6382 	getIndex: function() {
       
  6383 		var curve = this.getCurve();
       
  6384 		return curve && curve.getIndex();
       
  6385 	},
       
  6386 
       
  6387 	getOffset: function() {
       
  6388 		var path = this.getPath();
       
  6389 		return path ? path._getOffset(this) : this.getCurveOffset();
       
  6390 	},
       
  6391 
       
  6392 	getCurveOffset: function() {
       
  6393 		var curve = this.getCurve(),
       
  6394 			parameter = this.getParameter();
       
  6395 		return parameter != null && curve && curve.getPartLength(0, parameter);
       
  6396 	},
       
  6397 
       
  6398 	getParameter: function(_uncached) {
       
  6399 		if ((this._parameter == null || _uncached) && this._point) {
       
  6400 			var curve = this.getCurve(_uncached);
       
  6401 			this._parameter = curve && curve.getParameterOf(this._point);
       
  6402 		}
       
  6403 		return this._parameter;
       
  6404 	},
       
  6405 
       
  6406 	getPoint: function(_uncached) {
       
  6407 		if ((!this._point || _uncached) && this._parameter != null) {
       
  6408 			var curve = this.getCurve(_uncached);
       
  6409 			this._point = curve && curve.getPointAt(this._parameter, true);
       
  6410 		}
       
  6411 		return this._point;
       
  6412 	},
       
  6413 
       
  6414 	getDistance: function() {
       
  6415 		return this._distance;
       
  6416 	},
       
  6417 
       
  6418 	divide: function() {
       
  6419 		var curve = this.getCurve(true);
       
  6420 		return curve && curve.divide(this.getParameter(true), true);
       
  6421 	},
       
  6422 
       
  6423 	split: function() {
       
  6424 		var curve = this.getCurve(true);
       
  6425 		return curve && curve.split(this.getParameter(true), true);
       
  6426 	},
       
  6427 
       
  6428 	equals: function(loc) {
       
  6429 		var abs = Math.abs,
       
  6430 			tolerance = 0.000001;
       
  6431 		return this === loc
       
  6432 				|| loc
       
  6433 					&& this._curve === loc._curve
       
  6434 					&& this._curve2 === loc._curve2
       
  6435 					&& abs(this._parameter - loc._parameter) <= tolerance
       
  6436 					&& abs(this._parameter2 - loc._parameter2) <= tolerance
       
  6437 				|| false;
       
  6438 	},
       
  6439 
       
  6440 	toString: function() {
       
  6441 		var parts = [],
       
  6442 			point = this.getPoint(),
       
  6443 			f = Formatter.instance;
       
  6444 		if (point)
       
  6445 			parts.push('point: ' + point);
       
  6446 		var index = this.getIndex();
       
  6447 		if (index != null)
       
  6448 			parts.push('index: ' + index);
       
  6449 		var parameter = this.getParameter();
       
  6450 		if (parameter != null)
       
  6451 			parts.push('parameter: ' + f.number(parameter));
       
  6452 		if (this._distance != null)
       
  6453 			parts.push('distance: ' + f.number(this._distance));
       
  6454 		return '{ ' + parts.join(', ') + ' }';
       
  6455 	}
       
  6456 }, Base.each(['getTangent', 'getNormal', 'getCurvature'], function(name) {
       
  6457 	var get = name + 'At';
       
  6458 	this[name] = function() {
       
  6459 		var parameter = this.getParameter(),
       
  6460 			curve = this.getCurve();
       
  6461 		return parameter != null && curve && curve[get](parameter, true);
       
  6462 	};
       
  6463 }, {}));
       
  6464 
       
  6465 var PathItem = Item.extend({
       
  6466 	_class: 'PathItem',
       
  6467 
       
  6468 	initialize: function PathItem() {
       
  6469 	},
       
  6470 
       
  6471 	getIntersections: function(path, _matrix, _expand) {
       
  6472 		if (this === path)
       
  6473 			path = null;
       
  6474 		var locations = [],
       
  6475 			curves1 = this.getCurves(),
       
  6476 			curves2 = path ? path.getCurves() : curves1,
       
  6477 			matrix1 = this._matrix.orNullIfIdentity(),
       
  6478 			matrix2 = path ? (_matrix || path._matrix).orNullIfIdentity()
       
  6479 				: matrix1,
       
  6480 			length1 = curves1.length,
       
  6481 			length2 = path ? curves2.length : length1,
       
  6482 			values2 = [],
       
  6483 			tMin = 0.000001,
       
  6484 			tMax = 1 - tMin;
       
  6485 		if (path && !this.getBounds(matrix1).touches(path.getBounds(matrix2)))
       
  6486 			return [];
       
  6487 		for (var i = 0; i < length2; i++)
       
  6488 			values2[i] = curves2[i].getValues(matrix2);
       
  6489 		for (var i = 0; i < length1; i++) {
       
  6490 			var curve1 = curves1[i],
       
  6491 				values1 = path ? curve1.getValues(matrix1) : values2[i];
       
  6492 			if (!path) {
       
  6493 				var seg1 = curve1.getSegment1(),
       
  6494 					seg2 = curve1.getSegment2(),
       
  6495 					h1 = seg1._handleOut,
       
  6496 					h2 = seg2._handleIn;
       
  6497 				if (new Line(seg1._point.subtract(h1), h1.multiply(2), true)
       
  6498 						.intersect(new Line(seg2._point.subtract(h2),
       
  6499 						h2.multiply(2), true), false)) {
       
  6500 					var parts = Curve.subdivide(values1);
       
  6501 					Curve.getIntersections(
       
  6502 						parts[0], parts[1], curve1, curve1, locations,
       
  6503 						function(loc) {
       
  6504 							if (loc._parameter <= tMax) {
       
  6505 								loc._parameter /= 2;
       
  6506 								loc._parameter2 = 0.5 + loc._parameter2 / 2;
       
  6507 								return true;
       
  6508 							}
       
  6509 						}
       
  6510 					);
       
  6511 				}
       
  6512 			}
       
  6513 			for (var j = path ? 0 : i + 1; j < length2; j++) {
       
  6514 				Curve.getIntersections(
       
  6515 					values1, values2[j], curve1, curves2[j], locations,
       
  6516 					!path && (j === i + 1 || j === length2 - 1 && i === 0)
       
  6517 						&& function(loc) {
       
  6518 							var t = loc._parameter;
       
  6519 							return t >= tMin && t <= tMax;
       
  6520 						}
       
  6521 				);
       
  6522 			}
       
  6523 		}
       
  6524 		return Curve.filterIntersections(locations, _expand);
       
  6525 	},
       
  6526 
       
  6527 	_asPathItem: function() {
       
  6528 		return this;
       
  6529 	},
       
  6530 
       
  6531 	setPathData: function(data) {
       
  6532 
       
  6533 		var parts = data.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig),
       
  6534 			coords,
       
  6535 			relative = false,
       
  6536 			previous,
       
  6537 			control,
       
  6538 			current = new Point(),
       
  6539 			start = new Point();
       
  6540 
       
  6541 		function getCoord(index, coord) {
       
  6542 			var val = +coords[index];
       
  6543 			if (relative)
       
  6544 				val += current[coord];
       
  6545 			return val;
       
  6546 		}
       
  6547 
       
  6548 		function getPoint(index) {
       
  6549 			return new Point(
       
  6550 				getCoord(index, 'x'),
       
  6551 				getCoord(index + 1, 'y')
       
  6552 			);
       
  6553 		}
       
  6554 
       
  6555 		this.clear();
       
  6556 
       
  6557 		for (var i = 0, l = parts && parts.length; i < l; i++) {
       
  6558 			var part = parts[i],
       
  6559 				command = part[0],
       
  6560 				lower = command.toLowerCase();
       
  6561 			coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g);
       
  6562 			var length = coords && coords.length;
       
  6563 			relative = command === lower;
       
  6564 			if (previous === 'z' && !/[mz]/.test(lower))
       
  6565 				this.moveTo(current = start);
       
  6566 			switch (lower) {
       
  6567 			case 'm':
       
  6568 			case 'l':
       
  6569 				var move = lower === 'm';
       
  6570 				if (move && previous && previous !== 'z')
       
  6571 					this.closePath(true);
       
  6572 				for (var j = 0; j < length; j += 2)
       
  6573 					this[j === 0 && move ? 'moveTo' : 'lineTo'](
       
  6574 							current = getPoint(j));
       
  6575 				control = current;
       
  6576 				if (move)
       
  6577 					start = current;
       
  6578 				break;
       
  6579 			case 'h':
       
  6580 			case 'v':
       
  6581 				var coord = lower === 'h' ? 'x' : 'y';
       
  6582 				for (var j = 0; j < length; j++) {
       
  6583 					current[coord] = getCoord(j, coord);
       
  6584 					this.lineTo(current);
       
  6585 				}
       
  6586 				control = current;
       
  6587 				break;
       
  6588 			case 'c':
       
  6589 				for (var j = 0; j < length; j += 6) {
       
  6590 					this.cubicCurveTo(
       
  6591 							getPoint(j),
       
  6592 							control = getPoint(j + 2),
       
  6593 							current = getPoint(j + 4));
       
  6594 				}
       
  6595 				break;
       
  6596 			case 's':
       
  6597 				for (var j = 0; j < length; j += 4) {
       
  6598 					this.cubicCurveTo(
       
  6599 							/[cs]/.test(previous)
       
  6600 									? current.multiply(2).subtract(control)
       
  6601 									: current,
       
  6602 							control = getPoint(j),
       
  6603 							current = getPoint(j + 2));
       
  6604 					previous = lower;
       
  6605 				}
       
  6606 				break;
       
  6607 			case 'q':
       
  6608 				for (var j = 0; j < length; j += 4) {
       
  6609 					this.quadraticCurveTo(
       
  6610 							control = getPoint(j),
       
  6611 							current = getPoint(j + 2));
       
  6612 				}
       
  6613 				break;
       
  6614 			case 't':
       
  6615 				for (var j = 0; j < length; j += 2) {
       
  6616 					this.quadraticCurveTo(
       
  6617 							control = (/[qt]/.test(previous)
       
  6618 									? current.multiply(2).subtract(control)
       
  6619 									: current),
       
  6620 							current = getPoint(j));
       
  6621 					previous = lower;
       
  6622 				}
       
  6623 				break;
       
  6624 			case 'a':
       
  6625 				for (var j = 0; j < length; j += 7) {
       
  6626 					this.arcTo(current = getPoint(j + 5),
       
  6627 							new Size(+coords[j], +coords[j + 1]),
       
  6628 							+coords[j + 2], +coords[j + 4], +coords[j + 3]);
       
  6629 				}
       
  6630 				break;
       
  6631 			case 'z':
       
  6632 				this.closePath(true);
       
  6633 				break;
       
  6634 			}
       
  6635 			previous = lower;
       
  6636 		}
       
  6637 	},
       
  6638 
       
  6639 	_canComposite: function() {
       
  6640 		return !(this.hasFill() && this.hasStroke());
       
  6641 	},
       
  6642 
       
  6643 	_contains: function(point) {
       
  6644 		var winding = this._getWinding(point, false, true);
       
  6645 		return !!(this.getWindingRule() === 'evenodd' ? winding & 1 : winding);
       
  6646 	}
       
  6647 
       
  6648 });
       
  6649 
       
  6650 var Path = PathItem.extend({
       
  6651 	_class: 'Path',
       
  6652 	_serializeFields: {
       
  6653 		segments: [],
       
  6654 		closed: false
       
  6655 	},
       
  6656 
       
  6657 	initialize: function Path(arg) {
       
  6658 		this._closed = false;
       
  6659 		this._segments = [];
       
  6660 		var segments = Array.isArray(arg)
       
  6661 			? typeof arg[0] === 'object'
       
  6662 				? arg
       
  6663 				: arguments
       
  6664 			: arg && (arg.size === undefined && (arg.x !== undefined
       
  6665 					|| arg.point !== undefined))
       
  6666 				? arguments
       
  6667 				: null;
       
  6668 		if (segments && segments.length > 0) {
       
  6669 			this.setSegments(segments);
       
  6670 		} else {
       
  6671 			this._curves = undefined;
       
  6672 			this._selectedSegmentState = 0;
       
  6673 			if (!segments && typeof arg === 'string') {
       
  6674 				this.setPathData(arg);
       
  6675 				arg = null;
       
  6676 			}
       
  6677 		}
       
  6678 		this._initialize(!segments && arg);
       
  6679 	},
       
  6680 
       
  6681 	_equals: function(item) {
       
  6682 		return this._closed === item._closed
       
  6683 				&& Base.equals(this._segments, item._segments);
       
  6684 	},
       
  6685 
       
  6686 	clone: function(insert) {
       
  6687 		var copy = new Path(Item.NO_INSERT);
       
  6688 		copy.setSegments(this._segments);
       
  6689 		copy._closed = this._closed;
       
  6690 		if (this._clockwise !== undefined)
       
  6691 			copy._clockwise = this._clockwise;
       
  6692 		return this._clone(copy, insert);
       
  6693 	},
       
  6694 
       
  6695 	_changed: function _changed(flags) {
       
  6696 		_changed.base.call(this, flags);
       
  6697 		if (flags & 8) {
       
  6698 			var parent = this._parent;
       
  6699 			if (parent)
       
  6700 				parent._currentPath = undefined;
       
  6701 			this._length = this._clockwise = undefined;
       
  6702 			if (this._curves && !(flags & 16)) {
       
  6703 				for (var i = 0, l = this._curves.length; i < l; i++)
       
  6704 					this._curves[i]._changed();
       
  6705 			}
       
  6706 			this._monoCurves = undefined;
       
  6707 		} else if (flags & 32) {
       
  6708 			this._bounds = undefined;
       
  6709 		}
       
  6710 	},
       
  6711 
       
  6712 	getStyle: function() {
       
  6713 		var parent = this._parent;
       
  6714 		return (parent instanceof CompoundPath ? parent : this)._style;
       
  6715 	},
       
  6716 
       
  6717 	getSegments: function() {
       
  6718 		return this._segments;
       
  6719 	},
       
  6720 
       
  6721 	setSegments: function(segments) {
       
  6722 		var fullySelected = this.isFullySelected();
       
  6723 		this._segments.length = 0;
       
  6724 		this._selectedSegmentState = 0;
       
  6725 		this._curves = undefined;
       
  6726 		if (segments && segments.length > 0)
       
  6727 			this._add(Segment.readAll(segments));
       
  6728 		if (fullySelected)
       
  6729 			this.setFullySelected(true);
       
  6730 	},
       
  6731 
       
  6732 	getFirstSegment: function() {
       
  6733 		return this._segments[0];
       
  6734 	},
       
  6735 
       
  6736 	getLastSegment: function() {
       
  6737 		return this._segments[this._segments.length - 1];
       
  6738 	},
       
  6739 
       
  6740 	getCurves: function() {
       
  6741 		var curves = this._curves,
       
  6742 			segments = this._segments;
       
  6743 		if (!curves) {
       
  6744 			var length = this._countCurves();
       
  6745 			curves = this._curves = new Array(length);
       
  6746 			for (var i = 0; i < length; i++)
       
  6747 				curves[i] = new Curve(this, segments[i],
       
  6748 					segments[i + 1] || segments[0]);
       
  6749 		}
       
  6750 		return curves;
       
  6751 	},
       
  6752 
       
  6753 	getFirstCurve: function() {
       
  6754 		return this.getCurves()[0];
       
  6755 	},
       
  6756 
       
  6757 	getLastCurve: function() {
       
  6758 		var curves = this.getCurves();
       
  6759 		return curves[curves.length - 1];
       
  6760 	},
       
  6761 
       
  6762 	isClosed: function() {
       
  6763 		return this._closed;
       
  6764 	},
       
  6765 
       
  6766 	setClosed: function(closed) {
       
  6767 		if (this._closed != (closed = !!closed)) {
       
  6768 			this._closed = closed;
       
  6769 			if (this._curves) {
       
  6770 				var length = this._curves.length = this._countCurves();
       
  6771 				if (closed)
       
  6772 					this._curves[length - 1] = new Curve(this,
       
  6773 						this._segments[length - 1], this._segments[0]);
       
  6774 			}
       
  6775 			this._changed(25);
       
  6776 		}
       
  6777 	}
       
  6778 }, {
       
  6779 	beans: true,
       
  6780 
       
  6781 	getPathData: function(_matrix, _precision) {
       
  6782 		var segments = this._segments,
       
  6783 			length = segments.length,
       
  6784 			f = new Formatter(_precision),
       
  6785 			coords = new Array(6),
       
  6786 			first = true,
       
  6787 			curX, curY,
       
  6788 			prevX, prevY,
       
  6789 			inX, inY,
       
  6790 			outX, outY,
       
  6791 			parts = [];
       
  6792 
       
  6793 		function addSegment(segment, skipLine) {
       
  6794 			segment._transformCoordinates(_matrix, coords, false);
       
  6795 			curX = coords[0];
       
  6796 			curY = coords[1];
       
  6797 			if (first) {
       
  6798 				parts.push('M' + f.pair(curX, curY));
       
  6799 				first = false;
       
  6800 			} else {
       
  6801 				inX = coords[2];
       
  6802 				inY = coords[3];
       
  6803 				if (inX === curX && inY === curY
       
  6804 						&& outX === prevX && outY === prevY) {
       
  6805 					if (!skipLine)
       
  6806 						parts.push('l' + f.pair(curX - prevX, curY - prevY));
       
  6807 				} else {
       
  6808 					parts.push('c' + f.pair(outX - prevX, outY - prevY)
       
  6809 							+ ' ' + f.pair(inX - prevX, inY - prevY)
       
  6810 							+ ' ' + f.pair(curX - prevX, curY - prevY));
       
  6811 				}
       
  6812 			}
       
  6813 			prevX = curX;
       
  6814 			prevY = curY;
       
  6815 			outX = coords[4];
       
  6816 			outY = coords[5];
       
  6817 		}
       
  6818 
       
  6819 		if (length === 0)
       
  6820 			return '';
       
  6821 
       
  6822 		for (var i = 0; i < length; i++)
       
  6823 			addSegment(segments[i]);
       
  6824 		if (this._closed && length > 0) {
       
  6825 			addSegment(segments[0], true);
       
  6826 			parts.push('z');
       
  6827 		}
       
  6828 		return parts.join('');
       
  6829 	}
       
  6830 }, {
       
  6831 
       
  6832 	isEmpty: function() {
       
  6833 		return this._segments.length === 0;
       
  6834 	},
       
  6835 
       
  6836 	isPolygon: function() {
       
  6837 		for (var i = 0, l = this._segments.length; i < l; i++) {
       
  6838 			if (!this._segments[i].isLinear())
       
  6839 				return false;
       
  6840 		}
       
  6841 		return true;
       
  6842 	},
       
  6843 
       
  6844 	_transformContent: function(matrix) {
       
  6845 		var coords = new Array(6);
       
  6846 		for (var i = 0, l = this._segments.length; i < l; i++)
       
  6847 			this._segments[i]._transformCoordinates(matrix, coords, true);
       
  6848 		return true;
       
  6849 	},
       
  6850 
       
  6851 	_add: function(segs, index) {
       
  6852 		var segments = this._segments,
       
  6853 			curves = this._curves,
       
  6854 			amount = segs.length,
       
  6855 			append = index == null,
       
  6856 			index = append ? segments.length : index;
       
  6857 		for (var i = 0; i < amount; i++) {
       
  6858 			var segment = segs[i];
       
  6859 			if (segment._path)
       
  6860 				segment = segs[i] = segment.clone();
       
  6861 			segment._path = this;
       
  6862 			segment._index = index + i;
       
  6863 			if (segment._selectionState)
       
  6864 				this._updateSelection(segment, 0, segment._selectionState);
       
  6865 		}
       
  6866 		if (append) {
       
  6867 			segments.push.apply(segments, segs);
       
  6868 		} else {
       
  6869 			segments.splice.apply(segments, [index, 0].concat(segs));
       
  6870 			for (var i = index + amount, l = segments.length; i < l; i++)
       
  6871 				segments[i]._index = i;
       
  6872 		}
       
  6873 		if (curves || segs._curves) {
       
  6874 			if (!curves)
       
  6875 				curves = this._curves = [];
       
  6876 			var from = index > 0 ? index - 1 : index,
       
  6877 				start = from,
       
  6878 				to = Math.min(from + amount, this._countCurves());
       
  6879 			if (segs._curves) {
       
  6880 				curves.splice.apply(curves, [from, 0].concat(segs._curves));
       
  6881 				start += segs._curves.length;
       
  6882 			}
       
  6883 			for (var i = start; i < to; i++)
       
  6884 				curves.splice(i, 0, new Curve(this, null, null));
       
  6885 			this._adjustCurves(from, to);
       
  6886 		}
       
  6887 		this._changed(25);
       
  6888 		return segs;
       
  6889 	},
       
  6890 
       
  6891 	_adjustCurves: function(from, to) {
       
  6892 		var segments = this._segments,
       
  6893 			curves = this._curves,
       
  6894 			curve;
       
  6895 		for (var i = from; i < to; i++) {
       
  6896 			curve = curves[i];
       
  6897 			curve._path = this;
       
  6898 			curve._segment1 = segments[i];
       
  6899 			curve._segment2 = segments[i + 1] || segments[0];
       
  6900 			curve._changed();
       
  6901 		}
       
  6902 		if (curve = curves[this._closed && from === 0 ? segments.length - 1
       
  6903 				: from - 1]) {
       
  6904 			curve._segment2 = segments[from] || segments[0];
       
  6905 			curve._changed();
       
  6906 		}
       
  6907 		if (curve = curves[to]) {
       
  6908 			curve._segment1 = segments[to];
       
  6909 			curve._changed();
       
  6910 		}
       
  6911 	},
       
  6912 
       
  6913 	_countCurves: function() {
       
  6914 		var length = this._segments.length;
       
  6915 		return !this._closed && length > 0 ? length - 1 : length;
       
  6916 	},
       
  6917 
       
  6918 	add: function(segment1 ) {
       
  6919 		return arguments.length > 1 && typeof segment1 !== 'number'
       
  6920 			? this._add(Segment.readAll(arguments))
       
  6921 			: this._add([ Segment.read(arguments) ])[0];
       
  6922 	},
       
  6923 
       
  6924 	insert: function(index, segment1 ) {
       
  6925 		return arguments.length > 2 && typeof segment1 !== 'number'
       
  6926 			? this._add(Segment.readAll(arguments, 1), index)
       
  6927 			: this._add([ Segment.read(arguments, 1) ], index)[0];
       
  6928 	},
       
  6929 
       
  6930 	addSegment: function() {
       
  6931 		return this._add([ Segment.read(arguments) ])[0];
       
  6932 	},
       
  6933 
       
  6934 	insertSegment: function(index ) {
       
  6935 		return this._add([ Segment.read(arguments, 1) ], index)[0];
       
  6936 	},
       
  6937 
       
  6938 	addSegments: function(segments) {
       
  6939 		return this._add(Segment.readAll(segments));
       
  6940 	},
       
  6941 
       
  6942 	insertSegments: function(index, segments) {
       
  6943 		return this._add(Segment.readAll(segments), index);
       
  6944 	},
       
  6945 
       
  6946 	removeSegment: function(index) {
       
  6947 		return this.removeSegments(index, index + 1)[0] || null;
       
  6948 	},
       
  6949 
       
  6950 	removeSegments: function(from, to, _includeCurves) {
       
  6951 		from = from || 0;
       
  6952 		to = Base.pick(to, this._segments.length);
       
  6953 		var segments = this._segments,
       
  6954 			curves = this._curves,
       
  6955 			count = segments.length,
       
  6956 			removed = segments.splice(from, to - from),
       
  6957 			amount = removed.length;
       
  6958 		if (!amount)
       
  6959 			return removed;
       
  6960 		for (var i = 0; i < amount; i++) {
       
  6961 			var segment = removed[i];
       
  6962 			if (segment._selectionState)
       
  6963 				this._updateSelection(segment, segment._selectionState, 0);
       
  6964 			segment._index = segment._path = null;
       
  6965 		}
       
  6966 		for (var i = from, l = segments.length; i < l; i++)
       
  6967 			segments[i]._index = i;
       
  6968 		if (curves) {
       
  6969 			var index = from > 0 && to === count + (this._closed ? 1 : 0)
       
  6970 					? from - 1
       
  6971 					: from,
       
  6972 				curves = curves.splice(index, amount);
       
  6973 			if (_includeCurves)
       
  6974 				removed._curves = curves.slice(1);
       
  6975 			this._adjustCurves(index, index);
       
  6976 		}
       
  6977 		this._changed(25);
       
  6978 		return removed;
       
  6979 	},
       
  6980 
       
  6981 	clear: '#removeSegments',
       
  6982 
       
  6983 	getLength: function() {
       
  6984 		if (this._length == null) {
       
  6985 			var curves = this.getCurves();
       
  6986 			this._length = 0;
       
  6987 			for (var i = 0, l = curves.length; i < l; i++)
       
  6988 				this._length += curves[i].getLength();
       
  6989 		}
       
  6990 		return this._length;
       
  6991 	},
       
  6992 
       
  6993 	getArea: function() {
       
  6994 		var curves = this.getCurves();
       
  6995 		var area = 0;
       
  6996 		for (var i = 0, l = curves.length; i < l; i++)
       
  6997 			area += curves[i].getArea();
       
  6998 		return area;
       
  6999 	},
       
  7000 
       
  7001 	isFullySelected: function() {
       
  7002 		var length = this._segments.length;
       
  7003 		return this._selected && length > 0 && this._selectedSegmentState
       
  7004 				=== length * 7;
       
  7005 	},
       
  7006 
       
  7007 	setFullySelected: function(selected) {
       
  7008 		if (selected)
       
  7009 			this._selectSegments(true);
       
  7010 		this.setSelected(selected);
       
  7011 	},
       
  7012 
       
  7013 	setSelected: function setSelected(selected) {
       
  7014 		if (!selected)
       
  7015 			this._selectSegments(false);
       
  7016 		setSelected.base.call(this, selected);
       
  7017 	},
       
  7018 
       
  7019 	_selectSegments: function(selected) {
       
  7020 		var length = this._segments.length;
       
  7021 		this._selectedSegmentState = selected
       
  7022 				? length * 7 : 0;
       
  7023 		for (var i = 0; i < length; i++)
       
  7024 			this._segments[i]._selectionState = selected
       
  7025 					? 7 : 0;
       
  7026 	},
       
  7027 
       
  7028 	_updateSelection: function(segment, oldState, newState) {
       
  7029 		segment._selectionState = newState;
       
  7030 		var total = this._selectedSegmentState += newState - oldState;
       
  7031 		if (total > 0)
       
  7032 			this.setSelected(true);
       
  7033 	},
       
  7034 
       
  7035 	flatten: function(maxDistance) {
       
  7036 		var iterator = new PathIterator(this, 64, 0.1),
       
  7037 			pos = 0,
       
  7038 			step = iterator.length / Math.ceil(iterator.length / maxDistance),
       
  7039 			end = iterator.length + (this._closed ? -step : step) / 2;
       
  7040 		var segments = [];
       
  7041 		while (pos <= end) {
       
  7042 			segments.push(new Segment(iterator.evaluate(pos, 0)));
       
  7043 			pos += step;
       
  7044 		}
       
  7045 		this.setSegments(segments);
       
  7046 	},
       
  7047 
       
  7048 	reduce: function() {
       
  7049 		var curves = this.getCurves();
       
  7050 		for (var i = curves.length - 1; i >= 0; i--) {
       
  7051 			var curve = curves[i];
       
  7052 			if (curve.isLinear() && curve.getLength() === 0)
       
  7053 				curve.remove();
       
  7054 		}
       
  7055 		return this;
       
  7056 	},
       
  7057 
       
  7058 	simplify: function(tolerance) {
       
  7059 		if (this._segments.length > 2) {
       
  7060 			var fitter = new PathFitter(this, tolerance || 2.5);
       
  7061 			this.setSegments(fitter.fit());
       
  7062 		}
       
  7063 	},
       
  7064 
       
  7065 	split: function(index, parameter) {
       
  7066 		if (parameter === null)
       
  7067 			return null;
       
  7068 		if (arguments.length === 1) {
       
  7069 			var arg = index;
       
  7070 			if (typeof arg === 'number')
       
  7071 				arg = this.getLocationAt(arg);
       
  7072 			if (!arg)
       
  7073 				return null
       
  7074 			index = arg.index;
       
  7075 			parameter = arg.parameter;
       
  7076 		}
       
  7077 		var tolerance = 0.000001;
       
  7078 		if (parameter >= 1 - tolerance) {
       
  7079 			index++;
       
  7080 			parameter--;
       
  7081 		}
       
  7082 		var curves = this.getCurves();
       
  7083 		if (index >= 0 && index < curves.length) {
       
  7084 			if (parameter > tolerance) {
       
  7085 				curves[index++].divide(parameter, true);
       
  7086 			}
       
  7087 			var segs = this.removeSegments(index, this._segments.length, true),
       
  7088 				path;
       
  7089 			if (this._closed) {
       
  7090 				this.setClosed(false);
       
  7091 				path = this;
       
  7092 			} else {
       
  7093 				path = this._clone(new Path().insertAbove(this, true));
       
  7094 			}
       
  7095 			path._add(segs, 0);
       
  7096 			this.addSegment(segs[0]);
       
  7097 			return path;
       
  7098 		}
       
  7099 		return null;
       
  7100 	},
       
  7101 
       
  7102 	isClockwise: function() {
       
  7103 		if (this._clockwise !== undefined)
       
  7104 			return this._clockwise;
       
  7105 		return Path.isClockwise(this._segments);
       
  7106 	},
       
  7107 
       
  7108 	setClockwise: function(clockwise) {
       
  7109 		if (this.isClockwise() != (clockwise = !!clockwise))
       
  7110 			this.reverse();
       
  7111 		this._clockwise = clockwise;
       
  7112 	},
       
  7113 
       
  7114 	reverse: function() {
       
  7115 		this._segments.reverse();
       
  7116 		for (var i = 0, l = this._segments.length; i < l; i++) {
       
  7117 			var segment = this._segments[i];
       
  7118 			var handleIn = segment._handleIn;
       
  7119 			segment._handleIn = segment._handleOut;
       
  7120 			segment._handleOut = handleIn;
       
  7121 			segment._index = i;
       
  7122 		}
       
  7123 		this._curves = null;
       
  7124 		if (this._clockwise !== undefined)
       
  7125 			this._clockwise = !this._clockwise;
       
  7126 		this._changed(9);
       
  7127 	},
       
  7128 
       
  7129 	join: function(path) {
       
  7130 		if (path) {
       
  7131 			var segments = path._segments,
       
  7132 				last1 = this.getLastSegment(),
       
  7133 				last2 = path.getLastSegment();
       
  7134 			if (!last2)
       
  7135 				return this;
       
  7136 			if (last1 && last1._point.equals(last2._point))
       
  7137 				path.reverse();
       
  7138 			var first2 = path.getFirstSegment();
       
  7139 			if (last1 && last1._point.equals(first2._point)) {
       
  7140 				last1.setHandleOut(first2._handleOut);
       
  7141 				this._add(segments.slice(1));
       
  7142 			} else {
       
  7143 				var first1 = this.getFirstSegment();
       
  7144 				if (first1 && first1._point.equals(first2._point))
       
  7145 					path.reverse();
       
  7146 				last2 = path.getLastSegment();
       
  7147 				if (first1 && first1._point.equals(last2._point)) {
       
  7148 					first1.setHandleIn(last2._handleIn);
       
  7149 					this._add(segments.slice(0, segments.length - 1), 0);
       
  7150 				} else {
       
  7151 					this._add(segments.slice());
       
  7152 				}
       
  7153 			}
       
  7154 			if (path.closed)
       
  7155 				this._add([segments[0]]);
       
  7156 			path.remove();
       
  7157 		}
       
  7158 		var first = this.getFirstSegment(),
       
  7159 			last = this.getLastSegment();
       
  7160 		if (first !== last && first._point.equals(last._point)) {
       
  7161 			first.setHandleIn(last._handleIn);
       
  7162 			last.remove();
       
  7163 			this.setClosed(true);
       
  7164 		}
       
  7165 		return this;
       
  7166 	},
       
  7167 
       
  7168 	toShape: function(insert) {
       
  7169 		if (!this._closed)
       
  7170 			return null;
       
  7171 
       
  7172 		var segments = this._segments,
       
  7173 			type,
       
  7174 			size,
       
  7175 			radius,
       
  7176 			topCenter;
       
  7177 
       
  7178 		function isColinear(i, j) {
       
  7179 			return segments[i].isColinear(segments[j]);
       
  7180 		}
       
  7181 
       
  7182 		function isOrthogonal(i) {
       
  7183 			return segments[i].isOrthogonal();
       
  7184 		}
       
  7185 
       
  7186 		function isArc(i) {
       
  7187 			return segments[i].isArc();
       
  7188 		}
       
  7189 
       
  7190 		function getDistance(i, j) {
       
  7191 			return segments[i]._point.getDistance(segments[j]._point);
       
  7192 		}
       
  7193 
       
  7194 		if (this.isPolygon() && segments.length === 4
       
  7195 				&& isColinear(0, 2) && isColinear(1, 3) && isOrthogonal(1)) {
       
  7196 			type = Shape.Rectangle;
       
  7197 			size = new Size(getDistance(0, 3), getDistance(0, 1));
       
  7198 			topCenter = segments[1]._point.add(segments[2]._point).divide(2);
       
  7199 		} else if (segments.length === 8 && isArc(0) && isArc(2) && isArc(4)
       
  7200 				&& isArc(6) && isColinear(1, 5) && isColinear(3, 7)) {
       
  7201 			type = Shape.Rectangle;
       
  7202 			size = new Size(getDistance(1, 6), getDistance(0, 3));
       
  7203 			radius = size.subtract(new Size(getDistance(0, 7),
       
  7204 					getDistance(1, 2))).divide(2);
       
  7205 			topCenter = segments[3]._point.add(segments[4]._point).divide(2);
       
  7206 		} else if (segments.length === 4
       
  7207 				&& isArc(0) && isArc(1) && isArc(2) && isArc(3)) {
       
  7208 			if (Numerical.isZero(getDistance(0, 2) - getDistance(1, 3))) {
       
  7209 				type = Shape.Circle;
       
  7210 				radius = getDistance(0, 2) / 2;
       
  7211 			} else {
       
  7212 				type = Shape.Ellipse;
       
  7213 				radius = new Size(getDistance(2, 0) / 2, getDistance(3, 1) / 2);
       
  7214 			}
       
  7215 			topCenter = segments[1]._point;
       
  7216 		}
       
  7217 
       
  7218 		if (type) {
       
  7219 			var center = this.getPosition(true),
       
  7220 				shape = new type({
       
  7221 					center: center,
       
  7222 					size: size,
       
  7223 					radius: radius,
       
  7224 					insert: false
       
  7225 				});
       
  7226 			shape.rotate(topCenter.subtract(center).getAngle() + 90);
       
  7227 			shape.setStyle(this._style);
       
  7228 			if (insert || insert === undefined)
       
  7229 				shape.insertAbove(this);
       
  7230 			return shape;
       
  7231 		}
       
  7232 		return null;
       
  7233 	},
       
  7234 
       
  7235 	_hitTestSelf: function(point, options) {
       
  7236 		var that = this,
       
  7237 			style = this.getStyle(),
       
  7238 			segments = this._segments,
       
  7239 			numSegments = segments.length,
       
  7240 			closed = this._closed,
       
  7241 			tolerancePadding = options._tolerancePadding,
       
  7242 			strokePadding = tolerancePadding,
       
  7243 			join, cap, miterLimit,
       
  7244 			area, loc, res,
       
  7245 			hitStroke = options.stroke && style.hasStroke(),
       
  7246 			hitFill = options.fill && style.hasFill(),
       
  7247 			hitCurves = options.curves,
       
  7248 			radius = hitStroke
       
  7249 					? style.getStrokeWidth() / 2
       
  7250 					: hitFill && options.tolerance > 0 || hitCurves
       
  7251 						? 0 : null;
       
  7252 		if (radius !== null) {
       
  7253 			if (radius > 0) {
       
  7254 				join = style.getStrokeJoin();
       
  7255 				cap = style.getStrokeCap();
       
  7256 				miterLimit = radius * style.getMiterLimit();
       
  7257 				strokePadding = tolerancePadding.add(new Point(radius, radius));
       
  7258 			} else {
       
  7259 				join = cap = 'round';
       
  7260 			}
       
  7261 		}
       
  7262 
       
  7263 		function isCloseEnough(pt, padding) {
       
  7264 			return point.subtract(pt).divide(padding).length <= 1;
       
  7265 		}
       
  7266 
       
  7267 		function checkSegmentPoint(seg, pt, name) {
       
  7268 			if (!options.selected || pt.isSelected()) {
       
  7269 				var anchor = seg._point;
       
  7270 				if (pt !== anchor)
       
  7271 					pt = pt.add(anchor);
       
  7272 				if (isCloseEnough(pt, strokePadding)) {
       
  7273 					return new HitResult(name, that, {
       
  7274 						segment: seg,
       
  7275 						point: pt
       
  7276 					});
       
  7277 				}
       
  7278 			}
       
  7279 		}
       
  7280 
       
  7281 		function checkSegmentPoints(seg, ends) {
       
  7282 			return (ends || options.segments)
       
  7283 				&& checkSegmentPoint(seg, seg._point, 'segment')
       
  7284 				|| (!ends && options.handles) && (
       
  7285 					checkSegmentPoint(seg, seg._handleIn, 'handle-in') ||
       
  7286 					checkSegmentPoint(seg, seg._handleOut, 'handle-out'));
       
  7287 		}
       
  7288 
       
  7289 		function addToArea(point) {
       
  7290 			area.add(point);
       
  7291 		}
       
  7292 
       
  7293 		function checkSegmentStroke(segment) {
       
  7294 			if (join !== 'round' || cap !== 'round') {
       
  7295 				area = new Path({ internal: true, closed: true });
       
  7296 				if (closed || segment._index > 0
       
  7297 						&& segment._index < numSegments - 1) {
       
  7298 					if (join !== 'round' && (segment._handleIn.isZero()
       
  7299 							|| segment._handleOut.isZero()))
       
  7300 						Path._addBevelJoin(segment, join, radius, miterLimit,
       
  7301 								addToArea, true);
       
  7302 				} else if (cap !== 'round') {
       
  7303 					Path._addSquareCap(segment, cap, radius, addToArea, true);
       
  7304 				}
       
  7305 				if (!area.isEmpty()) {
       
  7306 					var loc;
       
  7307 					return area.contains(point)
       
  7308 						|| (loc = area.getNearestLocation(point))
       
  7309 							&& isCloseEnough(loc.getPoint(), tolerancePadding);
       
  7310 				}
       
  7311 			}
       
  7312 			return isCloseEnough(segment._point, strokePadding);
       
  7313 		}
       
  7314 
       
  7315 		if (options.ends && !options.segments && !closed) {
       
  7316 			if (res = checkSegmentPoints(segments[0], true)
       
  7317 					|| checkSegmentPoints(segments[numSegments - 1], true))
       
  7318 				return res;
       
  7319 		} else if (options.segments || options.handles) {
       
  7320 			for (var i = 0; i < numSegments; i++)
       
  7321 				if (res = checkSegmentPoints(segments[i]))
       
  7322 					return res;
       
  7323 		}
       
  7324 		if (radius !== null) {
       
  7325 			loc = this.getNearestLocation(point);
       
  7326 			if (loc) {
       
  7327 				var parameter = loc.getParameter();
       
  7328 				if (parameter === 0 || parameter === 1 && numSegments > 1) {
       
  7329 					if (!checkSegmentStroke(loc.getSegment()))
       
  7330 						loc = null;
       
  7331 				} else if (!isCloseEnough(loc.getPoint(), strokePadding)) {
       
  7332 					loc = null;
       
  7333 				}
       
  7334 			}
       
  7335 			if (!loc && join === 'miter' && numSegments > 1) {
       
  7336 				for (var i = 0; i < numSegments; i++) {
       
  7337 					var segment = segments[i];
       
  7338 					if (point.getDistance(segment._point) <= miterLimit
       
  7339 							&& checkSegmentStroke(segment)) {
       
  7340 						loc = segment.getLocation();
       
  7341 						break;
       
  7342 					}
       
  7343 				}
       
  7344 			}
       
  7345 		}
       
  7346 		return !loc && hitFill && this._contains(point)
       
  7347 				|| loc && !hitStroke && !hitCurves
       
  7348 					? new HitResult('fill', this)
       
  7349 					: loc
       
  7350 						? new HitResult(hitStroke ? 'stroke' : 'curve', this, {
       
  7351 							location: loc,
       
  7352 							point: loc.getPoint()
       
  7353 						})
       
  7354 						: null;
       
  7355 	}
       
  7356 
       
  7357 }, Base.each(['getPoint', 'getTangent', 'getNormal', 'getCurvature'],
       
  7358 	function(name) {
       
  7359 		this[name + 'At'] = function(offset, isParameter) {
       
  7360 			var loc = this.getLocationAt(offset, isParameter);
       
  7361 			return loc && loc[name]();
       
  7362 		};
       
  7363 	},
       
  7364 {
       
  7365 	beans: false,
       
  7366 
       
  7367 	_getOffset: function(location) {
       
  7368 		var index = location && location.getIndex();
       
  7369 		if (index != null) {
       
  7370 			var curves = this.getCurves(),
       
  7371 				offset = 0;
       
  7372 			for (var i = 0; i < index; i++)
       
  7373 				offset += curves[i].getLength();
       
  7374 			var curve = curves[index],
       
  7375 				parameter = location.getParameter();
       
  7376 			if (parameter > 0)
       
  7377 				offset += curve.getPartLength(0, parameter);
       
  7378 			return offset;
       
  7379 		}
       
  7380 		return null;
       
  7381 	},
       
  7382 
       
  7383 	getLocationOf: function() {
       
  7384 		var point = Point.read(arguments),
       
  7385 			curves = this.getCurves();
       
  7386 		for (var i = 0, l = curves.length; i < l; i++) {
       
  7387 			var loc = curves[i].getLocationOf(point);
       
  7388 			if (loc)
       
  7389 				return loc;
       
  7390 		}
       
  7391 		return null;
       
  7392 	},
       
  7393 
       
  7394 	getOffsetOf: function() {
       
  7395 		var loc = this.getLocationOf.apply(this, arguments);
       
  7396 		return loc ? loc.getOffset() : null;
       
  7397 	},
       
  7398 
       
  7399 	getLocationAt: function(offset, isParameter) {
       
  7400 		var curves = this.getCurves(),
       
  7401 			length = 0;
       
  7402 		if (isParameter) {
       
  7403 			var index = ~~offset;
       
  7404 			return curves[index].getLocationAt(offset - index, true);
       
  7405 		}
       
  7406 		for (var i = 0, l = curves.length; i < l; i++) {
       
  7407 			var start = length,
       
  7408 				curve = curves[i];
       
  7409 			length += curve.getLength();
       
  7410 			if (length > offset) {
       
  7411 				return curve.getLocationAt(offset - start);
       
  7412 			}
       
  7413 		}
       
  7414 		if (offset <= this.getLength())
       
  7415 			return new CurveLocation(curves[curves.length - 1], 1);
       
  7416 		return null;
       
  7417 	},
       
  7418 
       
  7419 	getNearestLocation: function() {
       
  7420 		var point = Point.read(arguments),
       
  7421 			curves = this.getCurves(),
       
  7422 			minDist = Infinity,
       
  7423 			minLoc = null;
       
  7424 		for (var i = 0, l = curves.length; i < l; i++) {
       
  7425 			var loc = curves[i].getNearestLocation(point);
       
  7426 			if (loc._distance < minDist) {
       
  7427 				minDist = loc._distance;
       
  7428 				minLoc = loc;
       
  7429 			}
       
  7430 		}
       
  7431 		return minLoc;
       
  7432 	},
       
  7433 
       
  7434 	getNearestPoint: function() {
       
  7435 		return this.getNearestLocation.apply(this, arguments).getPoint();
       
  7436 	}
       
  7437 }), new function() {
       
  7438 
       
  7439 	function drawHandles(ctx, segments, matrix, size) {
       
  7440 		var half = size / 2;
       
  7441 
       
  7442 		function drawHandle(index) {
       
  7443 			var hX = coords[index],
       
  7444 				hY = coords[index + 1];
       
  7445 			if (pX != hX || pY != hY) {
       
  7446 				ctx.beginPath();
       
  7447 				ctx.moveTo(pX, pY);
       
  7448 				ctx.lineTo(hX, hY);
       
  7449 				ctx.stroke();
       
  7450 				ctx.beginPath();
       
  7451 				ctx.arc(hX, hY, half, 0, Math.PI * 2, true);
       
  7452 				ctx.fill();
       
  7453 			}
       
  7454 		}
       
  7455 
       
  7456 		var coords = new Array(6);
       
  7457 		for (var i = 0, l = segments.length; i < l; i++) {
       
  7458 			var segment = segments[i];
       
  7459 			segment._transformCoordinates(matrix, coords, false);
       
  7460 			var state = segment._selectionState,
       
  7461 				pX = coords[0],
       
  7462 				pY = coords[1];
       
  7463 			if (state & 1)
       
  7464 				drawHandle(2);
       
  7465 			if (state & 2)
       
  7466 				drawHandle(4);
       
  7467 			ctx.fillRect(pX - half, pY - half, size, size);
       
  7468 			if (!(state & 4)) {
       
  7469 				var fillStyle = ctx.fillStyle;
       
  7470 				ctx.fillStyle = '#ffffff';
       
  7471 				ctx.fillRect(pX - half + 1, pY - half + 1, size - 2, size - 2);
       
  7472 				ctx.fillStyle = fillStyle;
       
  7473 			}
       
  7474 		}
       
  7475 	}
       
  7476 
       
  7477 	function drawSegments(ctx, path, matrix) {
       
  7478 		var segments = path._segments,
       
  7479 			length = segments.length,
       
  7480 			coords = new Array(6),
       
  7481 			first = true,
       
  7482 			curX, curY,
       
  7483 			prevX, prevY,
       
  7484 			inX, inY,
       
  7485 			outX, outY;
       
  7486 
       
  7487 		function drawSegment(segment) {
       
  7488 			if (matrix) {
       
  7489 				segment._transformCoordinates(matrix, coords, false);
       
  7490 				curX = coords[0];
       
  7491 				curY = coords[1];
       
  7492 			} else {
       
  7493 				var point = segment._point;
       
  7494 				curX = point._x;
       
  7495 				curY = point._y;
       
  7496 			}
       
  7497 			if (first) {
       
  7498 				ctx.moveTo(curX, curY);
       
  7499 				first = false;
       
  7500 			} else {
       
  7501 				if (matrix) {
       
  7502 					inX = coords[2];
       
  7503 					inY = coords[3];
       
  7504 				} else {
       
  7505 					var handle = segment._handleIn;
       
  7506 					inX = curX + handle._x;
       
  7507 					inY = curY + handle._y;
       
  7508 				}
       
  7509 				if (inX === curX && inY === curY
       
  7510 						&& outX === prevX && outY === prevY) {
       
  7511 					ctx.lineTo(curX, curY);
       
  7512 				} else {
       
  7513 					ctx.bezierCurveTo(outX, outY, inX, inY, curX, curY);
       
  7514 				}
       
  7515 			}
       
  7516 			prevX = curX;
       
  7517 			prevY = curY;
       
  7518 			if (matrix) {
       
  7519 				outX = coords[4];
       
  7520 				outY = coords[5];
       
  7521 			} else {
       
  7522 				var handle = segment._handleOut;
       
  7523 				outX = prevX + handle._x;
       
  7524 				outY = prevY + handle._y;
       
  7525 			}
       
  7526 		}
       
  7527 
       
  7528 		for (var i = 0; i < length; i++)
       
  7529 			drawSegment(segments[i]);
       
  7530 		if (path._closed && length > 0)
       
  7531 			drawSegment(segments[0]);
       
  7532 	}
       
  7533 
       
  7534 	return {
       
  7535 		_draw: function(ctx, param, strokeMatrix) {
       
  7536 			var dontStart = param.dontStart,
       
  7537 				dontPaint = param.dontFinish || param.clip,
       
  7538 				style = this.getStyle(),
       
  7539 				hasFill = style.hasFill(),
       
  7540 				hasStroke = style.hasStroke(),
       
  7541 				dashArray = style.getDashArray(),
       
  7542 				dashLength = !paper.support.nativeDash && hasStroke
       
  7543 						&& dashArray && dashArray.length;
       
  7544 
       
  7545 			if (!dontStart)
       
  7546 				ctx.beginPath();
       
  7547 
       
  7548 			if (!dontStart && this._currentPath) {
       
  7549 				ctx.currentPath = this._currentPath;
       
  7550 			} else if (hasFill || hasStroke && !dashLength || dontPaint) {
       
  7551 				drawSegments(ctx, this, strokeMatrix);
       
  7552 				if (this._closed)
       
  7553 					ctx.closePath();
       
  7554 				if (!dontStart)
       
  7555 					this._currentPath = ctx.currentPath;
       
  7556 			}
       
  7557 
       
  7558 			function getOffset(i) {
       
  7559 				return dashArray[((i % dashLength) + dashLength) % dashLength];
       
  7560 			}
       
  7561 
       
  7562 			if (!dontPaint && (hasFill || hasStroke)) {
       
  7563 				this._setStyles(ctx);
       
  7564 				if (hasFill) {
       
  7565 					ctx.fill(style.getWindingRule());
       
  7566 					ctx.shadowColor = 'rgba(0,0,0,0)';
       
  7567 				}
       
  7568 				if (hasStroke) {
       
  7569 					if (dashLength) {
       
  7570 						if (!dontStart)
       
  7571 							ctx.beginPath();
       
  7572 						var iterator = new PathIterator(this, 32, 0.25,
       
  7573 								strokeMatrix),
       
  7574 							length = iterator.length,
       
  7575 							from = -style.getDashOffset(), to,
       
  7576 							i = 0;
       
  7577 						from = from % length;
       
  7578 						while (from > 0) {
       
  7579 							from -= getOffset(i--) + getOffset(i--);
       
  7580 						}
       
  7581 						while (from < length) {
       
  7582 							to = from + getOffset(i++);
       
  7583 							if (from > 0 || to > 0)
       
  7584 								iterator.drawPart(ctx,
       
  7585 										Math.max(from, 0), Math.max(to, 0));
       
  7586 							from = to + getOffset(i++);
       
  7587 						}
       
  7588 					}
       
  7589 					ctx.stroke();
       
  7590 				}
       
  7591 			}
       
  7592 		},
       
  7593 
       
  7594 		_drawSelected: function(ctx, matrix) {
       
  7595 			ctx.beginPath();
       
  7596 			drawSegments(ctx, this, matrix);
       
  7597 			ctx.stroke();
       
  7598 			drawHandles(ctx, this._segments, matrix, paper.settings.handleSize);
       
  7599 		}
       
  7600 	};
       
  7601 }, new function() {
       
  7602 
       
  7603 	function getFirstControlPoints(rhs) {
       
  7604 		var n = rhs.length,
       
  7605 			x = [],
       
  7606 			tmp = [],
       
  7607 			b = 2;
       
  7608 		x[0] = rhs[0] / b;
       
  7609 		for (var i = 1; i < n; i++) {
       
  7610 			tmp[i] = 1 / b;
       
  7611 			b = (i < n - 1 ? 4 : 2) - tmp[i];
       
  7612 			x[i] = (rhs[i] - x[i - 1]) / b;
       
  7613 		}
       
  7614 		for (var i = 1; i < n; i++) {
       
  7615 			x[n - i - 1] -= tmp[n - i] * x[n - i];
       
  7616 		}
       
  7617 		return x;
       
  7618 	}
       
  7619 
       
  7620 	return {
       
  7621 		smooth: function() {
       
  7622 			var segments = this._segments,
       
  7623 				size = segments.length,
       
  7624 				closed = this._closed,
       
  7625 				n = size,
       
  7626 				overlap = 0;
       
  7627 			if (size <= 2)
       
  7628 				return;
       
  7629 			if (closed) {
       
  7630 				overlap = Math.min(size, 4);
       
  7631 				n += Math.min(size, overlap) * 2;
       
  7632 			}
       
  7633 			var knots = [];
       
  7634 			for (var i = 0; i < size; i++)
       
  7635 				knots[i + overlap] = segments[i]._point;
       
  7636 			if (closed) {
       
  7637 				for (var i = 0; i < overlap; i++) {
       
  7638 					knots[i] = segments[i + size - overlap]._point;
       
  7639 					knots[i + size + overlap] = segments[i]._point;
       
  7640 				}
       
  7641 			} else {
       
  7642 				n--;
       
  7643 			}
       
  7644 			var rhs = [];
       
  7645 
       
  7646 			for (var i = 1; i < n - 1; i++)
       
  7647 				rhs[i] = 4 * knots[i]._x + 2 * knots[i + 1]._x;
       
  7648 			rhs[0] = knots[0]._x + 2 * knots[1]._x;
       
  7649 			rhs[n - 1] = 3 * knots[n - 1]._x;
       
  7650 			var x = getFirstControlPoints(rhs);
       
  7651 
       
  7652 			for (var i = 1; i < n - 1; i++)
       
  7653 				rhs[i] = 4 * knots[i]._y + 2 * knots[i + 1]._y;
       
  7654 			rhs[0] = knots[0]._y + 2 * knots[1]._y;
       
  7655 			rhs[n - 1] = 3 * knots[n - 1]._y;
       
  7656 			var y = getFirstControlPoints(rhs);
       
  7657 
       
  7658 			if (closed) {
       
  7659 				for (var i = 0, j = size; i < overlap; i++, j++) {
       
  7660 					var f1 = i / overlap,
       
  7661 						f2 = 1 - f1,
       
  7662 						ie = i + overlap,
       
  7663 						je = j + overlap;
       
  7664 					x[j] = x[i] * f1 + x[j] * f2;
       
  7665 					y[j] = y[i] * f1 + y[j] * f2;
       
  7666 					x[je] = x[ie] * f2 + x[je] * f1;
       
  7667 					y[je] = y[ie] * f2 + y[je] * f1;
       
  7668 				}
       
  7669 				n--;
       
  7670 			}
       
  7671 			var handleIn = null;
       
  7672 			for (var i = overlap; i <= n - overlap; i++) {
       
  7673 				var segment = segments[i - overlap];
       
  7674 				if (handleIn)
       
  7675 					segment.setHandleIn(handleIn.subtract(segment._point));
       
  7676 				if (i < n) {
       
  7677 					segment.setHandleOut(
       
  7678 							new Point(x[i], y[i]).subtract(segment._point));
       
  7679 					handleIn = i < n - 1
       
  7680 							? new Point(
       
  7681 								2 * knots[i + 1]._x - x[i + 1],
       
  7682 								2 * knots[i + 1]._y - y[i + 1])
       
  7683 							: new Point(
       
  7684 								(knots[n]._x + x[n - 1]) / 2,
       
  7685 								(knots[n]._y + y[n - 1]) / 2);
       
  7686 				}
       
  7687 			}
       
  7688 			if (closed && handleIn) {
       
  7689 				var segment = this._segments[0];
       
  7690 				segment.setHandleIn(handleIn.subtract(segment._point));
       
  7691 			}
       
  7692 		}
       
  7693 	};
       
  7694 }, new function() {
       
  7695 	function getCurrentSegment(that) {
       
  7696 		var segments = that._segments;
       
  7697 		if (segments.length === 0)
       
  7698 			throw new Error('Use a moveTo() command first');
       
  7699 		return segments[segments.length - 1];
       
  7700 	}
       
  7701 
       
  7702 	return {
       
  7703 		moveTo: function() {
       
  7704 			var segments = this._segments;
       
  7705 			if (segments.length === 1)
       
  7706 				this.removeSegment(0);
       
  7707 			if (!segments.length)
       
  7708 				this._add([ new Segment(Point.read(arguments)) ]);
       
  7709 		},
       
  7710 
       
  7711 		moveBy: function() {
       
  7712 			throw new Error('moveBy() is unsupported on Path items.');
       
  7713 		},
       
  7714 
       
  7715 		lineTo: function() {
       
  7716 			this._add([ new Segment(Point.read(arguments)) ]);
       
  7717 		},
       
  7718 
       
  7719 		cubicCurveTo: function() {
       
  7720 			var handle1 = Point.read(arguments),
       
  7721 				handle2 = Point.read(arguments),
       
  7722 				to = Point.read(arguments),
       
  7723 				current = getCurrentSegment(this);
       
  7724 			current.setHandleOut(handle1.subtract(current._point));
       
  7725 			this._add([ new Segment(to, handle2.subtract(to)) ]);
       
  7726 		},
       
  7727 
       
  7728 		quadraticCurveTo: function() {
       
  7729 			var handle = Point.read(arguments),
       
  7730 				to = Point.read(arguments),
       
  7731 				current = getCurrentSegment(this)._point;
       
  7732 			this.cubicCurveTo(
       
  7733 				handle.add(current.subtract(handle).multiply(1 / 3)),
       
  7734 				handle.add(to.subtract(handle).multiply(1 / 3)),
       
  7735 				to
       
  7736 			);
       
  7737 		},
       
  7738 
       
  7739 		curveTo: function() {
       
  7740 			var through = Point.read(arguments),
       
  7741 				to = Point.read(arguments),
       
  7742 				t = Base.pick(Base.read(arguments), 0.5),
       
  7743 				t1 = 1 - t,
       
  7744 				current = getCurrentSegment(this)._point,
       
  7745 				handle = through.subtract(current.multiply(t1 * t1))
       
  7746 					.subtract(to.multiply(t * t)).divide(2 * t * t1);
       
  7747 			if (handle.isNaN())
       
  7748 				throw new Error(
       
  7749 					'Cannot put a curve through points with parameter = ' + t);
       
  7750 			this.quadraticCurveTo(handle, to);
       
  7751 		},
       
  7752 
       
  7753 		arcTo: function() {
       
  7754 			var current = getCurrentSegment(this),
       
  7755 				from = current._point,
       
  7756 				to = Point.read(arguments),
       
  7757 				through,
       
  7758 				peek = Base.peek(arguments),
       
  7759 				clockwise = Base.pick(peek, true),
       
  7760 				center, extent, vector, matrix;
       
  7761 			if (typeof clockwise === 'boolean') {
       
  7762 				var middle = from.add(to).divide(2),
       
  7763 				through = middle.add(middle.subtract(from).rotate(
       
  7764 						clockwise ? -90 : 90));
       
  7765 			} else if (Base.remain(arguments) <= 2) {
       
  7766 				through = to;
       
  7767 				to = Point.read(arguments);
       
  7768 			} else {
       
  7769 				var radius = Size.read(arguments);
       
  7770 				if (radius.isZero())
       
  7771 					return this.lineTo(to);
       
  7772 				var rotation = Base.read(arguments),
       
  7773 					clockwise = !!Base.read(arguments),
       
  7774 					large = !!Base.read(arguments),
       
  7775 					middle = from.add(to).divide(2),
       
  7776 					pt = from.subtract(middle).rotate(-rotation),
       
  7777 					x = pt.x,
       
  7778 					y = pt.y,
       
  7779 					abs = Math.abs,
       
  7780 					epsilon = 1e-12,
       
  7781 					rx = abs(radius.width),
       
  7782 					ry = abs(radius.height),
       
  7783 					rxSq = rx * rx,
       
  7784 					rySq = ry * ry,
       
  7785 					xSq =  x * x,
       
  7786 					ySq =  y * y;
       
  7787 				var factor = Math.sqrt(xSq / rxSq + ySq / rySq);
       
  7788 				if (factor > 1) {
       
  7789 					rx *= factor;
       
  7790 					ry *= factor;
       
  7791 					rxSq = rx * rx;
       
  7792 					rySq = ry * ry;
       
  7793 				}
       
  7794 				factor = (rxSq * rySq - rxSq * ySq - rySq * xSq) /
       
  7795 						(rxSq * ySq + rySq * xSq);
       
  7796 				if (abs(factor) < epsilon)
       
  7797 					factor = 0;
       
  7798 				if (factor < 0)
       
  7799 					throw new Error(
       
  7800 							'Cannot create an arc with the given arguments');
       
  7801 				center = new Point(rx * y / ry, -ry * x / rx)
       
  7802 						.multiply((large === clockwise ? -1 : 1)
       
  7803 							* Math.sqrt(factor))
       
  7804 						.rotate(rotation).add(middle);
       
  7805 				matrix = new Matrix().translate(center).rotate(rotation)
       
  7806 						.scale(rx, ry);
       
  7807 				vector = matrix._inverseTransform(from);
       
  7808 				extent = vector.getDirectedAngle(matrix._inverseTransform(to));
       
  7809 				if (!clockwise && extent > 0)
       
  7810 					extent -= 360;
       
  7811 				else if (clockwise && extent < 0)
       
  7812 					extent += 360;
       
  7813 			}
       
  7814 			if (through) {
       
  7815 				var l1 = new Line(from.add(through).divide(2),
       
  7816 							through.subtract(from).rotate(90), true),
       
  7817 					l2 = new Line(through.add(to).divide(2),
       
  7818 							to.subtract(through).rotate(90), true),
       
  7819 					line = new Line(from, to),
       
  7820 					throughSide = line.getSide(through);
       
  7821 				center = l1.intersect(l2, true);
       
  7822 				if (!center) {
       
  7823 					if (!throughSide)
       
  7824 						return this.lineTo(to);
       
  7825 					throw new Error(
       
  7826 							'Cannot create an arc with the given arguments');
       
  7827 				}
       
  7828 				vector = from.subtract(center);
       
  7829 				extent = vector.getDirectedAngle(to.subtract(center));
       
  7830 				var centerSide = line.getSide(center);
       
  7831 				if (centerSide === 0) {
       
  7832 					extent = throughSide * Math.abs(extent);
       
  7833 				} else if (throughSide === centerSide) {
       
  7834 					extent += extent < 0 ? 360 : -360;
       
  7835 				}
       
  7836 			}
       
  7837 			var ext = Math.abs(extent),
       
  7838 				count = ext >= 360 ? 4 : Math.ceil(ext / 90),
       
  7839 				inc = extent / count,
       
  7840 				half = inc * Math.PI / 360,
       
  7841 				z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
       
  7842 				segments = [];
       
  7843 			for (var i = 0; i <= count; i++) {
       
  7844 				var pt = to,
       
  7845 					out = null;
       
  7846 				if (i < count) {
       
  7847 					out = vector.rotate(90).multiply(z);
       
  7848 					if (matrix) {
       
  7849 						pt = matrix._transformPoint(vector);
       
  7850 						out = matrix._transformPoint(vector.add(out))
       
  7851 								.subtract(pt);
       
  7852 					} else {
       
  7853 						pt = center.add(vector);
       
  7854 					}
       
  7855 				}
       
  7856 				if (i === 0) {
       
  7857 					current.setHandleOut(out);
       
  7858 				} else {
       
  7859 					var _in = vector.rotate(-90).multiply(z);
       
  7860 					if (matrix) {
       
  7861 						_in = matrix._transformPoint(vector.add(_in))
       
  7862 								.subtract(pt);
       
  7863 					}
       
  7864 					segments.push(new Segment(pt, _in, out));
       
  7865 				}
       
  7866 				vector = vector.rotate(inc);
       
  7867 			}
       
  7868 			this._add(segments);
       
  7869 		},
       
  7870 
       
  7871 		lineBy: function() {
       
  7872 			var to = Point.read(arguments),
       
  7873 				current = getCurrentSegment(this)._point;
       
  7874 			this.lineTo(current.add(to));
       
  7875 		},
       
  7876 
       
  7877 		curveBy: function() {
       
  7878 			var through = Point.read(arguments),
       
  7879 				to = Point.read(arguments),
       
  7880 				parameter = Base.read(arguments),
       
  7881 				current = getCurrentSegment(this)._point;
       
  7882 			this.curveTo(current.add(through), current.add(to), parameter);
       
  7883 		},
       
  7884 
       
  7885 		cubicCurveBy: function() {
       
  7886 			var handle1 = Point.read(arguments),
       
  7887 				handle2 = Point.read(arguments),
       
  7888 				to = Point.read(arguments),
       
  7889 				current = getCurrentSegment(this)._point;
       
  7890 			this.cubicCurveTo(current.add(handle1), current.add(handle2),
       
  7891 					current.add(to));
       
  7892 		},
       
  7893 
       
  7894 		quadraticCurveBy: function() {
       
  7895 			var handle = Point.read(arguments),
       
  7896 				to = Point.read(arguments),
       
  7897 				current = getCurrentSegment(this)._point;
       
  7898 			this.quadraticCurveTo(current.add(handle), current.add(to));
       
  7899 		},
       
  7900 
       
  7901 		arcBy: function() {
       
  7902 			var current = getCurrentSegment(this)._point,
       
  7903 				point = current.add(Point.read(arguments)),
       
  7904 				clockwise = Base.pick(Base.peek(arguments), true);
       
  7905 			if (typeof clockwise === 'boolean') {
       
  7906 				this.arcTo(point, clockwise);
       
  7907 			} else {
       
  7908 				this.arcTo(point, current.add(Point.read(arguments)));
       
  7909 			}
       
  7910 		},
       
  7911 
       
  7912 		closePath: function(join) {
       
  7913 			this.setClosed(true);
       
  7914 			if (join)
       
  7915 				this.join();
       
  7916 		}
       
  7917 	};
       
  7918 }, {
       
  7919 
       
  7920 	_getBounds: function(getter, matrix) {
       
  7921 		return Path[getter](this._segments, this._closed, this.getStyle(),
       
  7922 				matrix);
       
  7923 	},
       
  7924 
       
  7925 statics: {
       
  7926 	isClockwise: function(segments) {
       
  7927 		var sum = 0;
       
  7928 		for (var i = 0, l = segments.length; i < l; i++)
       
  7929 			sum += Curve.getEdgeSum(Curve.getValues(
       
  7930 					segments[i], segments[i + 1 < l ? i + 1 : 0]));
       
  7931 		return sum > 0;
       
  7932 	},
       
  7933 
       
  7934 	getBounds: function(segments, closed, style, matrix, strokePadding) {
       
  7935 		var first = segments[0];
       
  7936 		if (!first)
       
  7937 			return new Rectangle();
       
  7938 		var coords = new Array(6),
       
  7939 			prevCoords = first._transformCoordinates(matrix, new Array(6), false),
       
  7940 			min = prevCoords.slice(0, 2),
       
  7941 			max = min.slice(),
       
  7942 			roots = new Array(2);
       
  7943 
       
  7944 		function processSegment(segment) {
       
  7945 			segment._transformCoordinates(matrix, coords, false);
       
  7946 			for (var i = 0; i < 2; i++) {
       
  7947 				Curve._addBounds(
       
  7948 					prevCoords[i],
       
  7949 					prevCoords[i + 4],
       
  7950 					coords[i + 2],
       
  7951 					coords[i],
       
  7952 					i, strokePadding ? strokePadding[i] : 0, min, max, roots);
       
  7953 			}
       
  7954 			var tmp = prevCoords;
       
  7955 			prevCoords = coords;
       
  7956 			coords = tmp;
       
  7957 		}
       
  7958 
       
  7959 		for (var i = 1, l = segments.length; i < l; i++)
       
  7960 			processSegment(segments[i]);
       
  7961 		if (closed)
       
  7962 			processSegment(first);
       
  7963 		return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]);
       
  7964 	},
       
  7965 
       
  7966 	getStrokeBounds: function(segments, closed, style, matrix) {
       
  7967 		if (!style.hasStroke())
       
  7968 			return Path.getBounds(segments, closed, style, matrix);
       
  7969 		var length = segments.length - (closed ? 0 : 1),
       
  7970 			radius = style.getStrokeWidth() / 2,
       
  7971 			padding = Path._getPenPadding(radius, matrix),
       
  7972 			bounds = Path.getBounds(segments, closed, style, matrix, padding),
       
  7973 			join = style.getStrokeJoin(),
       
  7974 			cap = style.getStrokeCap(),
       
  7975 			miterLimit = radius * style.getMiterLimit();
       
  7976 		var joinBounds = new Rectangle(new Size(padding).multiply(2));
       
  7977 
       
  7978 		function add(point) {
       
  7979 			bounds = bounds.include(matrix
       
  7980 				? matrix._transformPoint(point, point) : point);
       
  7981 		}
       
  7982 
       
  7983 		function addRound(segment) {
       
  7984 			bounds = bounds.unite(joinBounds.setCenter(matrix
       
  7985 				? matrix._transformPoint(segment._point) : segment._point));
       
  7986 		}
       
  7987 
       
  7988 		function addJoin(segment, join) {
       
  7989 			var handleIn = segment._handleIn,
       
  7990 				handleOut = segment._handleOut;
       
  7991 			if (join === 'round' || !handleIn.isZero() && !handleOut.isZero()
       
  7992 					&& handleIn.isColinear(handleOut)) {
       
  7993 				addRound(segment);
       
  7994 			} else {
       
  7995 				Path._addBevelJoin(segment, join, radius, miterLimit, add);
       
  7996 			}
       
  7997 		}
       
  7998 
       
  7999 		function addCap(segment, cap) {
       
  8000 			if (cap === 'round') {
       
  8001 				addRound(segment);
       
  8002 			} else {
       
  8003 				Path._addSquareCap(segment, cap, radius, add);
       
  8004 			}
       
  8005 		}
       
  8006 
       
  8007 		for (var i = 1; i < length; i++)
       
  8008 			addJoin(segments[i], join);
       
  8009 		if (closed) {
       
  8010 			addJoin(segments[0], join);
       
  8011 		} else if (length > 0) {
       
  8012 			addCap(segments[0], cap);
       
  8013 			addCap(segments[segments.length - 1], cap);
       
  8014 		}
       
  8015 		return bounds;
       
  8016 	},
       
  8017 
       
  8018 	_getPenPadding: function(radius, matrix) {
       
  8019 		if (!matrix)
       
  8020 			return [radius, radius];
       
  8021 		var mx = matrix.shiftless(),
       
  8022 			hor = mx.transform(new Point(radius, 0)),
       
  8023 			ver = mx.transform(new Point(0, radius)),
       
  8024 			phi = hor.getAngleInRadians(),
       
  8025 			a = hor.getLength(),
       
  8026 			b = ver.getLength();
       
  8027 		var sin = Math.sin(phi),
       
  8028 			cos = Math.cos(phi),
       
  8029 			tan = Math.tan(phi),
       
  8030 			tx = -Math.atan(b * tan / a),
       
  8031 			ty = Math.atan(b / (tan * a));
       
  8032 		return [Math.abs(a * Math.cos(tx) * cos - b * Math.sin(tx) * sin),
       
  8033 				Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)];
       
  8034 	},
       
  8035 
       
  8036 	_addBevelJoin: function(segment, join, radius, miterLimit, addPoint, area) {
       
  8037 		var curve2 = segment.getCurve(),
       
  8038 			curve1 = curve2.getPrevious(),
       
  8039 			point = curve2.getPointAt(0, true),
       
  8040 			normal1 = curve1.getNormalAt(1, true),
       
  8041 			normal2 = curve2.getNormalAt(0, true),
       
  8042 			step = normal1.getDirectedAngle(normal2) < 0 ? -radius : radius;
       
  8043 		normal1.setLength(step);
       
  8044 		normal2.setLength(step);
       
  8045 		if (area) {
       
  8046 			addPoint(point);
       
  8047 			addPoint(point.add(normal1));
       
  8048 		}
       
  8049 		if (join === 'miter') {
       
  8050 			var corner = new Line(
       
  8051 					point.add(normal1),
       
  8052 					new Point(-normal1.y, normal1.x), true
       
  8053 				).intersect(new Line(
       
  8054 					point.add(normal2),
       
  8055 					new Point(-normal2.y, normal2.x), true
       
  8056 				), true);
       
  8057 			if (corner && point.getDistance(corner) <= miterLimit) {
       
  8058 				addPoint(corner);
       
  8059 				if (!area)
       
  8060 					return;
       
  8061 			}
       
  8062 		}
       
  8063 		if (!area)
       
  8064 			addPoint(point.add(normal1));
       
  8065 		addPoint(point.add(normal2));
       
  8066 	},
       
  8067 
       
  8068 	_addSquareCap: function(segment, cap, radius, addPoint, area) {
       
  8069 		var point = segment._point,
       
  8070 			loc = segment.getLocation(),
       
  8071 			normal = loc.getNormal().normalize(radius);
       
  8072 		if (area) {
       
  8073 			addPoint(point.subtract(normal));
       
  8074 			addPoint(point.add(normal));
       
  8075 		}
       
  8076 		if (cap === 'square')
       
  8077 			point = point.add(normal.rotate(loc.getParameter() === 0 ? -90 : 90));
       
  8078 		addPoint(point.add(normal));
       
  8079 		addPoint(point.subtract(normal));
       
  8080 	},
       
  8081 
       
  8082 	getHandleBounds: function(segments, closed, style, matrix, strokePadding,
       
  8083 			joinPadding) {
       
  8084 		var coords = new Array(6),
       
  8085 			x1 = Infinity,
       
  8086 			x2 = -x1,
       
  8087 			y1 = x1,
       
  8088 			y2 = x2;
       
  8089 		for (var i = 0, l = segments.length; i < l; i++) {
       
  8090 			var segment = segments[i];
       
  8091 			segment._transformCoordinates(matrix, coords, false);
       
  8092 			for (var j = 0; j < 6; j += 2) {
       
  8093 				var padding = j === 0 ? joinPadding : strokePadding,
       
  8094 					paddingX = padding ? padding[0] : 0,
       
  8095 					paddingY = padding ? padding[1] : 0,
       
  8096 					x = coords[j],
       
  8097 					y = coords[j + 1],
       
  8098 					xn = x - paddingX,
       
  8099 					xx = x + paddingX,
       
  8100 					yn = y - paddingY,
       
  8101 					yx = y + paddingY;
       
  8102 				if (xn < x1) x1 = xn;
       
  8103 				if (xx > x2) x2 = xx;
       
  8104 				if (yn < y1) y1 = yn;
       
  8105 				if (yx > y2) y2 = yx;
       
  8106 			}
       
  8107 		}
       
  8108 		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
       
  8109 	},
       
  8110 
       
  8111 	getRoughBounds: function(segments, closed, style, matrix) {
       
  8112 		var strokeRadius = style.hasStroke() ? style.getStrokeWidth() / 2 : 0,
       
  8113 			joinRadius = strokeRadius;
       
  8114 		if (strokeRadius > 0) {
       
  8115 			if (style.getStrokeJoin() === 'miter')
       
  8116 				joinRadius = strokeRadius * style.getMiterLimit();
       
  8117 			if (style.getStrokeCap() === 'square')
       
  8118 				joinRadius = Math.max(joinRadius, strokeRadius * Math.sqrt(2));
       
  8119 		}
       
  8120 		return Path.getHandleBounds(segments, closed, style, matrix,
       
  8121 				Path._getPenPadding(strokeRadius, matrix),
       
  8122 				Path._getPenPadding(joinRadius, matrix));
       
  8123 	}
       
  8124 }});
       
  8125 
       
  8126 Path.inject({ statics: new function() {
       
  8127 
       
  8128 	var kappa = 0.5522847498307936,
       
  8129 		ellipseSegments = [
       
  8130 			new Segment([-1, 0], [0, kappa ], [0, -kappa]),
       
  8131 			new Segment([0, -1], [-kappa, 0], [kappa, 0 ]),
       
  8132 			new Segment([1, 0], [0, -kappa], [0, kappa ]),
       
  8133 			new Segment([0, 1], [kappa, 0 ], [-kappa, 0])
       
  8134 		];
       
  8135 
       
  8136 	function createPath(segments, closed, args) {
       
  8137 		var props = Base.getNamed(args),
       
  8138 			path = new Path(props && props.insert === false && Item.NO_INSERT);
       
  8139 		path._add(segments);
       
  8140 		path._closed = closed;
       
  8141 		return path.set(props);
       
  8142 	}
       
  8143 
       
  8144 	function createEllipse(center, radius, args) {
       
  8145 		var segments = new Array(4);
       
  8146 		for (var i = 0; i < 4; i++) {
       
  8147 			var segment = ellipseSegments[i];
       
  8148 			segments[i] = new Segment(
       
  8149 				segment._point.multiply(radius).add(center),
       
  8150 				segment._handleIn.multiply(radius),
       
  8151 				segment._handleOut.multiply(radius)
       
  8152 			);
       
  8153 		}
       
  8154 		return createPath(segments, true, args);
       
  8155 	}
       
  8156 
       
  8157 	return {
       
  8158 		Line: function() {
       
  8159 			return createPath([
       
  8160 				new Segment(Point.readNamed(arguments, 'from')),
       
  8161 				new Segment(Point.readNamed(arguments, 'to'))
       
  8162 			], false, arguments);
       
  8163 		},
       
  8164 
       
  8165 		Circle: function() {
       
  8166 			var center = Point.readNamed(arguments, 'center'),
       
  8167 				radius = Base.readNamed(arguments, 'radius');
       
  8168 			return createEllipse(center, new Size(radius), arguments);
       
  8169 		},
       
  8170 
       
  8171 		Rectangle: function() {
       
  8172 			var rect = Rectangle.readNamed(arguments, 'rectangle'),
       
  8173 				radius = Size.readNamed(arguments, 'radius', 0,
       
  8174 						{ readNull: true }),
       
  8175 				bl = rect.getBottomLeft(true),
       
  8176 				tl = rect.getTopLeft(true),
       
  8177 				tr = rect.getTopRight(true),
       
  8178 				br = rect.getBottomRight(true),
       
  8179 				segments;
       
  8180 			if (!radius || radius.isZero()) {
       
  8181 				segments = [
       
  8182 					new Segment(bl),
       
  8183 					new Segment(tl),
       
  8184 					new Segment(tr),
       
  8185 					new Segment(br)
       
  8186 				];
       
  8187 			} else {
       
  8188 				radius = Size.min(radius, rect.getSize(true).divide(2));
       
  8189 				var rx = radius.width,
       
  8190 					ry = radius.height,
       
  8191 					hx = rx * kappa,
       
  8192 					hy = ry * kappa;
       
  8193 				segments = [
       
  8194 					new Segment(bl.add(rx, 0), null, [-hx, 0]),
       
  8195 					new Segment(bl.subtract(0, ry), [0, hy]),
       
  8196 					new Segment(tl.add(0, ry), null, [0, -hy]),
       
  8197 					new Segment(tl.add(rx, 0), [-hx, 0], null),
       
  8198 					new Segment(tr.subtract(rx, 0), null, [hx, 0]),
       
  8199 					new Segment(tr.add(0, ry), [0, -hy], null),
       
  8200 					new Segment(br.subtract(0, ry), null, [0, hy]),
       
  8201 					new Segment(br.subtract(rx, 0), [hx, 0])
       
  8202 				];
       
  8203 			}
       
  8204 			return createPath(segments, true, arguments);
       
  8205 		},
       
  8206 
       
  8207 		RoundRectangle: '#Rectangle',
       
  8208 
       
  8209 		Ellipse: function() {
       
  8210 			var ellipse = Shape._readEllipse(arguments);
       
  8211 			return createEllipse(ellipse.center, ellipse.radius, arguments);
       
  8212 		},
       
  8213 
       
  8214 		Oval: '#Ellipse',
       
  8215 
       
  8216 		Arc: function() {
       
  8217 			var from = Point.readNamed(arguments, 'from'),
       
  8218 				through = Point.readNamed(arguments, 'through'),
       
  8219 				to = Point.readNamed(arguments, 'to'),
       
  8220 				props = Base.getNamed(arguments),
       
  8221 				path = new Path(props && props.insert === false
       
  8222 						&& Item.NO_INSERT);
       
  8223 			path.moveTo(from);
       
  8224 			path.arcTo(through, to);
       
  8225 			return path.set(props);
       
  8226 		},
       
  8227 
       
  8228 		RegularPolygon: function() {
       
  8229 			var center = Point.readNamed(arguments, 'center'),
       
  8230 				sides = Base.readNamed(arguments, 'sides'),
       
  8231 				radius = Base.readNamed(arguments, 'radius'),
       
  8232 				step = 360 / sides,
       
  8233 				three = !(sides % 3),
       
  8234 				vector = new Point(0, three ? -radius : radius),
       
  8235 				offset = three ? -1 : 0.5,
       
  8236 				segments = new Array(sides);
       
  8237 			for (var i = 0; i < sides; i++)
       
  8238 				segments[i] = new Segment(center.add(
       
  8239 					vector.rotate((i + offset) * step)));
       
  8240 			return createPath(segments, true, arguments);
       
  8241 		},
       
  8242 
       
  8243 		Star: function() {
       
  8244 			var center = Point.readNamed(arguments, 'center'),
       
  8245 				points = Base.readNamed(arguments, 'points') * 2,
       
  8246 				radius1 = Base.readNamed(arguments, 'radius1'),
       
  8247 				radius2 = Base.readNamed(arguments, 'radius2'),
       
  8248 				step = 360 / points,
       
  8249 				vector = new Point(0, -1),
       
  8250 				segments = new Array(points);
       
  8251 			for (var i = 0; i < points; i++)
       
  8252 				segments[i] = new Segment(center.add(vector.rotate(step * i)
       
  8253 						.multiply(i % 2 ? radius2 : radius1)));
       
  8254 			return createPath(segments, true, arguments);
       
  8255 		}
       
  8256 	};
       
  8257 }});
       
  8258 
       
  8259 var CompoundPath = PathItem.extend({
       
  8260 	_class: 'CompoundPath',
       
  8261 	_serializeFields: {
       
  8262 		children: []
       
  8263 	},
       
  8264 
       
  8265 	initialize: function CompoundPath(arg) {
       
  8266 		this._children = [];
       
  8267 		this._namedChildren = {};
       
  8268 		if (!this._initialize(arg)) {
       
  8269 			if (typeof arg === 'string') {
       
  8270 				this.setPathData(arg);
       
  8271 			} else {
       
  8272 				this.addChildren(Array.isArray(arg) ? arg : arguments);
       
  8273 			}
       
  8274 		}
       
  8275 	},
       
  8276 
       
  8277 	insertChildren: function insertChildren(index, items, _preserve) {
       
  8278 		items = insertChildren.base.call(this, index, items, _preserve, Path);
       
  8279 		for (var i = 0, l = !_preserve && items && items.length; i < l; i++) {
       
  8280 			var item = items[i];
       
  8281 			if (item._clockwise === undefined)
       
  8282 				item.setClockwise(item._index === 0);
       
  8283 		}
       
  8284 		return items;
       
  8285 	},
       
  8286 
       
  8287 	reverse: function() {
       
  8288 		var children = this._children;
       
  8289 		for (var i = 0, l = children.length; i < l; i++)
       
  8290 			children[i].reverse();
       
  8291 	},
       
  8292 
       
  8293 	smooth: function() {
       
  8294 		for (var i = 0, l = this._children.length; i < l; i++)
       
  8295 			this._children[i].smooth();
       
  8296 	},
       
  8297 
       
  8298 	reduce: function reduce() {
       
  8299 		if (this._children.length === 0) {
       
  8300 			var path = new Path(Item.NO_INSERT);
       
  8301 			path.insertAbove(this);
       
  8302 			path.setStyle(this._style);
       
  8303 			this.remove();
       
  8304 			return path;
       
  8305 		} else {
       
  8306 			return reduce.base.call(this);
       
  8307 		}
       
  8308 	},
       
  8309 
       
  8310 	isClockwise: function() {
       
  8311 		var child = this.getFirstChild();
       
  8312 		return child && child.isClockwise();
       
  8313 	},
       
  8314 
       
  8315 	setClockwise: function(clockwise) {
       
  8316 		if (this.isClockwise() !== !!clockwise)
       
  8317 			this.reverse();
       
  8318 	},
       
  8319 
       
  8320 	getFirstSegment: function() {
       
  8321 		var first = this.getFirstChild();
       
  8322 		return first && first.getFirstSegment();
       
  8323 	},
       
  8324 
       
  8325 	getLastSegment: function() {
       
  8326 		var last = this.getLastChild();
       
  8327 		return last && last.getLastSegment();
       
  8328 	},
       
  8329 
       
  8330 	getCurves: function() {
       
  8331 		var children = this._children,
       
  8332 			curves = [];
       
  8333 		for (var i = 0, l = children.length; i < l; i++)
       
  8334 			curves.push.apply(curves, children[i].getCurves());
       
  8335 		return curves;
       
  8336 	},
       
  8337 
       
  8338 	getFirstCurve: function() {
       
  8339 		var first = this.getFirstChild();
       
  8340 		return first && first.getFirstCurve();
       
  8341 	},
       
  8342 
       
  8343 	getLastCurve: function() {
       
  8344 		var last = this.getLastChild();
       
  8345 		return last && last.getFirstCurve();
       
  8346 	},
       
  8347 
       
  8348 	getArea: function() {
       
  8349 		var children = this._children,
       
  8350 			area = 0;
       
  8351 		for (var i = 0, l = children.length; i < l; i++)
       
  8352 			area += children[i].getArea();
       
  8353 		return area;
       
  8354 	}
       
  8355 }, {
       
  8356 	beans: true,
       
  8357 
       
  8358 	getPathData: function(_matrix, _precision) {
       
  8359 		var children = this._children,
       
  8360 			paths = [];
       
  8361 		for (var i = 0, l = children.length; i < l; i++) {
       
  8362 			var child = children[i],
       
  8363 				mx = child._matrix;
       
  8364 			paths.push(child.getPathData(_matrix && !mx.isIdentity()
       
  8365 					? _matrix.chain(mx) : mx, _precision));
       
  8366 		}
       
  8367 		return paths.join(' ');
       
  8368 	}
       
  8369 }, {
       
  8370 	_getChildHitTestOptions: function(options) {
       
  8371 		return options.class === Path || options.type === 'path'
       
  8372 				? options
       
  8373 				: new Base(options, { fill: false });
       
  8374 	},
       
  8375 
       
  8376 	_draw: function(ctx, param, strokeMatrix) {
       
  8377 		var children = this._children;
       
  8378 		if (children.length === 0)
       
  8379 			return;
       
  8380 
       
  8381 		if (this._currentPath) {
       
  8382 			ctx.currentPath = this._currentPath;
       
  8383 		} else {
       
  8384 			param = param.extend({ dontStart: true, dontFinish: true });
       
  8385 			ctx.beginPath();
       
  8386 			for (var i = 0, l = children.length; i < l; i++)
       
  8387 				children[i].draw(ctx, param, strokeMatrix);
       
  8388 			this._currentPath = ctx.currentPath;
       
  8389 		}
       
  8390 
       
  8391 		if (!param.clip) {
       
  8392 			this._setStyles(ctx);
       
  8393 			var style = this._style;
       
  8394 			if (style.hasFill()) {
       
  8395 				ctx.fill(style.getWindingRule());
       
  8396 				ctx.shadowColor = 'rgba(0,0,0,0)';
       
  8397 			}
       
  8398 			if (style.hasStroke())
       
  8399 				ctx.stroke();
       
  8400 		}
       
  8401 	},
       
  8402 
       
  8403 	_drawSelected: function(ctx, matrix, selectedItems) {
       
  8404 		var children = this._children;
       
  8405 		for (var i = 0, l = children.length; i < l; i++) {
       
  8406 			var child = children[i],
       
  8407 				mx = child._matrix;
       
  8408 			if (!selectedItems[child._id])
       
  8409 				child._drawSelected(ctx, mx.isIdentity() ? matrix
       
  8410 						: matrix.chain(mx));
       
  8411 		}
       
  8412 	}
       
  8413 }, new function() {
       
  8414 	function getCurrentPath(that, check) {
       
  8415 		var children = that._children;
       
  8416 		if (check && children.length === 0)
       
  8417 			throw new Error('Use a moveTo() command first');
       
  8418 		return children[children.length - 1];
       
  8419 	}
       
  8420 
       
  8421 	var fields = {
       
  8422 		moveTo: function() {
       
  8423 			var current = getCurrentPath(this),
       
  8424 				path = current && current.isEmpty() ? current : new Path();
       
  8425 			if (path !== current)
       
  8426 				this.addChild(path);
       
  8427 			path.moveTo.apply(path, arguments);
       
  8428 		},
       
  8429 
       
  8430 		moveBy: function() {
       
  8431 			var current = getCurrentPath(this, true),
       
  8432 				last = current && current.getLastSegment(),
       
  8433 				point = Point.read(arguments);
       
  8434 			this.moveTo(last ? point.add(last._point) : point);
       
  8435 		},
       
  8436 
       
  8437 		closePath: function(join) {
       
  8438 			getCurrentPath(this, true).closePath(join);
       
  8439 		}
       
  8440 	};
       
  8441 
       
  8442 	Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', 'arcTo',
       
  8443 			'lineBy', 'cubicCurveBy', 'quadraticCurveBy', 'curveBy', 'arcBy'],
       
  8444 			function(key) {
       
  8445 				fields[key] = function() {
       
  8446 					var path = getCurrentPath(this, true);
       
  8447 					path[key].apply(path, arguments);
       
  8448 				};
       
  8449 			}
       
  8450 	);
       
  8451 
       
  8452 	return fields;
       
  8453 });
       
  8454 
       
  8455 PathItem.inject(new function() {
       
  8456 	var operators = {
       
  8457 		unite: function(w) {
       
  8458 			return w === 1 || w === 0;
       
  8459 		},
       
  8460 
       
  8461 		intersect: function(w) {
       
  8462 			return w === 2;
       
  8463 		},
       
  8464 
       
  8465 		subtract: function(w) {
       
  8466 			return w === 1;
       
  8467 		},
       
  8468 
       
  8469 		exclude: function(w) {
       
  8470 			return w === 1;
       
  8471 		}
       
  8472 	};
       
  8473 
       
  8474 	function computeBoolean(path1, path2, operation) {
       
  8475 		var operator = operators[operation];
       
  8476 		function preparePath(path) {
       
  8477 			return path.clone(false).reduce().reorient().transform(null, true,
       
  8478 					true);
       
  8479 		}
       
  8480 
       
  8481 		var _path1 = preparePath(path1),
       
  8482 			_path2 = path2 && path1 !== path2 && preparePath(path2);
       
  8483 		if (_path2 && /^(subtract|exclude)$/.test(operation)
       
  8484 				^ (_path2.isClockwise() !== _path1.isClockwise()))
       
  8485 			_path2.reverse();
       
  8486 		splitPath(_path1.getIntersections(_path2, null, true));
       
  8487 
       
  8488 		var chain = [],
       
  8489 			segments = [],
       
  8490 			monoCurves = [],
       
  8491 			tolerance = 0.000001;
       
  8492 
       
  8493 		function collect(paths) {
       
  8494 			for (var i = 0, l = paths.length; i < l; i++) {
       
  8495 				var path = paths[i];
       
  8496 				segments.push.apply(segments, path._segments);
       
  8497 				monoCurves.push.apply(monoCurves, path._getMonoCurves());
       
  8498 			}
       
  8499 		}
       
  8500 
       
  8501 		collect(_path1._children || [_path1]);
       
  8502 		if (_path2)
       
  8503 			collect(_path2._children || [_path2]);
       
  8504 		segments.sort(function(a, b) {
       
  8505 			var _a = a._intersection,
       
  8506 				_b = b._intersection;
       
  8507 			return !_a && !_b || _a && _b ? 0 : _a ? -1 : 1;
       
  8508 		});
       
  8509 		for (var i = 0, l = segments.length; i < l; i++) {
       
  8510 			var segment = segments[i];
       
  8511 			if (segment._winding != null)
       
  8512 				continue;
       
  8513 			chain.length = 0;
       
  8514 			var startSeg = segment,
       
  8515 				totalLength = 0,
       
  8516 				windingSum = 0;
       
  8517 			do {
       
  8518 				var length = segment.getCurve().getLength();
       
  8519 				chain.push({ segment: segment, length: length });
       
  8520 				totalLength += length;
       
  8521 				segment = segment.getNext();
       
  8522 			} while (segment && !segment._intersection && segment !== startSeg);
       
  8523 			for (var j = 0; j < 3; j++) {
       
  8524 				var length = totalLength * (j + 1) / 4;
       
  8525 				for (k = 0, m = chain.length; k < m; k++) {
       
  8526 					var node = chain[k],
       
  8527 						curveLength = node.length;
       
  8528 					if (length <= curveLength) {
       
  8529 						if (length <= tolerance
       
  8530 								|| curveLength - length <= tolerance)
       
  8531 							length = curveLength / 2;
       
  8532 						var curve = node.segment.getCurve(),
       
  8533 							pt = curve.getPointAt(length),
       
  8534 							hor = curve.isLinear() && Math.abs(curve
       
  8535 									.getTangentAt(0.5, true).y) <= tolerance,
       
  8536 							path = curve._path;
       
  8537 						if (path._parent instanceof CompoundPath)
       
  8538 							path = path._parent;
       
  8539 						windingSum += operation === 'subtract' && _path2
       
  8540 							&& (path === _path1 && _path2._getWinding(pt, hor)
       
  8541 							|| path === _path2 && !_path1._getWinding(pt, hor))
       
  8542 							? 0
       
  8543 							: getWinding(pt, monoCurves, hor);
       
  8544 						break;
       
  8545 					}
       
  8546 					length -= curveLength;
       
  8547 				}
       
  8548 			}
       
  8549 			var winding = Math.round(windingSum / 3);
       
  8550 			for (var j = chain.length - 1; j >= 0; j--)
       
  8551 				chain[j].segment._winding = winding;
       
  8552 		}
       
  8553 		var result = new CompoundPath(Item.NO_INSERT);
       
  8554 		result.insertAbove(path1);
       
  8555 		result.addChildren(tracePaths(segments, operator), true);
       
  8556 		result = result.reduce();
       
  8557 		result.setStyle(path1._style);
       
  8558 		return result;
       
  8559 	}
       
  8560 
       
  8561 	function splitPath(intersections) {
       
  8562 		var tMin = 0.000001,
       
  8563 			tMax = 1 - tMin,
       
  8564 			linearHandles;
       
  8565 
       
  8566 		function resetLinear() {
       
  8567 			for (var i = 0, l = linearHandles.length; i < l; i++)
       
  8568 				linearHandles[i].set(0, 0);
       
  8569 		}
       
  8570 
       
  8571 		for (var i = intersections.length - 1, curve, prev; i >= 0; i--) {
       
  8572 			var loc = intersections[i],
       
  8573 				t = loc._parameter;
       
  8574 			if (prev && prev._curve === loc._curve && prev._parameter > 0) {
       
  8575 				t /= prev._parameter;
       
  8576 			} else {
       
  8577 				curve = loc._curve;
       
  8578 				if (linearHandles)
       
  8579 					resetLinear();
       
  8580 				linearHandles = curve.isLinear() ? [
       
  8581 						curve._segment1._handleOut,
       
  8582 						curve._segment2._handleIn
       
  8583 					] : null;
       
  8584 			}
       
  8585 			var newCurve,
       
  8586 				segment;
       
  8587 			if (newCurve = curve.divide(t, true, true)) {
       
  8588 				segment = newCurve._segment1;
       
  8589 				curve = newCurve.getPrevious();
       
  8590 				if (linearHandles)
       
  8591 					linearHandles.push(segment._handleOut, segment._handleIn);
       
  8592 			} else {
       
  8593 				segment = t < tMin
       
  8594 					? curve._segment1
       
  8595 					: t > tMax
       
  8596 						? curve._segment2
       
  8597 						: curve.getPartLength(0, t) < curve.getPartLength(t, 1)
       
  8598 							? curve._segment1
       
  8599 							: curve._segment2;
       
  8600 			}
       
  8601 			segment._intersection = loc.getIntersection();
       
  8602 			loc._segment = segment;
       
  8603 			prev = loc;
       
  8604 		}
       
  8605 		if (linearHandles)
       
  8606 			resetLinear();
       
  8607 	}
       
  8608 
       
  8609 	function getWinding(point, curves, horizontal, testContains) {
       
  8610 		var tolerance = 0.000001,
       
  8611 			tMin = tolerance,
       
  8612 			tMax = 1 - tMin,
       
  8613 			px = point.x,
       
  8614 			py = point.y,
       
  8615 			windLeft = 0,
       
  8616 			windRight = 0,
       
  8617 			roots = [],
       
  8618 			abs = Math.abs;
       
  8619 		if (horizontal) {
       
  8620 			var yTop = -Infinity,
       
  8621 				yBottom = Infinity,
       
  8622 				yBefore = py - tolerance,
       
  8623 				yAfter = py + tolerance;
       
  8624 			for (var i = 0, l = curves.length; i < l; i++) {
       
  8625 				var values = curves[i].values;
       
  8626 				if (Curve.solveCubic(values, 0, px, roots, 0, 1) > 0) {
       
  8627 					for (var j = roots.length - 1; j >= 0; j--) {
       
  8628 						var y = Curve.evaluate(values, roots[j], 0).y;
       
  8629 						if (y < yBefore && y > yTop) {
       
  8630 							yTop = y;
       
  8631 						} else if (y > yAfter && y < yBottom) {
       
  8632 							yBottom = y;
       
  8633 						}
       
  8634 					}
       
  8635 				}
       
  8636 			}
       
  8637 			yTop = (yTop + py) / 2;
       
  8638 			yBottom = (yBottom + py) / 2;
       
  8639 			if (yTop > -Infinity)
       
  8640 				windLeft = getWinding(new Point(px, yTop), curves);
       
  8641 			if (yBottom < Infinity)
       
  8642 				windRight = getWinding(new Point(px, yBottom), curves);
       
  8643 		} else {
       
  8644 			var xBefore = px - tolerance,
       
  8645 				xAfter = px + tolerance;
       
  8646 			for (var i = 0, l = curves.length; i < l; i++) {
       
  8647 				var curve = curves[i],
       
  8648 					values = curve.values,
       
  8649 					winding = curve.winding,
       
  8650 					prevT,
       
  8651 					prevX;
       
  8652 				if (winding && (winding === 1
       
  8653 						&& py >= values[1] && py <= values[7]
       
  8654 						|| py >= values[7] && py <= values[1])
       
  8655 					&& Curve.solveCubic(values, 1, py, roots, 0, 1) === 1) {
       
  8656 					var t = roots[0],
       
  8657 						x = Curve.evaluate(values, t, 0).x,
       
  8658 						slope = Curve.evaluate(values, t, 1).y;
       
  8659 					if (!(t > tMax
       
  8660 							&& (i === l - 1 || curve.next !== curves[i + 1])
       
  8661 							&& abs(Curve.evaluate(curve.next.values, 0, 0).x -x)
       
  8662 								<= tolerance
       
  8663 						|| i > 0 && curve.previous === curves[i - 1]
       
  8664 							&& abs(prevX - x) < tolerance
       
  8665 							&& prevT > tMax && t < tMin)) {
       
  8666 						if (Numerical.isZero(slope) && !Curve.isLinear(values)
       
  8667 								|| t < tMin && slope * Curve.evaluate(
       
  8668 									curve.previous.values, 1, 1).y < 0
       
  8669 								|| t > tMax && slope * Curve.evaluate(
       
  8670 									curve.next.values, 0, 1).y < 0) {
       
  8671 							if (testContains && x >= xBefore && x <= xAfter) {
       
  8672 								++windLeft;
       
  8673 								++windRight;
       
  8674 							}
       
  8675 						} else if (x <= xBefore) {
       
  8676 							windLeft += winding;
       
  8677 						} else if (x >= xAfter) {
       
  8678 							windRight += winding;
       
  8679 						}
       
  8680 					}
       
  8681 					prevT = t;
       
  8682 					prevX = x;
       
  8683 				}
       
  8684 			}
       
  8685 		}
       
  8686 		return Math.max(abs(windLeft), abs(windRight));
       
  8687 	}
       
  8688 
       
  8689 	function tracePaths(segments, operator, selfOp) {
       
  8690 		var paths = [],
       
  8691 			tMin = 0.000001,
       
  8692 			tMax = 1 - tMin;
       
  8693 		for (var i = 0, seg, startSeg, l = segments.length; i < l; i++) {
       
  8694 			seg = startSeg = segments[i];
       
  8695 			if (seg._visited || !operator(seg._winding))
       
  8696 				continue;
       
  8697 			var path = new Path(Item.NO_INSERT),
       
  8698 				inter = seg._intersection,
       
  8699 				startInterSeg = inter && inter._segment,
       
  8700 				added = false,
       
  8701 				dir = 1;
       
  8702 			do {
       
  8703 				var handleIn = dir > 0 ? seg._handleIn : seg._handleOut,
       
  8704 					handleOut = dir > 0 ? seg._handleOut : seg._handleIn,
       
  8705 					interSeg;
       
  8706 				if (added && (!operator(seg._winding) || selfOp)
       
  8707 						&& (inter = seg._intersection)
       
  8708 						&& (interSeg = inter._segment)
       
  8709 						&& interSeg !== startSeg) {
       
  8710 					if (selfOp) {
       
  8711 						seg._visited = interSeg._visited;
       
  8712 						seg = interSeg;
       
  8713 						dir = 1;
       
  8714 					} else {
       
  8715 						var c1 = seg.getCurve();
       
  8716 						if (dir > 0)
       
  8717 							c1 = c1.getPrevious();
       
  8718 						var t1 = c1.getTangentAt(dir < 1 ? tMin : tMax, true),
       
  8719 							c4 = interSeg.getCurve(),
       
  8720 							c3 = c4.getPrevious(),
       
  8721 							t3 = c3.getTangentAt(tMax, true),
       
  8722 							t4 = c4.getTangentAt(tMin, true),
       
  8723 							w3 = t1.cross(t3),
       
  8724 							w4 = t1.cross(t4);
       
  8725 						if (w3 * w4 !== 0) {
       
  8726 							var curve = w3 < w4 ? c3 : c4,
       
  8727 								nextCurve = operator(curve._segment1._winding)
       
  8728 									? curve
       
  8729 									: w3 < w4 ? c4 : c3,
       
  8730 								nextSeg = nextCurve._segment1;
       
  8731 							dir = nextCurve === c3 ? -1 : 1;
       
  8732 							if (nextSeg._visited && seg._path !== nextSeg._path
       
  8733 										|| !operator(nextSeg._winding)) {
       
  8734 								dir = 1;
       
  8735 							} else {
       
  8736 								seg._visited = interSeg._visited;
       
  8737 								seg = interSeg;
       
  8738 								if (nextSeg._visited)
       
  8739 									dir = 1;
       
  8740 							}
       
  8741 						} else {
       
  8742 							dir = 1;
       
  8743 						}
       
  8744 					}
       
  8745 					handleOut = dir > 0 ? seg._handleOut : seg._handleIn;
       
  8746 				}
       
  8747 				path.add(new Segment(seg._point, added && handleIn, handleOut));
       
  8748 				added = true;
       
  8749 				seg._visited = true;
       
  8750 				seg = dir > 0 ? seg.getNext() : seg. getPrevious();
       
  8751 			} while (seg && !seg._visited
       
  8752 					&& seg !== startSeg && seg !== startInterSeg
       
  8753 					&& (seg._intersection || operator(seg._winding)));
       
  8754 			if (seg && (seg === startSeg || seg === startInterSeg)) {
       
  8755 				path.firstSegment.setHandleIn((seg === startInterSeg
       
  8756 						? startInterSeg : seg)._handleIn);
       
  8757 				path.setClosed(true);
       
  8758 			} else {
       
  8759 				path.lastSegment._handleOut.set(0, 0);
       
  8760 			}
       
  8761 			if (path._segments.length >
       
  8762 					(path._closed ? path.isPolygon() ? 2 : 0 : 1))
       
  8763 				paths.push(path);
       
  8764 		}
       
  8765 		return paths;
       
  8766 	}
       
  8767 
       
  8768 	return {
       
  8769 		_getWinding: function(point, horizontal, testContains) {
       
  8770 			return getWinding(point, this._getMonoCurves(),
       
  8771 					horizontal, testContains);
       
  8772 		},
       
  8773 
       
  8774 		unite: function(path) {
       
  8775 			return computeBoolean(this, path, 'unite');
       
  8776 		},
       
  8777 
       
  8778 		intersect: function(path) {
       
  8779 			return computeBoolean(this, path, 'intersect');
       
  8780 		},
       
  8781 
       
  8782 		subtract: function(path) {
       
  8783 			return computeBoolean(this, path, 'subtract');
       
  8784 		},
       
  8785 
       
  8786 		exclude: function(path) {
       
  8787 			return computeBoolean(this, path, 'exclude');
       
  8788 		},
       
  8789 
       
  8790 		divide: function(path) {
       
  8791 			return new Group([this.subtract(path), this.intersect(path)]);
       
  8792 		}
       
  8793 	};
       
  8794 });
       
  8795 
       
  8796 Path.inject({
       
  8797 	_getMonoCurves: function() {
       
  8798 		var monoCurves = this._monoCurves,
       
  8799 			prevCurve;
       
  8800 
       
  8801 		function insertCurve(v) {
       
  8802 			var y0 = v[1],
       
  8803 				y1 = v[7],
       
  8804 				curve = {
       
  8805 					values: v,
       
  8806 					winding: y0 === y1
       
  8807 						? 0
       
  8808 						: y0 > y1
       
  8809 							? -1
       
  8810 							: 1,
       
  8811 					previous: prevCurve,
       
  8812 					next: null
       
  8813 				};
       
  8814 			if (prevCurve)
       
  8815 				prevCurve.next = curve;
       
  8816 			monoCurves.push(curve);
       
  8817 			prevCurve = curve;
       
  8818 		}
       
  8819 
       
  8820 		function handleCurve(v) {
       
  8821 			if (Curve.getLength(v) === 0)
       
  8822 				return;
       
  8823 			var y0 = v[1],
       
  8824 				y1 = v[3],
       
  8825 				y2 = v[5],
       
  8826 				y3 = v[7];
       
  8827 			if (Curve.isLinear(v)) {
       
  8828 				insertCurve(v);
       
  8829 			} else {
       
  8830 				var a = 3 * (y1 - y2) - y0 + y3,
       
  8831 					b = 2 * (y0 + y2) - 4 * y1,
       
  8832 					c = y1 - y0,
       
  8833 					tolerance = 0.000001,
       
  8834 					roots = [];
       
  8835 				var count = Numerical.solveQuadratic(a, b, c, roots, tolerance,
       
  8836 						1 - tolerance);
       
  8837 				if (count === 0) {
       
  8838 					insertCurve(v);
       
  8839 				} else {
       
  8840 					roots.sort();
       
  8841 					var t = roots[0],
       
  8842 						parts = Curve.subdivide(v, t);
       
  8843 					insertCurve(parts[0]);
       
  8844 					if (count > 1) {
       
  8845 						t = (roots[1] - t) / (1 - t);
       
  8846 						parts = Curve.subdivide(parts[1], t);
       
  8847 						insertCurve(parts[0]);
       
  8848 					}
       
  8849 					insertCurve(parts[1]);
       
  8850 				}
       
  8851 			}
       
  8852 		}
       
  8853 
       
  8854 		if (!monoCurves) {
       
  8855 			monoCurves = this._monoCurves = [];
       
  8856 			var curves = this.getCurves(),
       
  8857 				segments = this._segments;
       
  8858 			for (var i = 0, l = curves.length; i < l; i++)
       
  8859 				handleCurve(curves[i].getValues());
       
  8860 			if (!this._closed && segments.length > 1) {
       
  8861 				var p1 = segments[segments.length - 1]._point,
       
  8862 					p2 = segments[0]._point,
       
  8863 					p1x = p1._x, p1y = p1._y,
       
  8864 					p2x = p2._x, p2y = p2._y;
       
  8865 				handleCurve([p1x, p1y, p1x, p1y, p2x, p2y, p2x, p2y]);
       
  8866 			}
       
  8867 			if (monoCurves.length > 0) {
       
  8868 				var first = monoCurves[0],
       
  8869 					last = monoCurves[monoCurves.length - 1];
       
  8870 				first.previous = last;
       
  8871 				last.next = first;
       
  8872 			}
       
  8873 		}
       
  8874 		return monoCurves;
       
  8875 	},
       
  8876 
       
  8877 	getInteriorPoint: function() {
       
  8878 		var bounds = this.getBounds(),
       
  8879 			point = bounds.getCenter(true);
       
  8880 		if (!this.contains(point)) {
       
  8881 			var curves = this._getMonoCurves(),
       
  8882 				roots = [],
       
  8883 				y = point.y,
       
  8884 				xIntercepts = [];
       
  8885 			for (var i = 0, l = curves.length; i < l; i++) {
       
  8886 				var values = curves[i].values;
       
  8887 				if ((curves[i].winding === 1
       
  8888 						&& y >= values[1] && y <= values[7]
       
  8889 						|| y >= values[7] && y <= values[1])
       
  8890 						&& Curve.solveCubic(values, 1, y, roots, 0, 1) > 0) {
       
  8891 					for (var j = roots.length - 1; j >= 0; j--)
       
  8892 						xIntercepts.push(Curve.evaluate(values, roots[j], 0).x);
       
  8893 				}
       
  8894 				if (xIntercepts.length > 1)
       
  8895 					break;
       
  8896 			}
       
  8897 			point.x = (xIntercepts[0] + xIntercepts[1]) / 2;
       
  8898 		}
       
  8899 		return point;
       
  8900 	},
       
  8901 
       
  8902 	reorient: function() {
       
  8903 		this.setClockwise(true);
       
  8904 		return this;
       
  8905 	}
       
  8906 });
       
  8907 
       
  8908 CompoundPath.inject({
       
  8909 	_getMonoCurves: function() {
       
  8910 		var children = this._children,
       
  8911 			monoCurves = [];
       
  8912 		for (var i = 0, l = children.length; i < l; i++)
       
  8913 			monoCurves.push.apply(monoCurves, children[i]._getMonoCurves());
       
  8914 		return monoCurves;
       
  8915 	},
       
  8916 
       
  8917 	reorient: function() {
       
  8918 		var children = this.removeChildren().sort(function(a, b) {
       
  8919 			return b.getBounds().getArea() - a.getBounds().getArea();
       
  8920 		});
       
  8921 		if (children.length > 0) {
       
  8922 			this.addChildren(children);
       
  8923 			var clockwise = children[0].isClockwise();
       
  8924 			for (var i = 1, l = children.length; i < l; i++) {
       
  8925 				var point = children[i].getInteriorPoint(),
       
  8926 					counters = 0;
       
  8927 				for (var j = i - 1; j >= 0; j--) {
       
  8928 					if (children[j].contains(point))
       
  8929 						counters++;
       
  8930 				}
       
  8931 				children[i].setClockwise(counters % 2 === 0 && clockwise);
       
  8932 			}
       
  8933 		}
       
  8934 		return this;
       
  8935 	}
       
  8936 });
       
  8937 
       
  8938 var PathIterator = Base.extend({
       
  8939 	_class: 'PathIterator',
       
  8940 
       
  8941 	initialize: function(path, maxRecursion, tolerance, matrix) {
       
  8942 		var curves = [],
       
  8943 			parts = [],
       
  8944 			length = 0,
       
  8945 			minDifference = 1 / (maxRecursion || 32),
       
  8946 			segments = path._segments,
       
  8947 			segment1 = segments[0],
       
  8948 			segment2;
       
  8949 
       
  8950 		function addCurve(segment1, segment2) {
       
  8951 			var curve = Curve.getValues(segment1, segment2, matrix);
       
  8952 			curves.push(curve);
       
  8953 			computeParts(curve, segment1._index, 0, 1);
       
  8954 		}
       
  8955 
       
  8956 		function computeParts(curve, index, minT, maxT) {
       
  8957 			if ((maxT - minT) > minDifference
       
  8958 					&& !Curve.isFlatEnough(curve, tolerance || 0.25)) {
       
  8959 				var split = Curve.subdivide(curve),
       
  8960 					halfT = (minT + maxT) / 2;
       
  8961 				computeParts(split[0], index, minT, halfT);
       
  8962 				computeParts(split[1], index, halfT, maxT);
       
  8963 			} else {
       
  8964 				var x = curve[6] - curve[0],
       
  8965 					y = curve[7] - curve[1],
       
  8966 					dist = Math.sqrt(x * x + y * y);
       
  8967 				if (dist > 0.000001) {
       
  8968 					length += dist;
       
  8969 					parts.push({
       
  8970 						offset: length,
       
  8971 						value: maxT,
       
  8972 						index: index
       
  8973 					});
       
  8974 				}
       
  8975 			}
       
  8976 		}
       
  8977 
       
  8978 		for (var i = 1, l = segments.length; i < l; i++) {
       
  8979 			segment2 = segments[i];
       
  8980 			addCurve(segment1, segment2);
       
  8981 			segment1 = segment2;
       
  8982 		}
       
  8983 		if (path._closed)
       
  8984 			addCurve(segment2, segments[0]);
       
  8985 
       
  8986 		this.curves = curves;
       
  8987 		this.parts = parts;
       
  8988 		this.length = length;
       
  8989 		this.index = 0;
       
  8990 	},
       
  8991 
       
  8992 	getParameterAt: function(offset) {
       
  8993 		var i, j = this.index;
       
  8994 		for (;;) {
       
  8995 			i = j;
       
  8996 			if (j == 0 || this.parts[--j].offset < offset)
       
  8997 				break;
       
  8998 		}
       
  8999 		for (var l = this.parts.length; i < l; i++) {
       
  9000 			var part = this.parts[i];
       
  9001 			if (part.offset >= offset) {
       
  9002 				this.index = i;
       
  9003 				var prev = this.parts[i - 1];
       
  9004 				var prevVal = prev && prev.index == part.index ? prev.value : 0,
       
  9005 					prevLen = prev ? prev.offset : 0;
       
  9006 				return {
       
  9007 					value: prevVal + (part.value - prevVal)
       
  9008 						* (offset - prevLen) / (part.offset - prevLen),
       
  9009 					index: part.index
       
  9010 				};
       
  9011 			}
       
  9012 		}
       
  9013 		var part = this.parts[this.parts.length - 1];
       
  9014 		return {
       
  9015 			value: 1,
       
  9016 			index: part.index
       
  9017 		};
       
  9018 	},
       
  9019 
       
  9020 	evaluate: function(offset, type) {
       
  9021 		var param = this.getParameterAt(offset);
       
  9022 		return Curve.evaluate(this.curves[param.index], param.value, type);
       
  9023 	},
       
  9024 
       
  9025 	drawPart: function(ctx, from, to) {
       
  9026 		from = this.getParameterAt(from);
       
  9027 		to = this.getParameterAt(to);
       
  9028 		for (var i = from.index; i <= to.index; i++) {
       
  9029 			var curve = Curve.getPart(this.curves[i],
       
  9030 					i == from.index ? from.value : 0,
       
  9031 					i == to.index ? to.value : 1);
       
  9032 			if (i == from.index)
       
  9033 				ctx.moveTo(curve[0], curve[1]);
       
  9034 			ctx.bezierCurveTo.apply(ctx, curve.slice(2));
       
  9035 		}
       
  9036 	}
       
  9037 }, Base.each(['getPoint', 'getTangent', 'getNormal', 'getCurvature'],
       
  9038 	function(name, index) {
       
  9039 		this[name + 'At'] = function(offset) {
       
  9040 			return this.evaluate(offset, index);
       
  9041 		};
       
  9042 	}, {})
       
  9043 );
       
  9044 
       
  9045 var PathFitter = Base.extend({
       
  9046 	initialize: function(path, error) {
       
  9047 		var points = this.points = [],
       
  9048 			segments = path._segments,
       
  9049 			prev;
       
  9050 		for (var i = 0, l = segments.length; i < l; i++) {
       
  9051 			var point = segments[i].point.clone();
       
  9052 			if (!prev || !prev.equals(point)) {
       
  9053 				points.push(point);
       
  9054 				prev = point;
       
  9055 			}
       
  9056 		}
       
  9057 
       
  9058 		if (path._closed) {
       
  9059 			this.closed = true;
       
  9060 			points.unshift(points[points.length - 1]);
       
  9061 			points.push(points[1]);
       
  9062 		}
       
  9063 
       
  9064 		this.error = error;
       
  9065 	},
       
  9066 
       
  9067 	fit: function() {
       
  9068 		var points = this.points,
       
  9069 			length = points.length,
       
  9070 			segments = this.segments = length > 0
       
  9071 					? [new Segment(points[0])] : [];
       
  9072 		if (length > 1)
       
  9073 			this.fitCubic(0, length - 1,
       
  9074 				points[1].subtract(points[0]).normalize(),
       
  9075 				points[length - 2].subtract(points[length - 1]).normalize());
       
  9076 
       
  9077 		if (this.closed) {
       
  9078 			segments.shift();
       
  9079 			segments.pop();
       
  9080 		}
       
  9081 
       
  9082 		return segments;
       
  9083 	},
       
  9084 
       
  9085 	fitCubic: function(first, last, tan1, tan2) {
       
  9086 		if (last - first == 1) {
       
  9087 			var pt1 = this.points[first],
       
  9088 				pt2 = this.points[last],
       
  9089 				dist = pt1.getDistance(pt2) / 3;
       
  9090 			this.addCurve([pt1, pt1.add(tan1.normalize(dist)),
       
  9091 					pt2.add(tan2.normalize(dist)), pt2]);
       
  9092 			return;
       
  9093 		}
       
  9094 		var uPrime = this.chordLengthParameterize(first, last),
       
  9095 			maxError = Math.max(this.error, this.error * this.error),
       
  9096 			split;
       
  9097 		for (var i = 0; i <= 4; i++) {
       
  9098 			var curve = this.generateBezier(first, last, uPrime, tan1, tan2);
       
  9099 			var max = this.findMaxError(first, last, curve, uPrime);
       
  9100 			if (max.error < this.error) {
       
  9101 				this.addCurve(curve);
       
  9102 				return;
       
  9103 			}
       
  9104 			split = max.index;
       
  9105 			if (max.error >= maxError)
       
  9106 				break;
       
  9107 			this.reparameterize(first, last, uPrime, curve);
       
  9108 			maxError = max.error;
       
  9109 		}
       
  9110 		var V1 = this.points[split - 1].subtract(this.points[split]),
       
  9111 			V2 = this.points[split].subtract(this.points[split + 1]),
       
  9112 			tanCenter = V1.add(V2).divide(2).normalize();
       
  9113 		this.fitCubic(first, split, tan1, tanCenter);
       
  9114 		this.fitCubic(split, last, tanCenter.negate(), tan2);
       
  9115 	},
       
  9116 
       
  9117 	addCurve: function(curve) {
       
  9118 		var prev = this.segments[this.segments.length - 1];
       
  9119 		prev.setHandleOut(curve[1].subtract(curve[0]));
       
  9120 		this.segments.push(
       
  9121 				new Segment(curve[3], curve[2].subtract(curve[3])));
       
  9122 	},
       
  9123 
       
  9124 	generateBezier: function(first, last, uPrime, tan1, tan2) {
       
  9125 		var epsilon = 1e-12,
       
  9126 			pt1 = this.points[first],
       
  9127 			pt2 = this.points[last],
       
  9128 			C = [[0, 0], [0, 0]],
       
  9129 			X = [0, 0];
       
  9130 
       
  9131 		for (var i = 0, l = last - first + 1; i < l; i++) {
       
  9132 			var u = uPrime[i],
       
  9133 				t = 1 - u,
       
  9134 				b = 3 * u * t,
       
  9135 				b0 = t * t * t,
       
  9136 				b1 = b * t,
       
  9137 				b2 = b * u,
       
  9138 				b3 = u * u * u,
       
  9139 				a1 = tan1.normalize(b1),
       
  9140 				a2 = tan2.normalize(b2),
       
  9141 				tmp = this.points[first + i]
       
  9142 					.subtract(pt1.multiply(b0 + b1))
       
  9143 					.subtract(pt2.multiply(b2 + b3));
       
  9144 			C[0][0] += a1.dot(a1);
       
  9145 			C[0][1] += a1.dot(a2);
       
  9146 			C[1][0] = C[0][1];
       
  9147 			C[1][1] += a2.dot(a2);
       
  9148 			X[0] += a1.dot(tmp);
       
  9149 			X[1] += a2.dot(tmp);
       
  9150 		}
       
  9151 
       
  9152 		var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1],
       
  9153 			alpha1, alpha2;
       
  9154 		if (Math.abs(detC0C1) > epsilon) {
       
  9155 			var detC0X	= C[0][0] * X[1]	- C[1][0] * X[0],
       
  9156 				detXC1	= X[0]	  * C[1][1] - X[1]	  * C[0][1];
       
  9157 			alpha1 = detXC1 / detC0C1;
       
  9158 			alpha2 = detC0X / detC0C1;
       
  9159 		} else {
       
  9160 			var c0 = C[0][0] + C[0][1],
       
  9161 				c1 = C[1][0] + C[1][1];
       
  9162 			if (Math.abs(c0) > epsilon) {
       
  9163 				alpha1 = alpha2 = X[0] / c0;
       
  9164 			} else if (Math.abs(c1) > epsilon) {
       
  9165 				alpha1 = alpha2 = X[1] / c1;
       
  9166 			} else {
       
  9167 				alpha1 = alpha2 = 0;
       
  9168 			}
       
  9169 		}
       
  9170 
       
  9171 		var segLength = pt2.getDistance(pt1);
       
  9172 		epsilon *= segLength;
       
  9173 		if (alpha1 < epsilon || alpha2 < epsilon) {
       
  9174 			alpha1 = alpha2 = segLength / 3;
       
  9175 		}
       
  9176 
       
  9177 		return [pt1, pt1.add(tan1.normalize(alpha1)),
       
  9178 				pt2.add(tan2.normalize(alpha2)), pt2];
       
  9179 	},
       
  9180 
       
  9181 	reparameterize: function(first, last, u, curve) {
       
  9182 		for (var i = first; i <= last; i++) {
       
  9183 			u[i - first] = this.findRoot(curve, this.points[i], u[i - first]);
       
  9184 		}
       
  9185 	},
       
  9186 
       
  9187 	findRoot: function(curve, point, u) {
       
  9188 		var curve1 = [],
       
  9189 			curve2 = [];
       
  9190 		for (var i = 0; i <= 2; i++) {
       
  9191 			curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3);
       
  9192 		}
       
  9193 		for (var i = 0; i <= 1; i++) {
       
  9194 			curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2);
       
  9195 		}
       
  9196 		var pt = this.evaluate(3, curve, u),
       
  9197 			pt1 = this.evaluate(2, curve1, u),
       
  9198 			pt2 = this.evaluate(1, curve2, u),
       
  9199 			diff = pt.subtract(point),
       
  9200 			df = pt1.dot(pt1) + diff.dot(pt2);
       
  9201 		if (Math.abs(df) < 0.000001)
       
  9202 			return u;
       
  9203 		return u - diff.dot(pt1) / df;
       
  9204 	},
       
  9205 
       
  9206 	evaluate: function(degree, curve, t) {
       
  9207 		var tmp = curve.slice();
       
  9208 		for (var i = 1; i <= degree; i++) {
       
  9209 			for (var j = 0; j <= degree - i; j++) {
       
  9210 				tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t));
       
  9211 			}
       
  9212 		}
       
  9213 		return tmp[0];
       
  9214 	},
       
  9215 
       
  9216 	chordLengthParameterize: function(first, last) {
       
  9217 		var u = [0];
       
  9218 		for (var i = first + 1; i <= last; i++) {
       
  9219 			u[i - first] = u[i - first - 1]
       
  9220 					+ this.points[i].getDistance(this.points[i - 1]);
       
  9221 		}
       
  9222 		for (var i = 1, m = last - first; i <= m; i++) {
       
  9223 			u[i] /= u[m];
       
  9224 		}
       
  9225 		return u;
       
  9226 	},
       
  9227 
       
  9228 	findMaxError: function(first, last, curve, u) {
       
  9229 		var index = Math.floor((last - first + 1) / 2),
       
  9230 			maxDist = 0;
       
  9231 		for (var i = first + 1; i < last; i++) {
       
  9232 			var P = this.evaluate(3, curve, u[i - first]);
       
  9233 			var v = P.subtract(this.points[i]);
       
  9234 			var dist = v.x * v.x + v.y * v.y;
       
  9235 			if (dist >= maxDist) {
       
  9236 				maxDist = dist;
       
  9237 				index = i;
       
  9238 			}
       
  9239 		}
       
  9240 		return {
       
  9241 			error: maxDist,
       
  9242 			index: index
       
  9243 		};
       
  9244 	}
       
  9245 });
       
  9246 
       
  9247 var TextItem = Item.extend({
       
  9248 	_class: 'TextItem',
       
  9249 	_boundsSelected: true,
       
  9250 	_applyMatrix: false,
       
  9251 	_canApplyMatrix: false,
       
  9252 	_serializeFields: {
       
  9253 		content: null
       
  9254 	},
       
  9255 	_boundsGetter: 'getBounds',
       
  9256 
       
  9257 	initialize: function TextItem(arg) {
       
  9258 		this._content = '';
       
  9259 		this._lines = [];
       
  9260 		var hasProps = arg && Base.isPlainObject(arg)
       
  9261 				&& arg.x === undefined && arg.y === undefined;
       
  9262 		this._initialize(hasProps && arg, !hasProps && Point.read(arguments));
       
  9263 	},
       
  9264 
       
  9265 	_equals: function(item) {
       
  9266 		return this._content === item._content;
       
  9267 	},
       
  9268 
       
  9269 	_clone: function _clone(copy, insert) {
       
  9270 		copy.setContent(this._content);
       
  9271 		return _clone.base.call(this, copy, insert);
       
  9272 	},
       
  9273 
       
  9274 	getContent: function() {
       
  9275 		return this._content;
       
  9276 	},
       
  9277 
       
  9278 	setContent: function(content) {
       
  9279 		this._content = '' + content;
       
  9280 		this._lines = this._content.split(/\r\n|\n|\r/mg);
       
  9281 		this._changed(265);
       
  9282 	},
       
  9283 
       
  9284 	isEmpty: function() {
       
  9285 		return !this._content;
       
  9286 	},
       
  9287 
       
  9288 	getCharacterStyle: '#getStyle',
       
  9289 	setCharacterStyle: '#setStyle',
       
  9290 
       
  9291 	getParagraphStyle: '#getStyle',
       
  9292 	setParagraphStyle: '#setStyle'
       
  9293 });
       
  9294 
       
  9295 var PointText = TextItem.extend({
       
  9296 	_class: 'PointText',
       
  9297 
       
  9298 	initialize: function PointText() {
       
  9299 		TextItem.apply(this, arguments);
       
  9300 	},
       
  9301 
       
  9302 	clone: function(insert) {
       
  9303 		return this._clone(new PointText(Item.NO_INSERT), insert);
       
  9304 	},
       
  9305 
       
  9306 	getPoint: function() {
       
  9307 		var point = this._matrix.getTranslation();
       
  9308 		return new LinkedPoint(point.x, point.y, this, 'setPoint');
       
  9309 	},
       
  9310 
       
  9311 	setPoint: function() {
       
  9312 		var point = Point.read(arguments);
       
  9313 		this.translate(point.subtract(this._matrix.getTranslation()));
       
  9314 	},
       
  9315 
       
  9316 	_draw: function(ctx) {
       
  9317 		if (!this._content)
       
  9318 			return;
       
  9319 		this._setStyles(ctx);
       
  9320 		var style = this._style,
       
  9321 			lines = this._lines,
       
  9322 			leading = style.getLeading(),
       
  9323 			shadowColor = ctx.shadowColor;
       
  9324 		ctx.font = style.getFontStyle();
       
  9325 		ctx.textAlign = style.getJustification();
       
  9326 		for (var i = 0, l = lines.length; i < l; i++) {
       
  9327 			ctx.shadowColor = shadowColor;
       
  9328 			var line = lines[i];
       
  9329 			if (style.hasFill()) {
       
  9330 				ctx.fillText(line, 0, 0);
       
  9331 				ctx.shadowColor = 'rgba(0,0,0,0)';
       
  9332 			}
       
  9333 			if (style.hasStroke())
       
  9334 				ctx.strokeText(line, 0, 0);
       
  9335 			ctx.translate(0, leading);
       
  9336 		}
       
  9337 	},
       
  9338 
       
  9339 	_getBounds: function(getter, matrix) {
       
  9340 		var style = this._style,
       
  9341 			lines = this._lines,
       
  9342 			numLines = lines.length,
       
  9343 			justification = style.getJustification(),
       
  9344 			leading = style.getLeading(),
       
  9345 			width = this.getView().getTextWidth(style.getFontStyle(), lines),
       
  9346 			x = 0;
       
  9347 		if (justification !== 'left')
       
  9348 			x -= width / (justification === 'center' ? 2: 1);
       
  9349 		var bounds = new Rectangle(x,
       
  9350 					numLines ? - 0.75 * leading : 0,
       
  9351 					width, numLines * leading);
       
  9352 		return matrix ? matrix._transformBounds(bounds, bounds) : bounds;
       
  9353 	}
       
  9354 });
       
  9355 
       
  9356 var Color = Base.extend(new function() {
       
  9357 	var types = {
       
  9358 		gray: ['gray'],
       
  9359 		rgb: ['red', 'green', 'blue'],
       
  9360 		hsb: ['hue', 'saturation', 'brightness'],
       
  9361 		hsl: ['hue', 'saturation', 'lightness'],
       
  9362 		gradient: ['gradient', 'origin', 'destination', 'highlight']
       
  9363 	};
       
  9364 
       
  9365 	var componentParsers = {},
       
  9366 		colorCache = {},
       
  9367 		colorCtx;
       
  9368 
       
  9369 	function fromCSS(string) {
       
  9370 		var match = string.match(/^#(\w{1,2})(\w{1,2})(\w{1,2})$/),
       
  9371 			components;
       
  9372 		if (match) {
       
  9373 			components = [0, 0, 0];
       
  9374 			for (var i = 0; i < 3; i++) {
       
  9375 				var value = match[i + 1];
       
  9376 				components[i] = parseInt(value.length == 1
       
  9377 						? value + value : value, 16) / 255;
       
  9378 			}
       
  9379 		} else if (match = string.match(/^rgba?\((.*)\)$/)) {
       
  9380 			components = match[1].split(',');
       
  9381 			for (var i = 0, l = components.length; i < l; i++) {
       
  9382 				var value = +components[i];
       
  9383 				components[i] = i < 3 ? value / 255 : value;
       
  9384 			}
       
  9385 		} else {
       
  9386 			var cached = colorCache[string];
       
  9387 			if (!cached) {
       
  9388 				if (!colorCtx) {
       
  9389 					colorCtx = CanvasProvider.getContext(1, 1);
       
  9390 					colorCtx.globalCompositeOperation = 'copy';
       
  9391 				}
       
  9392 				colorCtx.fillStyle = 'rgba(0,0,0,0)';
       
  9393 				colorCtx.fillStyle = string;
       
  9394 				colorCtx.fillRect(0, 0, 1, 1);
       
  9395 				var data = colorCtx.getImageData(0, 0, 1, 1).data;
       
  9396 				cached = colorCache[string] = [
       
  9397 					data[0] / 255,
       
  9398 					data[1] / 255,
       
  9399 					data[2] / 255
       
  9400 				];
       
  9401 			}
       
  9402 			components = cached.slice();
       
  9403 		}
       
  9404 		return components;
       
  9405 	}
       
  9406 
       
  9407 	var hsbIndices = [
       
  9408 		[0, 3, 1],
       
  9409 		[2, 0, 1],
       
  9410 		[1, 0, 3],
       
  9411 		[1, 2, 0],
       
  9412 		[3, 1, 0],
       
  9413 		[0, 1, 2]
       
  9414 	];
       
  9415 
       
  9416 	var converters = {
       
  9417 		'rgb-hsb': function(r, g, b) {
       
  9418 			var max = Math.max(r, g, b),
       
  9419 				min = Math.min(r, g, b),
       
  9420 				delta = max - min,
       
  9421 				h = delta === 0 ? 0
       
  9422 					:	( max == r ? (g - b) / delta + (g < b ? 6 : 0)
       
  9423 						: max == g ? (b - r) / delta + 2
       
  9424 						:			 (r - g) / delta + 4) * 60;
       
  9425 			return [h, max === 0 ? 0 : delta / max, max];
       
  9426 		},
       
  9427 
       
  9428 		'hsb-rgb': function(h, s, b) {
       
  9429 			h = (((h / 60) % 6) + 6) % 6;
       
  9430 			var i = Math.floor(h),
       
  9431 				f = h - i,
       
  9432 				i = hsbIndices[i],
       
  9433 				v = [
       
  9434 					b,
       
  9435 					b * (1 - s),
       
  9436 					b * (1 - s * f),
       
  9437 					b * (1 - s * (1 - f))
       
  9438 				];
       
  9439 			return [v[i[0]], v[i[1]], v[i[2]]];
       
  9440 		},
       
  9441 
       
  9442 		'rgb-hsl': function(r, g, b) {
       
  9443 			var max = Math.max(r, g, b),
       
  9444 				min = Math.min(r, g, b),
       
  9445 				delta = max - min,
       
  9446 				achromatic = delta === 0,
       
  9447 				h = achromatic ? 0
       
  9448 					:	( max == r ? (g - b) / delta + (g < b ? 6 : 0)
       
  9449 						: max == g ? (b - r) / delta + 2
       
  9450 						:			 (r - g) / delta + 4) * 60,
       
  9451 				l = (max + min) / 2,
       
  9452 				s = achromatic ? 0 : l < 0.5
       
  9453 						? delta / (max + min)
       
  9454 						: delta / (2 - max - min);
       
  9455 			return [h, s, l];
       
  9456 		},
       
  9457 
       
  9458 		'hsl-rgb': function(h, s, l) {
       
  9459 			h = (((h / 360) % 1) + 1) % 1;
       
  9460 			if (s === 0)
       
  9461 				return [l, l, l];
       
  9462 			var t3s = [ h + 1 / 3, h, h - 1 / 3 ],
       
  9463 				t2 = l < 0.5 ? l * (1 + s) : l + s - l * s,
       
  9464 				t1 = 2 * l - t2,
       
  9465 				c = [];
       
  9466 			for (var i = 0; i < 3; i++) {
       
  9467 				var t3 = t3s[i];
       
  9468 				if (t3 < 0) t3 += 1;
       
  9469 				if (t3 > 1) t3 -= 1;
       
  9470 				c[i] = 6 * t3 < 1
       
  9471 					? t1 + (t2 - t1) * 6 * t3
       
  9472 					: 2 * t3 < 1
       
  9473 						? t2
       
  9474 						: 3 * t3 < 2
       
  9475 							? t1 + (t2 - t1) * ((2 / 3) - t3) * 6
       
  9476 							: t1;
       
  9477 			}
       
  9478 			return c;
       
  9479 		},
       
  9480 
       
  9481 		'rgb-gray': function(r, g, b) {
       
  9482 			return [r * 0.2989 + g * 0.587 + b * 0.114];
       
  9483 		},
       
  9484 
       
  9485 		'gray-rgb': function(g) {
       
  9486 			return [g, g, g];
       
  9487 		},
       
  9488 
       
  9489 		'gray-hsb': function(g) {
       
  9490 			return [0, 0, g];
       
  9491 		},
       
  9492 
       
  9493 		'gray-hsl': function(g) {
       
  9494 			return [0, 0, g];
       
  9495 		},
       
  9496 
       
  9497 		'gradient-rgb': function() {
       
  9498 			return [];
       
  9499 		},
       
  9500 
       
  9501 		'rgb-gradient': function() {
       
  9502 			return [];
       
  9503 		}
       
  9504 
       
  9505 	};
       
  9506 
       
  9507 	return Base.each(types, function(properties, type) {
       
  9508 		componentParsers[type] = [];
       
  9509 		Base.each(properties, function(name, index) {
       
  9510 			var part = Base.capitalize(name),
       
  9511 				hasOverlap = /^(hue|saturation)$/.test(name),
       
  9512 				parser = componentParsers[type][index] = name === 'gradient'
       
  9513 					? function(value) {
       
  9514 						var current = this._components[0];
       
  9515 						value = Gradient.read(Array.isArray(value) ? value
       
  9516 								: arguments, 0, { readNull: true });
       
  9517 						if (current !== value) {
       
  9518 							if (current)
       
  9519 								current._removeOwner(this);
       
  9520 							if (value)
       
  9521 								value._addOwner(this);
       
  9522 						}
       
  9523 						return value;
       
  9524 					}
       
  9525 					: type === 'gradient'
       
  9526 						? function() {
       
  9527 							return Point.read(arguments, 0, {
       
  9528 									readNull: name === 'highlight',
       
  9529 									clone: true
       
  9530 							});
       
  9531 						}
       
  9532 						: function(value) {
       
  9533 							return value == null || isNaN(value) ? 0 : value;
       
  9534 						};
       
  9535 
       
  9536 			this['get' + part] = function() {
       
  9537 				return this._type === type
       
  9538 					|| hasOverlap && /^hs[bl]$/.test(this._type)
       
  9539 						? this._components[index]
       
  9540 						: this._convert(type)[index];
       
  9541 			};
       
  9542 
       
  9543 			this['set' + part] = function(value) {
       
  9544 				if (this._type !== type
       
  9545 						&& !(hasOverlap && /^hs[bl]$/.test(this._type))) {
       
  9546 					this._components = this._convert(type);
       
  9547 					this._properties = types[type];
       
  9548 					this._type = type;
       
  9549 				}
       
  9550 				value = parser.call(this, value);
       
  9551 				if (value != null) {
       
  9552 					this._components[index] = value;
       
  9553 					this._changed();
       
  9554 				}
       
  9555 			};
       
  9556 		}, this);
       
  9557 	}, {
       
  9558 		_class: 'Color',
       
  9559 		_readIndex: true,
       
  9560 
       
  9561 		initialize: function Color(arg) {
       
  9562 			var slice = Array.prototype.slice,
       
  9563 				args = arguments,
       
  9564 				read = 0,
       
  9565 				type,
       
  9566 				components,
       
  9567 				alpha,
       
  9568 				values;
       
  9569 			if (Array.isArray(arg)) {
       
  9570 				args = arg;
       
  9571 				arg = args[0];
       
  9572 			}
       
  9573 			var argType = arg != null && typeof arg;
       
  9574 			if (argType === 'string' && arg in types) {
       
  9575 				type = arg;
       
  9576 				arg = args[1];
       
  9577 				if (Array.isArray(arg)) {
       
  9578 					components = arg;
       
  9579 					alpha = args[2];
       
  9580 				} else {
       
  9581 					if (this.__read)
       
  9582 						read = 1;
       
  9583 					args = slice.call(args, 1);
       
  9584 					argType = typeof arg;
       
  9585 				}
       
  9586 			}
       
  9587 			if (!components) {
       
  9588 				values = argType === 'number'
       
  9589 						? args
       
  9590 						: argType === 'object' && arg.length != null
       
  9591 							? arg
       
  9592 							: null;
       
  9593 				if (values) {
       
  9594 					if (!type)
       
  9595 						type = values.length >= 3
       
  9596 								? 'rgb'
       
  9597 								: 'gray';
       
  9598 					var length = types[type].length;
       
  9599 					alpha = values[length];
       
  9600 					if (this.__read)
       
  9601 						read += values === arguments
       
  9602 							? length + (alpha != null ? 1 : 0)
       
  9603 							: 1;
       
  9604 					if (values.length > length)
       
  9605 						values = slice.call(values, 0, length);
       
  9606 				} else if (argType === 'string') {
       
  9607 					type = 'rgb';
       
  9608 					components = fromCSS(arg);
       
  9609 					if (components.length === 4) {
       
  9610 						alpha = components[3];
       
  9611 						components.length--;
       
  9612 					}
       
  9613 				} else if (argType === 'object') {
       
  9614 					if (arg.constructor === Color) {
       
  9615 						type = arg._type;
       
  9616 						components = arg._components.slice();
       
  9617 						alpha = arg._alpha;
       
  9618 						if (type === 'gradient') {
       
  9619 							for (var i = 1, l = components.length; i < l; i++) {
       
  9620 								var point = components[i];
       
  9621 								if (point)
       
  9622 									components[i] = point.clone();
       
  9623 							}
       
  9624 						}
       
  9625 					} else if (arg.constructor === Gradient) {
       
  9626 						type = 'gradient';
       
  9627 						values = args;
       
  9628 					} else {
       
  9629 						type = 'hue' in arg
       
  9630 							? 'lightness' in arg
       
  9631 								? 'hsl'
       
  9632 								: 'hsb'
       
  9633 							: 'gradient' in arg || 'stops' in arg
       
  9634 									|| 'radial' in arg
       
  9635 								? 'gradient'
       
  9636 								: 'gray' in arg
       
  9637 									? 'gray'
       
  9638 									: 'rgb';
       
  9639 						var properties = types[type];
       
  9640 							parsers = componentParsers[type];
       
  9641 						this._components = components = [];
       
  9642 						for (var i = 0, l = properties.length; i < l; i++) {
       
  9643 							var value = arg[properties[i]];
       
  9644 							if (value == null && i === 0 && type === 'gradient'
       
  9645 									&& 'stops' in arg) {
       
  9646 								value = {
       
  9647 									stops: arg.stops,
       
  9648 									radial: arg.radial
       
  9649 								};
       
  9650 							}
       
  9651 							value = parsers[i].call(this, value);
       
  9652 							if (value != null)
       
  9653 								components[i] = value;
       
  9654 						}
       
  9655 						alpha = arg.alpha;
       
  9656 					}
       
  9657 				}
       
  9658 				if (this.__read && type)
       
  9659 					read = 1;
       
  9660 			}
       
  9661 			this._type = type || 'rgb';
       
  9662 			if (type === 'gradient')
       
  9663 				this._id = Color._id = (Color._id || 0) + 1;
       
  9664 			if (!components) {
       
  9665 				this._components = components = [];
       
  9666 				var parsers = componentParsers[this._type];
       
  9667 				for (var i = 0, l = parsers.length; i < l; i++) {
       
  9668 					var value = parsers[i].call(this, values && values[i]);
       
  9669 					if (value != null)
       
  9670 						components[i] = value;
       
  9671 				}
       
  9672 			}
       
  9673 			this._components = components;
       
  9674 			this._properties = types[this._type];
       
  9675 			this._alpha = alpha;
       
  9676 			if (this.__read)
       
  9677 				this.__read = read;
       
  9678 		},
       
  9679 
       
  9680 		_serialize: function(options, dictionary) {
       
  9681 			var components = this.getComponents();
       
  9682 			return Base.serialize(
       
  9683 					/^(gray|rgb)$/.test(this._type)
       
  9684 						? components
       
  9685 						: [this._type].concat(components),
       
  9686 					options, true, dictionary);
       
  9687 		},
       
  9688 
       
  9689 		_changed: function() {
       
  9690 			this._canvasStyle = null;
       
  9691 			if (this._owner)
       
  9692 				this._owner._changed(65);
       
  9693 		},
       
  9694 
       
  9695 		_convert: function(type) {
       
  9696 			var converter;
       
  9697 			return this._type === type
       
  9698 					? this._components.slice()
       
  9699 					: (converter = converters[this._type + '-' + type])
       
  9700 						? converter.apply(this, this._components)
       
  9701 						: converters['rgb-' + type].apply(this,
       
  9702 							converters[this._type + '-rgb'].apply(this,
       
  9703 								this._components));
       
  9704 		},
       
  9705 
       
  9706 		convert: function(type) {
       
  9707 			return new Color(type, this._convert(type), this._alpha);
       
  9708 		},
       
  9709 
       
  9710 		getType: function() {
       
  9711 			return this._type;
       
  9712 		},
       
  9713 
       
  9714 		setType: function(type) {
       
  9715 			this._components = this._convert(type);
       
  9716 			this._properties = types[type];
       
  9717 			this._type = type;
       
  9718 		},
       
  9719 
       
  9720 		getComponents: function() {
       
  9721 			var components = this._components.slice();
       
  9722 			if (this._alpha != null)
       
  9723 				components.push(this._alpha);
       
  9724 			return components;
       
  9725 		},
       
  9726 
       
  9727 		getAlpha: function() {
       
  9728 			return this._alpha != null ? this._alpha : 1;
       
  9729 		},
       
  9730 
       
  9731 		setAlpha: function(alpha) {
       
  9732 			this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1);
       
  9733 			this._changed();
       
  9734 		},
       
  9735 
       
  9736 		hasAlpha: function() {
       
  9737 			return this._alpha != null;
       
  9738 		},
       
  9739 
       
  9740 		equals: function(color) {
       
  9741 			var col = Base.isPlainValue(color, true)
       
  9742 					? Color.read(arguments)
       
  9743 					: color;
       
  9744 			return col === this || col && this._class === col._class
       
  9745 					&& this._type === col._type
       
  9746 					&& this._alpha === col._alpha
       
  9747 					&& Base.equals(this._components, col._components)
       
  9748 					|| false;
       
  9749 		},
       
  9750 
       
  9751 		toString: function() {
       
  9752 			var properties = this._properties,
       
  9753 				parts = [],
       
  9754 				isGradient = this._type === 'gradient',
       
  9755 				f = Formatter.instance;
       
  9756 			for (var i = 0, l = properties.length; i < l; i++) {
       
  9757 				var value = this._components[i];
       
  9758 				if (value != null)
       
  9759 					parts.push(properties[i] + ': '
       
  9760 							+ (isGradient ? value : f.number(value)));
       
  9761 			}
       
  9762 			if (this._alpha != null)
       
  9763 				parts.push('alpha: ' + f.number(this._alpha));
       
  9764 			return '{ ' + parts.join(', ') + ' }';
       
  9765 		},
       
  9766 
       
  9767 		toCSS: function(hex) {
       
  9768 			var components = this._convert('rgb'),
       
  9769 				alpha = hex || this._alpha == null ? 1 : this._alpha;
       
  9770 			function convert(val) {
       
  9771 				return Math.round((val < 0 ? 0 : val > 1 ? 1 : val) * 255);
       
  9772 			}
       
  9773 			components = [
       
  9774 				convert(components[0]),
       
  9775 				convert(components[1]),
       
  9776 				convert(components[2])
       
  9777 			];
       
  9778 			if (alpha < 1)
       
  9779 				components.push(alpha < 0 ? 0 : alpha);
       
  9780 			return hex
       
  9781 					? '#' + ((1 << 24) + (components[0] << 16)
       
  9782 						+ (components[1] << 8)
       
  9783 						+ components[2]).toString(16).slice(1)
       
  9784 					: (components.length == 4 ? 'rgba(' : 'rgb(')
       
  9785 						+ components.join(',') + ')';
       
  9786 		},
       
  9787 
       
  9788 		toCanvasStyle: function(ctx) {
       
  9789 			if (this._canvasStyle)
       
  9790 				return this._canvasStyle;
       
  9791 			if (this._type !== 'gradient')
       
  9792 				return this._canvasStyle = this.toCSS();
       
  9793 			var components = this._components,
       
  9794 				gradient = components[0],
       
  9795 				stops = gradient._stops,
       
  9796 				origin = components[1],
       
  9797 				destination = components[2],
       
  9798 				canvasGradient;
       
  9799 			if (gradient._radial) {
       
  9800 				var radius = destination.getDistance(origin),
       
  9801 					highlight = components[3];
       
  9802 				if (highlight) {
       
  9803 					var vector = highlight.subtract(origin);
       
  9804 					if (vector.getLength() > radius)
       
  9805 						highlight = origin.add(vector.normalize(radius - 0.1));
       
  9806 				}
       
  9807 				var start = highlight || origin;
       
  9808 				canvasGradient = ctx.createRadialGradient(start.x, start.y,
       
  9809 						0, origin.x, origin.y, radius);
       
  9810 			} else {
       
  9811 				canvasGradient = ctx.createLinearGradient(origin.x, origin.y,
       
  9812 						destination.x, destination.y);
       
  9813 			}
       
  9814 			for (var i = 0, l = stops.length; i < l; i++) {
       
  9815 				var stop = stops[i];
       
  9816 				canvasGradient.addColorStop(stop._rampPoint,
       
  9817 						stop._color.toCanvasStyle());
       
  9818 			}
       
  9819 			return this._canvasStyle = canvasGradient;
       
  9820 		},
       
  9821 
       
  9822 		transform: function(matrix) {
       
  9823 			if (this._type === 'gradient') {
       
  9824 				var components = this._components;
       
  9825 				for (var i = 1, l = components.length; i < l; i++) {
       
  9826 					var point = components[i];
       
  9827 					matrix._transformPoint(point, point, true);
       
  9828 				}
       
  9829 				this._changed();
       
  9830 			}
       
  9831 		},
       
  9832 
       
  9833 		statics: {
       
  9834 			_types: types,
       
  9835 
       
  9836 			random: function() {
       
  9837 				var random = Math.random;
       
  9838 				return new Color(random(), random(), random());
       
  9839 			}
       
  9840 		}
       
  9841 	});
       
  9842 }, new function() {
       
  9843 	var operators = {
       
  9844 		add: function(a, b) {
       
  9845 			return a + b;
       
  9846 		},
       
  9847 
       
  9848 		subtract: function(a, b) {
       
  9849 			return a - b;
       
  9850 		},
       
  9851 
       
  9852 		multiply: function(a, b) {
       
  9853 			return a * b;
       
  9854 		},
       
  9855 
       
  9856 		divide: function(a, b) {
       
  9857 			return a / b;
       
  9858 		}
       
  9859 	};
       
  9860 
       
  9861 	return Base.each(operators, function(operator, name) {
       
  9862 		this[name] = function(color) {
       
  9863 			color = Color.read(arguments);
       
  9864 			var type = this._type,
       
  9865 				components1 = this._components,
       
  9866 				components2 = color._convert(type);
       
  9867 			for (var i = 0, l = components1.length; i < l; i++)
       
  9868 				components2[i] = operator(components1[i], components2[i]);
       
  9869 			return new Color(type, components2,
       
  9870 					this._alpha != null
       
  9871 							? operator(this._alpha, color.getAlpha())
       
  9872 							: null);
       
  9873 		};
       
  9874 	}, {
       
  9875 	});
       
  9876 });
       
  9877 
       
  9878 Base.each(Color._types, function(properties, type) {
       
  9879 	var ctor = this[Base.capitalize(type) + 'Color'] = function(arg) {
       
  9880 			var argType = arg != null && typeof arg,
       
  9881 				components = argType === 'object' && arg.length != null
       
  9882 					? arg
       
  9883 					: argType === 'string'
       
  9884 						? null
       
  9885 						: arguments;
       
  9886 			return components
       
  9887 					? new Color(type, components)
       
  9888 					: new Color(arg);
       
  9889 		};
       
  9890 	if (type.length == 3) {
       
  9891 		var acronym = type.toUpperCase();
       
  9892 		Color[acronym] = this[acronym + 'Color'] = ctor;
       
  9893 	}
       
  9894 }, Base.exports);
       
  9895 
       
  9896 var Gradient = Base.extend({
       
  9897 	_class: 'Gradient',
       
  9898 
       
  9899 	initialize: function Gradient(stops, radial) {
       
  9900 		this._id = Gradient._id = (Gradient._id || 0) + 1;
       
  9901 		if (stops && this._set(stops))
       
  9902 			stops = radial = null;
       
  9903 		if (!this._stops)
       
  9904 			this.setStops(stops || ['white', 'black']);
       
  9905 		if (this._radial == null)
       
  9906 			this.setRadial(typeof radial === 'string' && radial === 'radial'
       
  9907 					|| radial || false);
       
  9908 	},
       
  9909 
       
  9910 	_serialize: function(options, dictionary) {
       
  9911 		return dictionary.add(this, function() {
       
  9912 			return Base.serialize([this._stops, this._radial],
       
  9913 					options, true, dictionary);
       
  9914 		});
       
  9915 	},
       
  9916 
       
  9917 	_changed: function() {
       
  9918 		for (var i = 0, l = this._owners && this._owners.length; i < l; i++)
       
  9919 			this._owners[i]._changed();
       
  9920 	},
       
  9921 
       
  9922 	_addOwner: function(color) {
       
  9923 		if (!this._owners)
       
  9924 			this._owners = [];
       
  9925 		this._owners.push(color);
       
  9926 	},
       
  9927 
       
  9928 	_removeOwner: function(color) {
       
  9929 		var index = this._owners ? this._owners.indexOf(color) : -1;
       
  9930 		if (index != -1) {
       
  9931 			this._owners.splice(index, 1);
       
  9932 			if (this._owners.length === 0)
       
  9933 				this._owners = undefined;
       
  9934 		}
       
  9935 	},
       
  9936 
       
  9937 	clone: function() {
       
  9938 		var stops = [];
       
  9939 		for (var i = 0, l = this._stops.length; i < l; i++)
       
  9940 			stops[i] = this._stops[i].clone();
       
  9941 		return new Gradient(stops);
       
  9942 	},
       
  9943 
       
  9944 	getStops: function() {
       
  9945 		return this._stops;
       
  9946 	},
       
  9947 
       
  9948 	setStops: function(stops) {
       
  9949 		if (this.stops) {
       
  9950 			for (var i = 0, l = this._stops.length; i < l; i++)
       
  9951 				this._stops[i]._owner = undefined;
       
  9952 		}
       
  9953 		if (stops.length < 2)
       
  9954 			throw new Error(
       
  9955 					'Gradient stop list needs to contain at least two stops.');
       
  9956 		this._stops = GradientStop.readAll(stops, 0, { clone: true });
       
  9957 		for (var i = 0, l = this._stops.length; i < l; i++) {
       
  9958 			var stop = this._stops[i];
       
  9959 			stop._owner = this;
       
  9960 			if (stop._defaultRamp)
       
  9961 				stop.setRampPoint(i / (l - 1));
       
  9962 		}
       
  9963 		this._changed();
       
  9964 	},
       
  9965 
       
  9966 	getRadial: function() {
       
  9967 		return this._radial;
       
  9968 	},
       
  9969 
       
  9970 	setRadial: function(radial) {
       
  9971 		this._radial = radial;
       
  9972 		this._changed();
       
  9973 	},
       
  9974 
       
  9975 	equals: function(gradient) {
       
  9976 		if (gradient === this)
       
  9977 			return true;
       
  9978 		if (gradient && this._class === gradient._class
       
  9979 				&& this._stops.length === gradient._stops.length) {
       
  9980 			for (var i = 0, l = this._stops.length; i < l; i++) {
       
  9981 				if (!this._stops[i].equals(gradient._stops[i]))
       
  9982 					return false;
       
  9983 			}
       
  9984 			return true;
       
  9985 		}
       
  9986 		return false;
       
  9987 	}
       
  9988 });
       
  9989 
       
  9990 var GradientStop = Base.extend({
       
  9991 	_class: 'GradientStop',
       
  9992 
       
  9993 	initialize: function GradientStop(arg0, arg1) {
       
  9994 		if (arg0) {
       
  9995 			var color, rampPoint;
       
  9996 			if (arg1 === undefined && Array.isArray(arg0)) {
       
  9997 				color = arg0[0];
       
  9998 				rampPoint = arg0[1];
       
  9999 			} else if (arg0.color) {
       
 10000 				color = arg0.color;
       
 10001 				rampPoint = arg0.rampPoint;
       
 10002 			} else {
       
 10003 				color = arg0;
       
 10004 				rampPoint = arg1;
       
 10005 			}
       
 10006 			this.setColor(color);
       
 10007 			this.setRampPoint(rampPoint);
       
 10008 		}
       
 10009 	},
       
 10010 
       
 10011 	clone: function() {
       
 10012 		return new GradientStop(this._color.clone(), this._rampPoint);
       
 10013 	},
       
 10014 
       
 10015 	_serialize: function(options, dictionary) {
       
 10016 		return Base.serialize([this._color, this._rampPoint], options, true,
       
 10017 				dictionary);
       
 10018 	},
       
 10019 
       
 10020 	_changed: function() {
       
 10021 		if (this._owner)
       
 10022 			this._owner._changed(65);
       
 10023 	},
       
 10024 
       
 10025 	getRampPoint: function() {
       
 10026 		return this._rampPoint;
       
 10027 	},
       
 10028 
       
 10029 	setRampPoint: function(rampPoint) {
       
 10030 		this._defaultRamp = rampPoint == null;
       
 10031 		this._rampPoint = rampPoint || 0;
       
 10032 		this._changed();
       
 10033 	},
       
 10034 
       
 10035 	getColor: function() {
       
 10036 		return this._color;
       
 10037 	},
       
 10038 
       
 10039 	setColor: function(color) {
       
 10040 		this._color = Color.read(arguments);
       
 10041 		if (this._color === color)
       
 10042 			this._color = color.clone();
       
 10043 		this._color._owner = this;
       
 10044 		this._changed();
       
 10045 	},
       
 10046 
       
 10047 	equals: function(stop) {
       
 10048 		return stop === this || stop && this._class === stop._class
       
 10049 				&& this._color.equals(stop._color)
       
 10050 				&& this._rampPoint == stop._rampPoint
       
 10051 				|| false;
       
 10052 	}
       
 10053 });
       
 10054 
       
 10055 var Style = Base.extend(new function() {
       
 10056 	var defaults = {
       
 10057 		fillColor: undefined,
       
 10058 		strokeColor: undefined,
       
 10059 		strokeWidth: 1,
       
 10060 		strokeCap: 'butt',
       
 10061 		strokeJoin: 'miter',
       
 10062 		strokeScaling: true,
       
 10063 		miterLimit: 10,
       
 10064 		dashOffset: 0,
       
 10065 		dashArray: [],
       
 10066 		windingRule: 'nonzero',
       
 10067 		shadowColor: undefined,
       
 10068 		shadowBlur: 0,
       
 10069 		shadowOffset: new Point(),
       
 10070 		selectedColor: undefined,
       
 10071 		fontFamily: 'sans-serif',
       
 10072 		fontWeight: 'normal',
       
 10073 		fontSize: 12,
       
 10074 		font: 'sans-serif',
       
 10075 		leading: null,
       
 10076 		justification: 'left'
       
 10077 	};
       
 10078 
       
 10079 	var flags = {
       
 10080 		strokeWidth: 97,
       
 10081 		strokeCap: 97,
       
 10082 		strokeJoin: 97,
       
 10083 		strokeScaling: 105,
       
 10084 		miterLimit: 97,
       
 10085 		fontFamily: 9,
       
 10086 		fontWeight: 9,
       
 10087 		fontSize: 9,
       
 10088 		font: 9,
       
 10089 		leading: 9,
       
 10090 		justification: 9
       
 10091 	};
       
 10092 
       
 10093 	var item = { beans: true },
       
 10094 		fields = {
       
 10095 			_defaults: defaults,
       
 10096 			_textDefaults: new Base(defaults, {
       
 10097 				fillColor: new Color()
       
 10098 			}),
       
 10099 			beans: true
       
 10100 		};
       
 10101 
       
 10102 	Base.each(defaults, function(value, key) {
       
 10103 		var isColor = /Color$/.test(key),
       
 10104 			isPoint = key === 'shadowOffset',
       
 10105 			part = Base.capitalize(key),
       
 10106 			flag = flags[key],
       
 10107 			set = 'set' + part,
       
 10108 			get = 'get' + part;
       
 10109 
       
 10110 		fields[set] = function(value) {
       
 10111 			var owner = this._owner,
       
 10112 				children = owner && owner._children;
       
 10113 			if (children && children.length > 0
       
 10114 					&& !(owner instanceof CompoundPath)) {
       
 10115 				for (var i = 0, l = children.length; i < l; i++)
       
 10116 					children[i]._style[set](value);
       
 10117 			} else {
       
 10118 				var old = this._values[key];
       
 10119 				if (old !== value) {
       
 10120 					if (isColor) {
       
 10121 						if (old)
       
 10122 							old._owner = undefined;
       
 10123 						if (value && value.constructor === Color) {
       
 10124 							if (value._owner)
       
 10125 								value = value.clone();
       
 10126 							value._owner = owner;
       
 10127 						}
       
 10128 					}
       
 10129 					this._values[key] = value;
       
 10130 					if (owner)
       
 10131 						owner._changed(flag || 65);
       
 10132 				}
       
 10133 			}
       
 10134 		};
       
 10135 
       
 10136 		fields[get] = function(_dontMerge) {
       
 10137 			var owner = this._owner,
       
 10138 				children = owner && owner._children,
       
 10139 				value;
       
 10140 			if (!children || children.length === 0 || _dontMerge
       
 10141 					|| owner instanceof CompoundPath) {
       
 10142 				var value = this._values[key];
       
 10143 				if (value === undefined) {
       
 10144 					value = this._defaults[key];
       
 10145 					if (value && value.clone)
       
 10146 						value = value.clone();
       
 10147 				} else {
       
 10148 					var ctor = isColor ? Color : isPoint ? Point : null;
       
 10149 					if (ctor && !(value && value.constructor === ctor)) {
       
 10150 						this._values[key] = value = ctor.read([value], 0,
       
 10151 								{ readNull: true, clone: true });
       
 10152 						if (value && isColor)
       
 10153 							value._owner = owner;
       
 10154 					}
       
 10155 				}
       
 10156 				return value;
       
 10157 			}
       
 10158 			for (var i = 0, l = children.length; i < l; i++) {
       
 10159 				var childValue = children[i]._style[get]();
       
 10160 				if (i === 0) {
       
 10161 					value = childValue;
       
 10162 				} else if (!Base.equals(value, childValue)) {
       
 10163 					return undefined;
       
 10164 				}
       
 10165 			}
       
 10166 			return value;
       
 10167 		};
       
 10168 
       
 10169 		item[get] = function(_dontMerge) {
       
 10170 			return this._style[get](_dontMerge);
       
 10171 		};
       
 10172 
       
 10173 		item[set] = function(value) {
       
 10174 			this._style[set](value);
       
 10175 		};
       
 10176 	});
       
 10177 
       
 10178 	Item.inject(item);
       
 10179 	return fields;
       
 10180 }, {
       
 10181 	_class: 'Style',
       
 10182 
       
 10183 	initialize: function Style(style, _owner, _project) {
       
 10184 		this._values = {};
       
 10185 		this._owner = _owner;
       
 10186 		this._project = _owner && _owner._project || _project || paper.project;
       
 10187 		if (_owner instanceof TextItem)
       
 10188 			this._defaults = this._textDefaults;
       
 10189 		if (style)
       
 10190 			this.set(style);
       
 10191 	},
       
 10192 
       
 10193 	set: function(style) {
       
 10194 		var isStyle = style instanceof Style,
       
 10195 			values = isStyle ? style._values : style;
       
 10196 		if (values) {
       
 10197 			for (var key in values) {
       
 10198 				if (key in this._defaults) {
       
 10199 					var value = values[key];
       
 10200 					this[key] = value && isStyle && value.clone
       
 10201 							? value.clone() : value;
       
 10202 				}
       
 10203 			}
       
 10204 		}
       
 10205 	},
       
 10206 
       
 10207 	equals: function(style) {
       
 10208 		return style === this || style && this._class === style._class
       
 10209 				&& Base.equals(this._values, style._values)
       
 10210 				|| false;
       
 10211 	},
       
 10212 
       
 10213 	hasFill: function() {
       
 10214 		return !!this.getFillColor();
       
 10215 	},
       
 10216 
       
 10217 	hasStroke: function() {
       
 10218 		return !!this.getStrokeColor() && this.getStrokeWidth() > 0;
       
 10219 	},
       
 10220 
       
 10221 	hasShadow: function() {
       
 10222 		return !!this.getShadowColor() && this.getShadowBlur() > 0;
       
 10223 	},
       
 10224 
       
 10225 	getView: function() {
       
 10226 		return this._project.getView();
       
 10227 	},
       
 10228 
       
 10229 	getFontStyle: function() {
       
 10230 		var fontSize = this.getFontSize();
       
 10231 		return this.getFontWeight()
       
 10232 				+ ' ' + fontSize + (/[a-z]/i.test(fontSize + '') ? ' ' : 'px ')
       
 10233 				+ this.getFontFamily();
       
 10234 	},
       
 10235 
       
 10236 	getFont: '#getFontFamily',
       
 10237 	setFont: '#setFontFamily',
       
 10238 
       
 10239 	getLeading: function getLeading() {
       
 10240 		var leading = getLeading.base.call(this),
       
 10241 			fontSize = this.getFontSize();
       
 10242 		if (/pt|em|%|px/.test(fontSize))
       
 10243 			fontSize = this.getView().getPixelSize(fontSize);
       
 10244 		return leading != null ? leading : fontSize * 1.2;
       
 10245 	}
       
 10246 
       
 10247 });
       
 10248 
       
 10249 var DomElement = new function() {
       
 10250 	function handlePrefix(el, name, set, value) {
       
 10251 		var prefixes = ['', 'webkit', 'moz', 'Moz', 'ms', 'o'],
       
 10252 			suffix = name[0].toUpperCase() + name.substring(1);
       
 10253 		for (var i = 0; i < 6; i++) {
       
 10254 			var prefix = prefixes[i],
       
 10255 				key = prefix ? prefix + suffix : name;
       
 10256 			if (key in el) {
       
 10257 				if (set) {
       
 10258 					el[key] = value;
       
 10259 				} else {
       
 10260 					return el[key];
       
 10261 				}
       
 10262 				break;
       
 10263 			}
       
 10264 		}
       
 10265 	}
       
 10266 
       
 10267 	return {
       
 10268 		getStyles: function(el) {
       
 10269 			var doc = el && el.nodeType !== 9 ? el.ownerDocument : el,
       
 10270 				view = doc && doc.defaultView;
       
 10271 			return view && view.getComputedStyle(el, '');
       
 10272 		},
       
 10273 
       
 10274 		getBounds: function(el, viewport) {
       
 10275 			var doc = el.ownerDocument,
       
 10276 				body = doc.body,
       
 10277 				html = doc.documentElement,
       
 10278 				rect;
       
 10279 			try {
       
 10280 				rect = el.getBoundingClientRect();
       
 10281 			} catch (e) {
       
 10282 				rect = { left: 0, top: 0, width: 0, height: 0 };
       
 10283 			}
       
 10284 			var x = rect.left - (html.clientLeft || body.clientLeft || 0),
       
 10285 				y = rect.top - (html.clientTop || body.clientTop || 0);
       
 10286 			if (!viewport) {
       
 10287 				var view = doc.defaultView;
       
 10288 				x += view.pageXOffset || html.scrollLeft || body.scrollLeft;
       
 10289 				y += view.pageYOffset || html.scrollTop || body.scrollTop;
       
 10290 			}
       
 10291 			return new Rectangle(x, y, rect.width, rect.height);
       
 10292 		},
       
 10293 
       
 10294 		getViewportBounds: function(el) {
       
 10295 			var doc = el.ownerDocument,
       
 10296 				view = doc.defaultView,
       
 10297 				html = doc.documentElement;
       
 10298 			return new Rectangle(0, 0,
       
 10299 				view.innerWidth || html.clientWidth,
       
 10300 				view.innerHeight || html.clientHeight
       
 10301 			);
       
 10302 		},
       
 10303 
       
 10304 		getOffset: function(el, viewport) {
       
 10305 			return DomElement.getBounds(el, viewport).getPoint();
       
 10306 		},
       
 10307 
       
 10308 		getSize: function(el) {
       
 10309 			return DomElement.getBounds(el, true).getSize();
       
 10310 		},
       
 10311 
       
 10312 		isInvisible: function(el) {
       
 10313 			return DomElement.getSize(el).equals(new Size(0, 0));
       
 10314 		},
       
 10315 
       
 10316 		isInView: function(el) {
       
 10317 			return !DomElement.isInvisible(el)
       
 10318 					&& DomElement.getViewportBounds(el).intersects(
       
 10319 						DomElement.getBounds(el, true));
       
 10320 		},
       
 10321 
       
 10322 		getPrefixed: function(el, name) {
       
 10323 			return handlePrefix(el, name);
       
 10324 		},
       
 10325 
       
 10326 		setPrefixed: function(el, name, value) {
       
 10327 			if (typeof name === 'object') {
       
 10328 				for (var key in name)
       
 10329 					handlePrefix(el, key, true, name[key]);
       
 10330 			} else {
       
 10331 				handlePrefix(el, name, true, value);
       
 10332 			}
       
 10333 		}
       
 10334 	};
       
 10335 };
       
 10336 
       
 10337 var DomEvent = {
       
 10338 	add: function(el, events) {
       
 10339 		for (var type in events) {
       
 10340 			var func = events[type],
       
 10341 				parts = type.split(/[\s,]+/g);
       
 10342 			for (var i = 0, l = parts.length; i < l; i++)
       
 10343 				el.addEventListener(parts[i], func, false);
       
 10344 		}
       
 10345 	},
       
 10346 
       
 10347 	remove: function(el, events) {
       
 10348 		for (var type in events) {
       
 10349 			var func = events[type],
       
 10350 				parts = type.split(/[\s,]+/g);
       
 10351 			for (var i = 0, l = parts.length; i < l; i++)
       
 10352 				el.removeEventListener(parts[i], func, false);
       
 10353 		}
       
 10354 	},
       
 10355 
       
 10356 	getPoint: function(event) {
       
 10357 		var pos = event.targetTouches
       
 10358 				? event.targetTouches.length
       
 10359 					? event.targetTouches[0]
       
 10360 					: event.changedTouches[0]
       
 10361 				: event;
       
 10362 		return new Point(
       
 10363 			pos.pageX || pos.clientX + document.documentElement.scrollLeft,
       
 10364 			pos.pageY || pos.clientY + document.documentElement.scrollTop
       
 10365 		);
       
 10366 	},
       
 10367 
       
 10368 	getTarget: function(event) {
       
 10369 		return event.target || event.srcElement;
       
 10370 	},
       
 10371 
       
 10372 	getRelatedTarget: function(event) {
       
 10373 		return event.relatedTarget || event.toElement;
       
 10374 	},
       
 10375 
       
 10376 	getOffset: function(event, target) {
       
 10377 		return DomEvent.getPoint(event).subtract(DomElement.getOffset(
       
 10378 				target || DomEvent.getTarget(event)));
       
 10379 	},
       
 10380 
       
 10381 	stop: function(event) {
       
 10382 		event.stopPropagation();
       
 10383 		event.preventDefault();
       
 10384 	}
       
 10385 };
       
 10386 
       
 10387 DomEvent.requestAnimationFrame = new function() {
       
 10388 	var nativeRequest = DomElement.getPrefixed(window, 'requestAnimationFrame'),
       
 10389 		requested = false,
       
 10390 		callbacks = [],
       
 10391 		focused = true,
       
 10392 		timer;
       
 10393 
       
 10394 	DomEvent.add(window, {
       
 10395 		focus: function() {
       
 10396 			focused = true;
       
 10397 		},
       
 10398 		blur: function() {
       
 10399 			focused = false;
       
 10400 		}
       
 10401 	});
       
 10402 
       
 10403 	function handleCallbacks() {
       
 10404 		for (var i = callbacks.length - 1; i >= 0; i--) {
       
 10405 			var entry = callbacks[i],
       
 10406 				func = entry[0],
       
 10407 				el = entry[1];
       
 10408 			if (!el || (PaperScope.getAttribute(el, 'keepalive') == 'true'
       
 10409 					|| focused) && DomElement.isInView(el)) {
       
 10410 				callbacks.splice(i, 1);
       
 10411 				func();
       
 10412 			}
       
 10413 		}
       
 10414 		if (nativeRequest) {
       
 10415 			if (callbacks.length) {
       
 10416 				nativeRequest(handleCallbacks);
       
 10417 			} else {
       
 10418 				requested = false;
       
 10419 			}
       
 10420 		}
       
 10421 	}
       
 10422 
       
 10423 	return function(callback, element) {
       
 10424 		callbacks.push([callback, element]);
       
 10425 		if (nativeRequest) {
       
 10426 			if (!requested) {
       
 10427 				nativeRequest(handleCallbacks);
       
 10428 				requested = true;
       
 10429 			}
       
 10430 		} else if (!timer) {
       
 10431 			timer = setInterval(handleCallbacks, 1000 / 60);
       
 10432 		}
       
 10433 	};
       
 10434 };
       
 10435 
       
 10436 var View = Base.extend(Emitter, {
       
 10437 	_class: 'View',
       
 10438 
       
 10439 	initialize: function View(project, element) {
       
 10440 		this._project = project;
       
 10441 		this._scope = project._scope;
       
 10442 		this._element = element;
       
 10443 		var size;
       
 10444 		if (!this._pixelRatio)
       
 10445 			this._pixelRatio = window.devicePixelRatio || 1;
       
 10446 		this._id = element.getAttribute('id');
       
 10447 		if (this._id == null)
       
 10448 			element.setAttribute('id', this._id = 'view-' + View._id++);
       
 10449 		DomEvent.add(element, this._viewEvents);
       
 10450 		var none = 'none';
       
 10451 		DomElement.setPrefixed(element.style, {
       
 10452 			userSelect: none,
       
 10453 			touchAction: none,
       
 10454 			touchCallout: none,
       
 10455 			contentZooming: none,
       
 10456 			userDrag: none,
       
 10457 			tapHighlightColor: 'rgba(0,0,0,0)'
       
 10458 		});
       
 10459 
       
 10460 		function getSize(name) {
       
 10461 			return element[name] || parseInt(element.getAttribute(name), 10);
       
 10462 		};
       
 10463 
       
 10464 		function getCanvasSize() {
       
 10465 			var size = DomElement.getSize(element);
       
 10466 			return size.isNaN() || size.isZero()
       
 10467 					? new Size(getSize('width'), getSize('height'))
       
 10468 					: size;
       
 10469 		};
       
 10470 
       
 10471 		if (PaperScope.hasAttribute(element, 'resize')) {
       
 10472 			var that = this;
       
 10473 			DomEvent.add(window, this._windowEvents = {
       
 10474 				resize: function() {
       
 10475 					that.setViewSize(getCanvasSize());
       
 10476 				}
       
 10477 			});
       
 10478 		}
       
 10479 		this._setViewSize(size = getCanvasSize());
       
 10480 		if (PaperScope.hasAttribute(element, 'stats')
       
 10481 				&& typeof Stats !== 'undefined') {
       
 10482 			this._stats = new Stats();
       
 10483 			var stats = this._stats.domElement,
       
 10484 				style = stats.style,
       
 10485 				offset = DomElement.getOffset(element);
       
 10486 			style.position = 'absolute';
       
 10487 			style.left = offset.x + 'px';
       
 10488 			style.top = offset.y + 'px';
       
 10489 			document.body.appendChild(stats);
       
 10490 		}
       
 10491 		View._views.push(this);
       
 10492 		View._viewsById[this._id] = this;
       
 10493 		this._viewSize = size;
       
 10494 		(this._matrix = new Matrix())._owner = this;
       
 10495 		this._zoom = 1;
       
 10496 		if (!View._focused)
       
 10497 			View._focused = this;
       
 10498 		this._frameItems = {};
       
 10499 		this._frameItemCount = 0;
       
 10500 	},
       
 10501 
       
 10502 	remove: function() {
       
 10503 		if (!this._project)
       
 10504 			return false;
       
 10505 		if (View._focused === this)
       
 10506 			View._focused = null;
       
 10507 		View._views.splice(View._views.indexOf(this), 1);
       
 10508 		delete View._viewsById[this._id];
       
 10509 		if (this._project._view === this)
       
 10510 			this._project._view = null;
       
 10511 		DomEvent.remove(this._element, this._viewEvents);
       
 10512 		DomEvent.remove(window, this._windowEvents);
       
 10513 		this._element = this._project = null;
       
 10514 		this.off('frame');
       
 10515 		this._animate = false;
       
 10516 		this._frameItems = {};
       
 10517 		return true;
       
 10518 	},
       
 10519 
       
 10520 	_events: {
       
 10521 		onFrame: {
       
 10522 			install: function() {
       
 10523 				this.play();
       
 10524 			},
       
 10525 
       
 10526 			uninstall: function() {
       
 10527 				this.pause();
       
 10528 			}
       
 10529 		},
       
 10530 
       
 10531 		onResize: {}
       
 10532 	},
       
 10533 
       
 10534 	_animate: false,
       
 10535 	_time: 0,
       
 10536 	_count: 0,
       
 10537 
       
 10538 	_requestFrame: function() {
       
 10539 		var that = this;
       
 10540 		DomEvent.requestAnimationFrame(function() {
       
 10541 			that._requested = false;
       
 10542 			if (!that._animate)
       
 10543 				return;
       
 10544 			that._requestFrame();
       
 10545 			that._handleFrame();
       
 10546 		}, this._element);
       
 10547 		this._requested = true;
       
 10548 	},
       
 10549 
       
 10550 	_handleFrame: function() {
       
 10551 		paper = this._scope;
       
 10552 		var now = Date.now() / 1000,
       
 10553 			delta = this._before ? now - this._before : 0;
       
 10554 		this._before = now;
       
 10555 		this._handlingFrame = true;
       
 10556 		this.emit('frame', new Base({
       
 10557 			delta: delta,
       
 10558 			time: this._time += delta,
       
 10559 			count: this._count++
       
 10560 		}));
       
 10561 		if (this._stats)
       
 10562 			this._stats.update();
       
 10563 		this._handlingFrame = false;
       
 10564 		this.update();
       
 10565 	},
       
 10566 
       
 10567 	_animateItem: function(item, animate) {
       
 10568 		var items = this._frameItems;
       
 10569 		if (animate) {
       
 10570 			items[item._id] = {
       
 10571 				item: item,
       
 10572 				time: 0,
       
 10573 				count: 0
       
 10574 			};
       
 10575 			if (++this._frameItemCount === 1)
       
 10576 				this.on('frame', this._handleFrameItems);
       
 10577 		} else {
       
 10578 			delete items[item._id];
       
 10579 			if (--this._frameItemCount === 0) {
       
 10580 				this.off('frame', this._handleFrameItems);
       
 10581 			}
       
 10582 		}
       
 10583 	},
       
 10584 
       
 10585 	_handleFrameItems: function(event) {
       
 10586 		for (var i in this._frameItems) {
       
 10587 			var entry = this._frameItems[i];
       
 10588 			entry.item.emit('frame', new Base(event, {
       
 10589 				time: entry.time += event.delta,
       
 10590 				count: entry.count++
       
 10591 			}));
       
 10592 		}
       
 10593 	},
       
 10594 
       
 10595 	_update: function() {
       
 10596 		this._project._needsUpdate = true;
       
 10597 		if (this._handlingFrame)
       
 10598 			return;
       
 10599 		if (this._animate) {
       
 10600 			this._handleFrame();
       
 10601 		} else {
       
 10602 			this.update();
       
 10603 		}
       
 10604 	},
       
 10605 
       
 10606 	_changed: function(flags) {
       
 10607 		if (flags & 1)
       
 10608 			this._project._needsUpdate = true;
       
 10609 	},
       
 10610 
       
 10611 	_transform: function(matrix) {
       
 10612 		this._matrix.concatenate(matrix);
       
 10613 		this._bounds = null;
       
 10614 		this._update();
       
 10615 	},
       
 10616 
       
 10617 	getElement: function() {
       
 10618 		return this._element;
       
 10619 	},
       
 10620 
       
 10621 	getPixelRatio: function() {
       
 10622 		return this._pixelRatio;
       
 10623 	},
       
 10624 
       
 10625 	getResolution: function() {
       
 10626 		return this._pixelRatio * 72;
       
 10627 	},
       
 10628 
       
 10629 	getViewSize: function() {
       
 10630 		var size = this._viewSize;
       
 10631 		return new LinkedSize(size.width, size.height, this, 'setViewSize');
       
 10632 	},
       
 10633 
       
 10634 	setViewSize: function() {
       
 10635 		var size = Size.read(arguments),
       
 10636 			delta = size.subtract(this._viewSize);
       
 10637 		if (delta.isZero())
       
 10638 			return;
       
 10639 		this._viewSize.set(size.width, size.height);
       
 10640 		this._setViewSize(size);
       
 10641 		this._bounds = null;
       
 10642 		this.emit('resize', {
       
 10643 			size: size,
       
 10644 			delta: delta
       
 10645 		});
       
 10646 		this._update();
       
 10647 	},
       
 10648 
       
 10649 	_setViewSize: function(size) {
       
 10650 		var element = this._element;
       
 10651 		element.width = size.width;
       
 10652 		element.height = size.height;
       
 10653 	},
       
 10654 
       
 10655 	getBounds: function() {
       
 10656 		if (!this._bounds)
       
 10657 			this._bounds = this._matrix.inverted()._transformBounds(
       
 10658 					new Rectangle(new Point(), this._viewSize));
       
 10659 		return this._bounds;
       
 10660 	},
       
 10661 
       
 10662 	getSize: function() {
       
 10663 		return this.getBounds().getSize();
       
 10664 	},
       
 10665 
       
 10666 	getCenter: function() {
       
 10667 		return this.getBounds().getCenter();
       
 10668 	},
       
 10669 
       
 10670 	setCenter: function() {
       
 10671 		var center = Point.read(arguments);
       
 10672 		this.scrollBy(center.subtract(this.getCenter()));
       
 10673 	},
       
 10674 
       
 10675 	getZoom: function() {
       
 10676 		return this._zoom;
       
 10677 	},
       
 10678 
       
 10679 	setZoom: function(zoom) {
       
 10680 		this._transform(new Matrix().scale(zoom / this._zoom,
       
 10681 			this.getCenter()));
       
 10682 		this._zoom = zoom;
       
 10683 	},
       
 10684 
       
 10685 	isVisible: function() {
       
 10686 		return DomElement.isInView(this._element);
       
 10687 	},
       
 10688 
       
 10689 	scrollBy: function() {
       
 10690 		this._transform(new Matrix().translate(Point.read(arguments).negate()));
       
 10691 	},
       
 10692 
       
 10693 	play: function() {
       
 10694 		this._animate = true;
       
 10695 		if (!this._requested)
       
 10696 			this._requestFrame();
       
 10697 	},
       
 10698 
       
 10699 	pause: function() {
       
 10700 		this._animate = false;
       
 10701 	},
       
 10702 
       
 10703 	draw: function() {
       
 10704 		this.update();
       
 10705 	},
       
 10706 
       
 10707 	projectToView: function() {
       
 10708 		return this._matrix._transformPoint(Point.read(arguments));
       
 10709 	},
       
 10710 
       
 10711 	viewToProject: function() {
       
 10712 		return this._matrix._inverseTransform(Point.read(arguments));
       
 10713 	}
       
 10714 
       
 10715 }, {
       
 10716 	statics: {
       
 10717 		_views: [],
       
 10718 		_viewsById: {},
       
 10719 		_id: 0,
       
 10720 
       
 10721 		create: function(project, element) {
       
 10722 			if (typeof element === 'string')
       
 10723 				element = document.getElementById(element);
       
 10724 			return new CanvasView(project, element);
       
 10725 		}
       
 10726 	}
       
 10727 }, new function() {
       
 10728 	var tool,
       
 10729 		prevFocus,
       
 10730 		tempFocus,
       
 10731 		dragging = false;
       
 10732 
       
 10733 	function getView(event) {
       
 10734 		var target = DomEvent.getTarget(event);
       
 10735 		return target.getAttribute && View._viewsById[target.getAttribute('id')];
       
 10736 	}
       
 10737 
       
 10738 	function viewToProject(view, event) {
       
 10739 		return view.viewToProject(DomEvent.getOffset(event, view._element));
       
 10740 	}
       
 10741 
       
 10742 	function updateFocus() {
       
 10743 		if (!View._focused || !View._focused.isVisible()) {
       
 10744 			for (var i = 0, l = View._views.length; i < l; i++) {
       
 10745 				var view = View._views[i];
       
 10746 				if (view && view.isVisible()) {
       
 10747 					View._focused = tempFocus = view;
       
 10748 					break;
       
 10749 				}
       
 10750 			}
       
 10751 		}
       
 10752 	}
       
 10753 
       
 10754 	function handleMouseMove(view, point, event) {
       
 10755 		view._handleEvent('mousemove', point, event);
       
 10756 		var tool = view._scope.tool;
       
 10757 		if (tool) {
       
 10758 			tool._handleEvent(dragging && tool.responds('mousedrag')
       
 10759 					? 'mousedrag' : 'mousemove', point, event);
       
 10760 		}
       
 10761 		view.update();
       
 10762 		return tool;
       
 10763 	}
       
 10764 
       
 10765 	var navigator = window.navigator,
       
 10766 		mousedown, mousemove, mouseup;
       
 10767 	if (navigator.pointerEnabled || navigator.msPointerEnabled) {
       
 10768 		mousedown = 'pointerdown MSPointerDown';
       
 10769 		mousemove = 'pointermove MSPointerMove';
       
 10770 		mouseup = 'pointerup pointercancel MSPointerUp MSPointerCancel';
       
 10771 	} else {
       
 10772 		mousedown = 'touchstart';
       
 10773 		mousemove = 'touchmove';
       
 10774 		mouseup = 'touchend touchcancel';
       
 10775 		if (!('ontouchstart' in window && navigator.userAgent.match(
       
 10776 				/mobile|tablet|ip(ad|hone|od)|android|silk/i))) {
       
 10777 			mousedown += ' mousedown';
       
 10778 			mousemove += ' mousemove';
       
 10779 			mouseup += ' mouseup';
       
 10780 		}
       
 10781 	}
       
 10782 
       
 10783 	var viewEvents = {
       
 10784 		'selectstart dragstart': function(event) {
       
 10785 			if (dragging)
       
 10786 				event.preventDefault();
       
 10787 		}
       
 10788 	};
       
 10789 
       
 10790 	var docEvents = {
       
 10791 		mouseout: function(event) {
       
 10792 			var view = View._focused,
       
 10793 				target = DomEvent.getRelatedTarget(event);
       
 10794 			if (view && (!target || target.nodeName === 'HTML'))
       
 10795 				handleMouseMove(view, viewToProject(view, event), event);
       
 10796 		},
       
 10797 
       
 10798 		scroll: updateFocus
       
 10799 	};
       
 10800 
       
 10801 	viewEvents[mousedown] = function(event) {
       
 10802 		var view = View._focused = getView(event),
       
 10803 			point = viewToProject(view, event);
       
 10804 		dragging = true;
       
 10805 		view._handleEvent('mousedown', point, event);
       
 10806 		if (tool = view._scope.tool)
       
 10807 			tool._handleEvent('mousedown', point, event);
       
 10808 		view.update();
       
 10809 	};
       
 10810 
       
 10811 	docEvents[mousemove] = function(event) {
       
 10812 		var view = View._focused;
       
 10813 		if (!dragging) {
       
 10814 			var target = getView(event);
       
 10815 			if (target) {
       
 10816 				if (view !== target)
       
 10817 					handleMouseMove(view, viewToProject(view, event), event);
       
 10818 				prevFocus = view;
       
 10819 				view = View._focused = tempFocus = target;
       
 10820 			} else if (tempFocus && tempFocus === view) {
       
 10821 				view = View._focused = prevFocus;
       
 10822 				updateFocus();
       
 10823 			}
       
 10824 		}
       
 10825 		if (view) {
       
 10826 			var point = viewToProject(view, event);
       
 10827 			if (dragging || view.getBounds().contains(point))
       
 10828 				tool = handleMouseMove(view, point, event);
       
 10829 		}
       
 10830 	};
       
 10831 
       
 10832 	docEvents[mouseup] = function(event) {
       
 10833 		var view = View._focused;
       
 10834 		if (!view || !dragging)
       
 10835 			return;
       
 10836 		var point = viewToProject(view, event);
       
 10837 		dragging = false;
       
 10838 		view._handleEvent('mouseup', point, event);
       
 10839 		if (tool)
       
 10840 			tool._handleEvent('mouseup', point, event);
       
 10841 		view.update();
       
 10842 	};
       
 10843 
       
 10844 	DomEvent.add(document, docEvents);
       
 10845 
       
 10846 	DomEvent.add(window, {
       
 10847 		load: updateFocus
       
 10848 	});
       
 10849 
       
 10850 	return {
       
 10851 		_viewEvents: viewEvents,
       
 10852 
       
 10853 		_handleEvent: function() {},
       
 10854 
       
 10855 		statics: {
       
 10856 			updateFocus: updateFocus
       
 10857 		}
       
 10858 	};
       
 10859 });
       
 10860 
       
 10861 var CanvasView = View.extend({
       
 10862 	_class: 'CanvasView',
       
 10863 
       
 10864 	initialize: function CanvasView(project, canvas) {
       
 10865 		if (!(canvas instanceof HTMLCanvasElement)) {
       
 10866 			var size = Size.read(arguments, 1);
       
 10867 			if (size.isZero())
       
 10868 				throw new Error(
       
 10869 						'Cannot create CanvasView with the provided argument: '
       
 10870 						+ [].slice.call(arguments, 1));
       
 10871 			canvas = CanvasProvider.getCanvas(size);
       
 10872 		}
       
 10873 		this._context = canvas.getContext('2d');
       
 10874 		this._eventCounters = {};
       
 10875 		this._pixelRatio = 1;
       
 10876 		if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) {
       
 10877 			var deviceRatio = window.devicePixelRatio || 1,
       
 10878 				backingStoreRatio = DomElement.getPrefixed(this._context,
       
 10879 						'backingStorePixelRatio') || 1;
       
 10880 			this._pixelRatio = deviceRatio / backingStoreRatio;
       
 10881 		}
       
 10882 		View.call(this, project, canvas);
       
 10883 	},
       
 10884 
       
 10885 	_setViewSize: function(size) {
       
 10886 		var element = this._element,
       
 10887 			pixelRatio = this._pixelRatio,
       
 10888 			width = size.width,
       
 10889 			height = size.height;
       
 10890 		element.width = width * pixelRatio;
       
 10891 		element.height = height * pixelRatio;
       
 10892 		if (pixelRatio !== 1) {
       
 10893 			if (!PaperScope.hasAttribute(element, 'resize')) {
       
 10894 				var style = element.style;
       
 10895 				style.width = width + 'px';
       
 10896 				style.height = height + 'px';
       
 10897 			}
       
 10898 			this._context.scale(pixelRatio, pixelRatio);
       
 10899 		}
       
 10900 	},
       
 10901 
       
 10902 	getPixelSize: function(size) {
       
 10903 		var ctx = this._context,
       
 10904 			prevFont = ctx.font;
       
 10905 		ctx.font = size + ' serif';
       
 10906 		size = parseFloat(ctx.font);
       
 10907 		ctx.font = prevFont;
       
 10908 		return size;
       
 10909 	},
       
 10910 
       
 10911 	getTextWidth: function(font, lines) {
       
 10912 		var ctx = this._context,
       
 10913 			prevFont = ctx.font,
       
 10914 			width = 0;
       
 10915 		ctx.font = font;
       
 10916 		for (var i = 0, l = lines.length; i < l; i++)
       
 10917 			width = Math.max(width, ctx.measureText(lines[i]).width);
       
 10918 		ctx.font = prevFont;
       
 10919 		return width;
       
 10920 	},
       
 10921 
       
 10922 	update: function() {
       
 10923 		var project = this._project;
       
 10924 		if (!project || !project._needsUpdate)
       
 10925 			return false;
       
 10926 		var ctx = this._context,
       
 10927 			size = this._viewSize;
       
 10928 		ctx.clearRect(0, 0, size.width + 1, size.height + 1);
       
 10929 		project.draw(ctx, this._matrix, this._pixelRatio);
       
 10930 		project._needsUpdate = false;
       
 10931 		return true;
       
 10932 	}
       
 10933 }, new function() {
       
 10934 
       
 10935 	var downPoint,
       
 10936 		lastPoint,
       
 10937 		overPoint,
       
 10938 		downItem,
       
 10939 		lastItem,
       
 10940 		overItem,
       
 10941 		dragItem,
       
 10942 		dblClick,
       
 10943 		clickTime;
       
 10944 
       
 10945 	function callEvent(view, type, event, point, target, lastPoint) {
       
 10946 		var item = target,
       
 10947 			mouseEvent;
       
 10948 
       
 10949 		function call(obj) {
       
 10950 			if (obj.responds(type)) {
       
 10951 				if (!mouseEvent) {
       
 10952 					mouseEvent = new MouseEvent(type, event, point, target,
       
 10953 							lastPoint ? point.subtract(lastPoint) : null);
       
 10954 				}
       
 10955 				if (obj.emit(type, mouseEvent) && mouseEvent.isStopped) {
       
 10956 					event.preventDefault();
       
 10957 					return true;
       
 10958 				}
       
 10959 			}
       
 10960 		}
       
 10961 
       
 10962 		while (item) {
       
 10963 			if (call(item))
       
 10964 				return true;
       
 10965 			item = item.getParent();
       
 10966 		}
       
 10967 		if (call(view))
       
 10968 			return true;
       
 10969 		return false;
       
 10970 	}
       
 10971 
       
 10972 	return {
       
 10973 		_handleEvent: function(type, point, event) {
       
 10974 			if (!this._eventCounters[type])
       
 10975 				return;
       
 10976 			var project = this._project,
       
 10977 				hit = project.hitTest(point, {
       
 10978 					tolerance: 0,
       
 10979 					fill: true,
       
 10980 					stroke: true
       
 10981 				}),
       
 10982 				item = hit && hit.item,
       
 10983 				stopped = false;
       
 10984 			switch (type) {
       
 10985 			case 'mousedown':
       
 10986 				stopped = callEvent(this, type, event, point, item);
       
 10987 				dblClick = lastItem == item && (Date.now() - clickTime < 300);
       
 10988 				downItem = lastItem = item;
       
 10989 				downPoint = lastPoint = overPoint = point;
       
 10990 				dragItem = !stopped && item;
       
 10991 				while (dragItem && !dragItem.responds('mousedrag'))
       
 10992 					dragItem = dragItem._parent;
       
 10993 				break;
       
 10994 			case 'mouseup':
       
 10995 				stopped = callEvent(this, type, event, point, item, downPoint);
       
 10996 				if (dragItem) {
       
 10997 					if (lastPoint && !lastPoint.equals(point))
       
 10998 						callEvent(this, 'mousedrag', event, point, dragItem,
       
 10999 								lastPoint);
       
 11000 					if (item !== dragItem) {
       
 11001 						overPoint = point;
       
 11002 						callEvent(this, 'mousemove', event, point, item,
       
 11003 								overPoint);
       
 11004 					}
       
 11005 				}
       
 11006 				if (!stopped && item && item === downItem) {
       
 11007 					clickTime = Date.now();
       
 11008 					callEvent(this, dblClick && downItem.responds('doubleclick')
       
 11009 							? 'doubleclick' : 'click', event, downPoint, item);
       
 11010 					dblClick = false;
       
 11011 				}
       
 11012 				downItem = dragItem = null;
       
 11013 				break;
       
 11014 			case 'mousemove':
       
 11015 				if (dragItem)
       
 11016 					stopped = callEvent(this, 'mousedrag', event, point,
       
 11017 							dragItem, lastPoint);
       
 11018 				if (!stopped) {
       
 11019 					if (item !== overItem)
       
 11020 						overPoint = point;
       
 11021 					stopped = callEvent(this, type, event, point, item,
       
 11022 							overPoint);
       
 11023 				}
       
 11024 				lastPoint = overPoint = point;
       
 11025 				if (item !== overItem) {
       
 11026 					callEvent(this, 'mouseleave', event, point, overItem);
       
 11027 					overItem = item;
       
 11028 					callEvent(this, 'mouseenter', event, point, item);
       
 11029 				}
       
 11030 				break;
       
 11031 			}
       
 11032 			return stopped;
       
 11033 		}
       
 11034 	};
       
 11035 });
       
 11036 
       
 11037 var Event = Base.extend({
       
 11038 	_class: 'Event',
       
 11039 
       
 11040 	initialize: function Event(event) {
       
 11041 		this.event = event;
       
 11042 	},
       
 11043 
       
 11044 	isPrevented: false,
       
 11045 	isStopped: false,
       
 11046 
       
 11047 	preventDefault: function() {
       
 11048 		this.isPrevented = true;
       
 11049 		this.event.preventDefault();
       
 11050 	},
       
 11051 
       
 11052 	stopPropagation: function() {
       
 11053 		this.isStopped = true;
       
 11054 		this.event.stopPropagation();
       
 11055 	},
       
 11056 
       
 11057 	stop: function() {
       
 11058 		this.stopPropagation();
       
 11059 		this.preventDefault();
       
 11060 	},
       
 11061 
       
 11062 	getModifiers: function() {
       
 11063 		return Key.modifiers;
       
 11064 	}
       
 11065 });
       
 11066 
       
 11067 var KeyEvent = Event.extend({
       
 11068 	_class: 'KeyEvent',
       
 11069 
       
 11070 	initialize: function KeyEvent(down, key, character, event) {
       
 11071 		Event.call(this, event);
       
 11072 		this.type = down ? 'keydown' : 'keyup';
       
 11073 		this.key = key;
       
 11074 		this.character = character;
       
 11075 	},
       
 11076 
       
 11077 	toString: function() {
       
 11078 		return "{ type: '" + this.type
       
 11079 				+ "', key: '" + this.key
       
 11080 				+ "', character: '" + this.character
       
 11081 				+ "', modifiers: " + this.getModifiers()
       
 11082 				+ " }";
       
 11083 	}
       
 11084 });
       
 11085 
       
 11086 var Key = new function() {
       
 11087 
       
 11088 	var specialKeys = {
       
 11089 		8: 'backspace',
       
 11090 		9: 'tab',
       
 11091 		13: 'enter',
       
 11092 		16: 'shift',
       
 11093 		17: 'control',
       
 11094 		18: 'option',
       
 11095 		19: 'pause',
       
 11096 		20: 'caps-lock',
       
 11097 		27: 'escape',
       
 11098 		32: 'space',
       
 11099 		35: 'end',
       
 11100 		36: 'home',
       
 11101 		37: 'left',
       
 11102 		38: 'up',
       
 11103 		39: 'right',
       
 11104 		40: 'down',
       
 11105 		46: 'delete',
       
 11106 		91: 'command',
       
 11107 		93: 'command',
       
 11108 		224: 'command'
       
 11109 	},
       
 11110 
       
 11111 	specialChars = {
       
 11112 		9: true,
       
 11113 		13: true,
       
 11114 		32: true
       
 11115 	},
       
 11116 
       
 11117 	modifiers = new Base({
       
 11118 		shift: false,
       
 11119 		control: false,
       
 11120 		option: false,
       
 11121 		command: false,
       
 11122 		capsLock: false,
       
 11123 		space: false
       
 11124 	}),
       
 11125 
       
 11126 	charCodeMap = {},
       
 11127 	keyMap = {},
       
 11128 	downCode;
       
 11129 
       
 11130 	function handleKey(down, keyCode, charCode, event) {
       
 11131 		var character = charCode ? String.fromCharCode(charCode) : '',
       
 11132 			specialKey = specialKeys[keyCode],
       
 11133 			key = specialKey || character.toLowerCase(),
       
 11134 			type = down ? 'keydown' : 'keyup',
       
 11135 			view = View._focused,
       
 11136 			scope = view && view.isVisible() && view._scope,
       
 11137 			tool = scope && scope.tool,
       
 11138 			name;
       
 11139 		keyMap[key] = down;
       
 11140 		if (specialKey && (name = Base.camelize(specialKey)) in modifiers)
       
 11141 			modifiers[name] = down;
       
 11142 		if (down) {
       
 11143 			charCodeMap[keyCode] = charCode;
       
 11144 		} else {
       
 11145 			delete charCodeMap[keyCode];
       
 11146 		}
       
 11147 		if (tool && tool.responds(type)) {
       
 11148 			paper = scope;
       
 11149 			tool.emit(type, new KeyEvent(down, key, character, event));
       
 11150 			if (view)
       
 11151 				view.update();
       
 11152 		}
       
 11153 	}
       
 11154 
       
 11155 	DomEvent.add(document, {
       
 11156 		keydown: function(event) {
       
 11157 			var code = event.which || event.keyCode;
       
 11158 			if (code in specialKeys || modifiers.command) {
       
 11159 				handleKey(true, code,
       
 11160 						code in specialChars || modifiers.command ? code : 0,
       
 11161 						event);
       
 11162 			} else {
       
 11163 				downCode = code;
       
 11164 			}
       
 11165 		},
       
 11166 
       
 11167 		keypress: function(event) {
       
 11168 			if (downCode != null) {
       
 11169 				handleKey(true, downCode, event.which || event.keyCode, event);
       
 11170 				downCode = null;
       
 11171 			}
       
 11172 		},
       
 11173 
       
 11174 		keyup: function(event) {
       
 11175 			var code = event.which || event.keyCode;
       
 11176 			if (code in charCodeMap)
       
 11177 				handleKey(false, code, charCodeMap[code], event);
       
 11178 		}
       
 11179 	});
       
 11180 
       
 11181 	DomEvent.add(window, {
       
 11182 		blur: function(event) {
       
 11183 			for (var code in charCodeMap)
       
 11184 				handleKey(false, code, charCodeMap[code], event);
       
 11185 		}
       
 11186 	});
       
 11187 
       
 11188 	return {
       
 11189 		modifiers: modifiers,
       
 11190 
       
 11191 		isDown: function(key) {
       
 11192 			return !!keyMap[key];
       
 11193 		}
       
 11194 	};
       
 11195 };
       
 11196 
       
 11197 var MouseEvent = Event.extend({
       
 11198 	_class: 'MouseEvent',
       
 11199 
       
 11200 	initialize: function MouseEvent(type, event, point, target, delta) {
       
 11201 		Event.call(this, event);
       
 11202 		this.type = type;
       
 11203 		this.point = point;
       
 11204 		this.target = target;
       
 11205 		this.delta = delta;
       
 11206 	},
       
 11207 
       
 11208 	toString: function() {
       
 11209 		return "{ type: '" + this.type
       
 11210 				+ "', point: " + this.point
       
 11211 				+ ', target: ' + this.target
       
 11212 				+ (this.delta ? ', delta: ' + this.delta : '')
       
 11213 				+ ', modifiers: ' + this.getModifiers()
       
 11214 				+ ' }';
       
 11215 	}
       
 11216 });
       
 11217 
       
 11218 var ToolEvent = Event.extend({
       
 11219 	_class: 'ToolEvent',
       
 11220 	_item: null,
       
 11221 
       
 11222 	initialize: function ToolEvent(tool, type, event) {
       
 11223 		this.tool = tool;
       
 11224 		this.type = type;
       
 11225 		this.event = event;
       
 11226 	},
       
 11227 
       
 11228 	_choosePoint: function(point, toolPoint) {
       
 11229 		return point ? point : toolPoint ? toolPoint.clone() : null;
       
 11230 	},
       
 11231 
       
 11232 	getPoint: function() {
       
 11233 		return this._choosePoint(this._point, this.tool._point);
       
 11234 	},
       
 11235 
       
 11236 	setPoint: function(point) {
       
 11237 		this._point = point;
       
 11238 	},
       
 11239 
       
 11240 	getLastPoint: function() {
       
 11241 		return this._choosePoint(this._lastPoint, this.tool._lastPoint);
       
 11242 	},
       
 11243 
       
 11244 	setLastPoint: function(lastPoint) {
       
 11245 		this._lastPoint = lastPoint;
       
 11246 	},
       
 11247 
       
 11248 	getDownPoint: function() {
       
 11249 		return this._choosePoint(this._downPoint, this.tool._downPoint);
       
 11250 	},
       
 11251 
       
 11252 	setDownPoint: function(downPoint) {
       
 11253 		this._downPoint = downPoint;
       
 11254 	},
       
 11255 
       
 11256 	getMiddlePoint: function() {
       
 11257 		if (!this._middlePoint && this.tool._lastPoint) {
       
 11258 			return this.tool._point.add(this.tool._lastPoint).divide(2);
       
 11259 		}
       
 11260 		return this._middlePoint;
       
 11261 	},
       
 11262 
       
 11263 	setMiddlePoint: function(middlePoint) {
       
 11264 		this._middlePoint = middlePoint;
       
 11265 	},
       
 11266 
       
 11267 	getDelta: function() {
       
 11268 		return !this._delta && this.tool._lastPoint
       
 11269 				? this.tool._point.subtract(this.tool._lastPoint)
       
 11270 				: this._delta;
       
 11271 	},
       
 11272 
       
 11273 	setDelta: function(delta) {
       
 11274 		this._delta = delta;
       
 11275 	},
       
 11276 
       
 11277 	getCount: function() {
       
 11278 		return /^mouse(down|up)$/.test(this.type)
       
 11279 				? this.tool._downCount
       
 11280 				: this.tool._count;
       
 11281 	},
       
 11282 
       
 11283 	setCount: function(count) {
       
 11284 		this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count']
       
 11285 			= count;
       
 11286 	},
       
 11287 
       
 11288 	getItem: function() {
       
 11289 		if (!this._item) {
       
 11290 			var result = this.tool._scope.project.hitTest(this.getPoint());
       
 11291 			if (result) {
       
 11292 				var item = result.item,
       
 11293 					parent = item._parent;
       
 11294 				while (/^(Group|CompoundPath)$/.test(parent._class)) {
       
 11295 					item = parent;
       
 11296 					parent = parent._parent;
       
 11297 				}
       
 11298 				this._item = item;
       
 11299 			}
       
 11300 		}
       
 11301 		return this._item;
       
 11302 	},
       
 11303 
       
 11304 	setItem: function(item) {
       
 11305 		this._item = item;
       
 11306 	},
       
 11307 
       
 11308 	toString: function() {
       
 11309 		return '{ type: ' + this.type
       
 11310 				+ ', point: ' + this.getPoint()
       
 11311 				+ ', count: ' + this.getCount()
       
 11312 				+ ', modifiers: ' + this.getModifiers()
       
 11313 				+ ' }';
       
 11314 	}
       
 11315 });
       
 11316 
       
 11317 var Tool = PaperScopeItem.extend({
       
 11318 	_class: 'Tool',
       
 11319 	_list: 'tools',
       
 11320 	_reference: 'tool',
       
 11321 	_events: [ 'onActivate', 'onDeactivate', 'onEditOptions',
       
 11322 			'onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove',
       
 11323 			'onKeyDown', 'onKeyUp' ],
       
 11324 
       
 11325 	initialize: function Tool(props) {
       
 11326 		PaperScopeItem.call(this);
       
 11327 		this._firstMove = true;
       
 11328 		this._count = 0;
       
 11329 		this._downCount = 0;
       
 11330 		this._set(props);
       
 11331 	},
       
 11332 
       
 11333 	getMinDistance: function() {
       
 11334 		return this._minDistance;
       
 11335 	},
       
 11336 
       
 11337 	setMinDistance: function(minDistance) {
       
 11338 		this._minDistance = minDistance;
       
 11339 		if (this._minDistance != null && this._maxDistance != null
       
 11340 				&& this._minDistance > this._maxDistance) {
       
 11341 			this._maxDistance = this._minDistance;
       
 11342 		}
       
 11343 	},
       
 11344 
       
 11345 	getMaxDistance: function() {
       
 11346 		return this._maxDistance;
       
 11347 	},
       
 11348 
       
 11349 	setMaxDistance: function(maxDistance) {
       
 11350 		this._maxDistance = maxDistance;
       
 11351 		if (this._minDistance != null && this._maxDistance != null
       
 11352 				&& this._maxDistance < this._minDistance) {
       
 11353 			this._minDistance = maxDistance;
       
 11354 		}
       
 11355 	},
       
 11356 
       
 11357 	getFixedDistance: function() {
       
 11358 		return this._minDistance == this._maxDistance
       
 11359 			? this._minDistance : null;
       
 11360 	},
       
 11361 
       
 11362 	setFixedDistance: function(distance) {
       
 11363 		this._minDistance = distance;
       
 11364 		this._maxDistance = distance;
       
 11365 	},
       
 11366 
       
 11367 	_updateEvent: function(type, point, minDistance, maxDistance, start,
       
 11368 			needsChange, matchMaxDistance) {
       
 11369 		if (!start) {
       
 11370 			if (minDistance != null || maxDistance != null) {
       
 11371 				var minDist = minDistance != null ? minDistance : 0,
       
 11372 					vector = point.subtract(this._point),
       
 11373 					distance = vector.getLength();
       
 11374 				if (distance < minDist)
       
 11375 					return false;
       
 11376 				var maxDist = maxDistance != null ? maxDistance : 0;
       
 11377 				if (maxDist != 0) {
       
 11378 					if (distance > maxDist) {
       
 11379 						point = this._point.add(vector.normalize(maxDist));
       
 11380 					} else if (matchMaxDistance) {
       
 11381 						return false;
       
 11382 					}
       
 11383 				}
       
 11384 			}
       
 11385 			if (needsChange && point.equals(this._point))
       
 11386 				return false;
       
 11387 		}
       
 11388 		this._lastPoint = start && type == 'mousemove' ? point : this._point;
       
 11389 		this._point = point;
       
 11390 		switch (type) {
       
 11391 		case 'mousedown':
       
 11392 			this._lastPoint = this._downPoint;
       
 11393 			this._downPoint = this._point;
       
 11394 			this._downCount++;
       
 11395 			break;
       
 11396 		case 'mouseup':
       
 11397 			this._lastPoint = this._downPoint;
       
 11398 			break;
       
 11399 		}
       
 11400 		this._count = start ? 0 : this._count + 1;
       
 11401 		return true;
       
 11402 	},
       
 11403 
       
 11404 	_fireEvent: function(type, event) {
       
 11405 		var sets = paper.project._removeSets;
       
 11406 		if (sets) {
       
 11407 			if (type === 'mouseup')
       
 11408 				sets.mousedrag = null;
       
 11409 			var set = sets[type];
       
 11410 			if (set) {
       
 11411 				for (var id in set) {
       
 11412 					var item = set[id];
       
 11413 					for (var key in sets) {
       
 11414 						var other = sets[key];
       
 11415 						if (other && other != set)
       
 11416 							delete other[item._id];
       
 11417 					}
       
 11418 					item.remove();
       
 11419 				}
       
 11420 				sets[type] = null;
       
 11421 			}
       
 11422 		}
       
 11423 		return this.responds(type)
       
 11424 				&& this.emit(type, new ToolEvent(this, type, event));
       
 11425 	},
       
 11426 
       
 11427 	_handleEvent: function(type, point, event) {
       
 11428 		paper = this._scope;
       
 11429 		var called = false;
       
 11430 		switch (type) {
       
 11431 		case 'mousedown':
       
 11432 			this._updateEvent(type, point, null, null, true, false, false);
       
 11433 			called = this._fireEvent(type, event);
       
 11434 			break;
       
 11435 		case 'mousedrag':
       
 11436 			var needsChange = false,
       
 11437 				matchMaxDistance = false;
       
 11438 			while (this._updateEvent(type, point, this.minDistance,
       
 11439 					this.maxDistance, false, needsChange, matchMaxDistance)) {
       
 11440 				called = this._fireEvent(type, event) || called;
       
 11441 				needsChange = true;
       
 11442 				matchMaxDistance = true;
       
 11443 			}
       
 11444 			break;
       
 11445 		case 'mouseup':
       
 11446 			if (!point.equals(this._point)
       
 11447 					&& this._updateEvent('mousedrag', point, this.minDistance,
       
 11448 							this.maxDistance, false, false, false)) {
       
 11449 				called = this._fireEvent('mousedrag', event);
       
 11450 			}
       
 11451 			this._updateEvent(type, point, null, this.maxDistance, false,
       
 11452 					false, false);
       
 11453 			called = this._fireEvent(type, event) || called;
       
 11454 			this._updateEvent(type, point, null, null, true, false, false);
       
 11455 			this._firstMove = true;
       
 11456 			break;
       
 11457 		case 'mousemove':
       
 11458 			while (this._updateEvent(type, point, this.minDistance,
       
 11459 					this.maxDistance, this._firstMove, true, false)) {
       
 11460 				called = this._fireEvent(type, event) || called;
       
 11461 				this._firstMove = false;
       
 11462 			}
       
 11463 			break;
       
 11464 		}
       
 11465 		if (called)
       
 11466 			event.preventDefault();
       
 11467 		return called;
       
 11468 	}
       
 11469 
       
 11470 });
       
 11471 
       
 11472 var Http = {
       
 11473 	request: function(method, url, callback) {
       
 11474 		var xhr = new (window.ActiveXObject || XMLHttpRequest)(
       
 11475 					'Microsoft.XMLHTTP');
       
 11476 		xhr.open(method.toUpperCase(), url, true);
       
 11477 		if ('overrideMimeType' in xhr)
       
 11478 			xhr.overrideMimeType('text/plain');
       
 11479 		xhr.onreadystatechange = function() {
       
 11480 			if (xhr.readyState === 4) {
       
 11481 				var status = xhr.status;
       
 11482 				if (status === 0 || status === 200) {
       
 11483 					callback.call(xhr, xhr.responseText);
       
 11484 				} else {
       
 11485 					throw new Error('Could not load ' + url + ' (Error '
       
 11486 							+ status + ')');
       
 11487 				}
       
 11488 			}
       
 11489 		};
       
 11490 		return xhr.send(null);
       
 11491 	}
       
 11492 };
       
 11493 
       
 11494 var CanvasProvider = {
       
 11495 	canvases: [],
       
 11496 
       
 11497 	getCanvas: function(width, height) {
       
 11498 		var canvas,
       
 11499 			clear = true;
       
 11500 		if (typeof width === 'object') {
       
 11501 			height = width.height;
       
 11502 			width = width.width;
       
 11503 		}
       
 11504 		if (this.canvases.length) {
       
 11505 			canvas = this.canvases.pop();
       
 11506 		} else {
       
 11507 			canvas = document.createElement('canvas');
       
 11508 		}
       
 11509 		var ctx = canvas.getContext('2d');
       
 11510 		if (canvas.width === width && canvas.height === height) {
       
 11511 			if (clear)
       
 11512 				ctx.clearRect(0, 0, width + 1, height + 1);
       
 11513 		} else {
       
 11514 			canvas.width = width;
       
 11515 			canvas.height = height;
       
 11516 		}
       
 11517 		ctx.save();
       
 11518 		return canvas;
       
 11519 	},
       
 11520 
       
 11521 	getContext: function(width, height) {
       
 11522 		return this.getCanvas(width, height).getContext('2d');
       
 11523 	},
       
 11524 
       
 11525 	release: function(obj) {
       
 11526 		var canvas = obj.canvas ? obj.canvas : obj;
       
 11527 		canvas.getContext('2d').restore();
       
 11528 		this.canvases.push(canvas);
       
 11529 	}
       
 11530 };
       
 11531 
       
 11532 var BlendMode = new function() {
       
 11533 	var min = Math.min,
       
 11534 		max = Math.max,
       
 11535 		abs = Math.abs,
       
 11536 		sr, sg, sb, sa,
       
 11537 		br, bg, bb, ba,
       
 11538 		dr, dg, db;
       
 11539 
       
 11540 	function getLum(r, g, b) {
       
 11541 		return 0.2989 * r + 0.587 * g + 0.114 * b;
       
 11542 	}
       
 11543 
       
 11544 	function setLum(r, g, b, l) {
       
 11545 		var d = l - getLum(r, g, b);
       
 11546 		dr = r + d;
       
 11547 		dg = g + d;
       
 11548 		db = b + d;
       
 11549 		var l = getLum(dr, dg, db),
       
 11550 			mn = min(dr, dg, db),
       
 11551 			mx = max(dr, dg, db);
       
 11552 		if (mn < 0) {
       
 11553 			var lmn = l - mn;
       
 11554 			dr = l + (dr - l) * l / lmn;
       
 11555 			dg = l + (dg - l) * l / lmn;
       
 11556 			db = l + (db - l) * l / lmn;
       
 11557 		}
       
 11558 		if (mx > 255) {
       
 11559 			var ln = 255 - l,
       
 11560 				mxl = mx - l;
       
 11561 			dr = l + (dr - l) * ln / mxl;
       
 11562 			dg = l + (dg - l) * ln / mxl;
       
 11563 			db = l + (db - l) * ln / mxl;
       
 11564 		}
       
 11565 	}
       
 11566 
       
 11567 	function getSat(r, g, b) {
       
 11568 		return max(r, g, b) - min(r, g, b);
       
 11569 	}
       
 11570 
       
 11571 	function setSat(r, g, b, s) {
       
 11572 		var col = [r, g, b],
       
 11573 			mx = max(r, g, b),
       
 11574 			mn = min(r, g, b),
       
 11575 			md;
       
 11576 		mn = mn === r ? 0 : mn === g ? 1 : 2;
       
 11577 		mx = mx === r ? 0 : mx === g ? 1 : 2;
       
 11578 		md = min(mn, mx) === 0 ? max(mn, mx) === 1 ? 2 : 1 : 0;
       
 11579 		if (col[mx] > col[mn]) {
       
 11580 			col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]);
       
 11581 			col[mx] = s;
       
 11582 		} else {
       
 11583 			col[md] = col[mx] = 0;
       
 11584 		}
       
 11585 		col[mn] = 0;
       
 11586 		dr = col[0];
       
 11587 		dg = col[1];
       
 11588 		db = col[2];
       
 11589 	}
       
 11590 
       
 11591 	var modes = {
       
 11592 		multiply: function() {
       
 11593 			dr = br * sr / 255;
       
 11594 			dg = bg * sg / 255;
       
 11595 			db = bb * sb / 255;
       
 11596 		},
       
 11597 
       
 11598 		screen: function() {
       
 11599 			dr = br + sr - (br * sr / 255);
       
 11600 			dg = bg + sg - (bg * sg / 255);
       
 11601 			db = bb + sb - (bb * sb / 255);
       
 11602 		},
       
 11603 
       
 11604 		overlay: function() {
       
 11605 			dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255;
       
 11606 			dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255;
       
 11607 			db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255;
       
 11608 		},
       
 11609 
       
 11610 		'soft-light': function() {
       
 11611 			var t = sr * br / 255;
       
 11612 			dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255;
       
 11613 			t = sg * bg / 255;
       
 11614 			dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255;
       
 11615 			t = sb * bb / 255;
       
 11616 			db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255;
       
 11617 		},
       
 11618 
       
 11619 		'hard-light': function() {
       
 11620 			dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255;
       
 11621 			dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255;
       
 11622 			db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255;
       
 11623 		},
       
 11624 
       
 11625 		'color-dodge': function() {
       
 11626 			dr = br === 0 ? 0 : sr === 255 ? 255 : min(255, 255 * br / (255 - sr));
       
 11627 			dg = bg === 0 ? 0 : sg === 255 ? 255 : min(255, 255 * bg / (255 - sg));
       
 11628 			db = bb === 0 ? 0 : sb === 255 ? 255 : min(255, 255 * bb / (255 - sb));
       
 11629 		},
       
 11630 
       
 11631 		'color-burn': function() {
       
 11632 			dr = br === 255 ? 255 : sr === 0 ? 0 : max(0, 255 - (255 - br) * 255 / sr);
       
 11633 			dg = bg === 255 ? 255 : sg === 0 ? 0 : max(0, 255 - (255 - bg) * 255 / sg);
       
 11634 			db = bb === 255 ? 255 : sb === 0 ? 0 : max(0, 255 - (255 - bb) * 255 / sb);
       
 11635 		},
       
 11636 
       
 11637 		darken: function() {
       
 11638 			dr = br < sr ? br : sr;
       
 11639 			dg = bg < sg ? bg : sg;
       
 11640 			db = bb < sb ? bb : sb;
       
 11641 		},
       
 11642 
       
 11643 		lighten: function() {
       
 11644 			dr = br > sr ? br : sr;
       
 11645 			dg = bg > sg ? bg : sg;
       
 11646 			db = bb > sb ? bb : sb;
       
 11647 		},
       
 11648 
       
 11649 		difference: function() {
       
 11650 			dr = br - sr;
       
 11651 			if (dr < 0)
       
 11652 				dr = -dr;
       
 11653 			dg = bg - sg;
       
 11654 			if (dg < 0)
       
 11655 				dg = -dg;
       
 11656 			db = bb - sb;
       
 11657 			if (db < 0)
       
 11658 				db = -db;
       
 11659 		},
       
 11660 
       
 11661 		exclusion: function() {
       
 11662 			dr = br + sr * (255 - br - br) / 255;
       
 11663 			dg = bg + sg * (255 - bg - bg) / 255;
       
 11664 			db = bb + sb * (255 - bb - bb) / 255;
       
 11665 		},
       
 11666 
       
 11667 		hue: function() {
       
 11668 			setSat(sr, sg, sb, getSat(br, bg, bb));
       
 11669 			setLum(dr, dg, db, getLum(br, bg, bb));
       
 11670 		},
       
 11671 
       
 11672 		saturation: function() {
       
 11673 			setSat(br, bg, bb, getSat(sr, sg, sb));
       
 11674 			setLum(dr, dg, db, getLum(br, bg, bb));
       
 11675 		},
       
 11676 
       
 11677 		luminosity: function() {
       
 11678 			setLum(br, bg, bb, getLum(sr, sg, sb));
       
 11679 		},
       
 11680 
       
 11681 		color: function() {
       
 11682 			setLum(sr, sg, sb, getLum(br, bg, bb));
       
 11683 		},
       
 11684 
       
 11685 		add: function() {
       
 11686 			dr = min(br + sr, 255);
       
 11687 			dg = min(bg + sg, 255);
       
 11688 			db = min(bb + sb, 255);
       
 11689 		},
       
 11690 
       
 11691 		subtract: function() {
       
 11692 			dr = max(br - sr, 0);
       
 11693 			dg = max(bg - sg, 0);
       
 11694 			db = max(bb - sb, 0);
       
 11695 		},
       
 11696 
       
 11697 		average: function() {
       
 11698 			dr = (br + sr) / 2;
       
 11699 			dg = (bg + sg) / 2;
       
 11700 			db = (bb + sb) / 2;
       
 11701 		},
       
 11702 
       
 11703 		negation: function() {
       
 11704 			dr = 255 - abs(255 - sr - br);
       
 11705 			dg = 255 - abs(255 - sg - bg);
       
 11706 			db = 255 - abs(255 - sb - bb);
       
 11707 		}
       
 11708 	};
       
 11709 
       
 11710 	var nativeModes = this.nativeModes = Base.each([
       
 11711 		'source-over', 'source-in', 'source-out', 'source-atop',
       
 11712 		'destination-over', 'destination-in', 'destination-out',
       
 11713 		'destination-atop', 'lighter', 'darker', 'copy', 'xor'
       
 11714 	], function(mode) {
       
 11715 		this[mode] = true;
       
 11716 	}, {});
       
 11717 
       
 11718 	var ctx = CanvasProvider.getContext(1, 1);
       
 11719 	Base.each(modes, function(func, mode) {
       
 11720 		var darken = mode === 'darken',
       
 11721 			ok = false;
       
 11722 		ctx.save();
       
 11723 		try {
       
 11724 			ctx.fillStyle = darken ? '#300' : '#a00';
       
 11725 			ctx.fillRect(0, 0, 1, 1);
       
 11726 			ctx.globalCompositeOperation = mode;
       
 11727 			if (ctx.globalCompositeOperation === mode) {
       
 11728 				ctx.fillStyle = darken ? '#a00' : '#300';
       
 11729 				ctx.fillRect(0, 0, 1, 1);
       
 11730 				ok = ctx.getImageData(0, 0, 1, 1).data[0] !== darken ? 170 : 51;
       
 11731 			}
       
 11732 		} catch (e) {}
       
 11733 		ctx.restore();
       
 11734 		nativeModes[mode] = ok;
       
 11735 	});
       
 11736 	CanvasProvider.release(ctx);
       
 11737 
       
 11738 	this.process = function(mode, srcContext, dstContext, alpha, offset) {
       
 11739 		var srcCanvas = srcContext.canvas,
       
 11740 			normal = mode === 'normal';
       
 11741 		if (normal || nativeModes[mode]) {
       
 11742 			dstContext.save();
       
 11743 			dstContext.setTransform(1, 0, 0, 1, 0, 0);
       
 11744 			dstContext.globalAlpha = alpha;
       
 11745 			if (!normal)
       
 11746 				dstContext.globalCompositeOperation = mode;
       
 11747 			dstContext.drawImage(srcCanvas, offset.x, offset.y);
       
 11748 			dstContext.restore();
       
 11749 		} else {
       
 11750 			var process = modes[mode];
       
 11751 			if (!process)
       
 11752 				return;
       
 11753 			var dstData = dstContext.getImageData(offset.x, offset.y,
       
 11754 					srcCanvas.width, srcCanvas.height),
       
 11755 				dst = dstData.data,
       
 11756 				src = srcContext.getImageData(0, 0,
       
 11757 					srcCanvas.width, srcCanvas.height).data;
       
 11758 			for (var i = 0, l = dst.length; i < l; i += 4) {
       
 11759 				sr = src[i];
       
 11760 				br = dst[i];
       
 11761 				sg = src[i + 1];
       
 11762 				bg = dst[i + 1];
       
 11763 				sb = src[i + 2];
       
 11764 				bb = dst[i + 2];
       
 11765 				sa = src[i + 3];
       
 11766 				ba = dst[i + 3];
       
 11767 				process();
       
 11768 				var a1 = sa * alpha / 255,
       
 11769 					a2 = 1 - a1;
       
 11770 				dst[i] = a1 * dr + a2 * br;
       
 11771 				dst[i + 1] = a1 * dg + a2 * bg;
       
 11772 				dst[i + 2] = a1 * db + a2 * bb;
       
 11773 				dst[i + 3] = sa * alpha + a2 * ba;
       
 11774 			}
       
 11775 			dstContext.putImageData(dstData, offset.x, offset.y);
       
 11776 		}
       
 11777 	};
       
 11778 };
       
 11779 
       
 11780 var SVGStyles = Base.each({
       
 11781 	fillColor: ['fill', 'color'],
       
 11782 	strokeColor: ['stroke', 'color'],
       
 11783 	strokeWidth: ['stroke-width', 'number'],
       
 11784 	strokeCap: ['stroke-linecap', 'string'],
       
 11785 	strokeJoin: ['stroke-linejoin', 'string'],
       
 11786 	strokeScaling: ['vector-effect', 'lookup', {
       
 11787 		true: 'none',
       
 11788 		false: 'non-scaling-stroke'
       
 11789 	}, function(item, value) {
       
 11790 		return !value
       
 11791 				&& (item instanceof PathItem
       
 11792 					|| item instanceof Shape
       
 11793 					|| item instanceof TextItem);
       
 11794 	}],
       
 11795 	miterLimit: ['stroke-miterlimit', 'number'],
       
 11796 	dashArray: ['stroke-dasharray', 'array'],
       
 11797 	dashOffset: ['stroke-dashoffset', 'number'],
       
 11798 	fontFamily: ['font-family', 'string'],
       
 11799 	fontWeight: ['font-weight', 'string'],
       
 11800 	fontSize: ['font-size', 'number'],
       
 11801 	justification: ['text-anchor', 'lookup', {
       
 11802 		left: 'start',
       
 11803 		center: 'middle',
       
 11804 		right: 'end'
       
 11805 	}],
       
 11806 	opacity: ['opacity', 'number'],
       
 11807 	blendMode: ['mix-blend-mode', 'string']
       
 11808 }, function(entry, key) {
       
 11809 	var part = Base.capitalize(key),
       
 11810 		lookup = entry[2];
       
 11811 	this[key] = {
       
 11812 		type: entry[1],
       
 11813 		property: key,
       
 11814 		attribute: entry[0],
       
 11815 		toSVG: lookup,
       
 11816 		fromSVG: lookup && Base.each(lookup, function(value, name) {
       
 11817 			this[value] = name;
       
 11818 		}, {}),
       
 11819 		exportFilter: entry[3],
       
 11820 		get: 'get' + part,
       
 11821 		set: 'set' + part
       
 11822 	};
       
 11823 }, {});
       
 11824 
       
 11825 var SVGNamespaces = {
       
 11826 	href: 'http://www.w3.org/1999/xlink',
       
 11827 	xlink: 'http://www.w3.org/2000/xmlns'
       
 11828 };
       
 11829 
       
 11830 new function() {
       
 11831 	var formatter;
       
 11832 
       
 11833 	function setAttributes(node, attrs) {
       
 11834 		for (var key in attrs) {
       
 11835 			var val = attrs[key],
       
 11836 				namespace = SVGNamespaces[key];
       
 11837 			if (typeof val === 'number')
       
 11838 				val = formatter.number(val);
       
 11839 			if (namespace) {
       
 11840 				node.setAttributeNS(namespace, key, val);
       
 11841 			} else {
       
 11842 				node.setAttribute(key, val);
       
 11843 			}
       
 11844 		}
       
 11845 		return node;
       
 11846 	}
       
 11847 
       
 11848 	function createElement(tag, attrs) {
       
 11849 		return setAttributes(
       
 11850 			document.createElementNS('http://www.w3.org/2000/svg', tag), attrs);
       
 11851 	}
       
 11852 
       
 11853 	function getTransform(matrix, coordinates, center) {
       
 11854 		var attrs = new Base(),
       
 11855 			trans = matrix.getTranslation();
       
 11856 		if (coordinates) {
       
 11857 			matrix = matrix.shiftless();
       
 11858 			var point = matrix._inverseTransform(trans);
       
 11859 			attrs[center ? 'cx' : 'x'] = point.x;
       
 11860 			attrs[center ? 'cy' : 'y'] = point.y;
       
 11861 			trans = null;
       
 11862 		}
       
 11863 		if (!matrix.isIdentity()) {
       
 11864 			var decomposed = matrix.decompose();
       
 11865 			if (decomposed && !decomposed.shearing) {
       
 11866 				var parts = [],
       
 11867 					angle = decomposed.rotation,
       
 11868 					scale = decomposed.scaling;
       
 11869 				if (trans && !trans.isZero())
       
 11870 					parts.push('translate(' + formatter.point(trans) + ')');
       
 11871 				if (!Numerical.isZero(scale.x - 1)
       
 11872 						|| !Numerical.isZero(scale.y - 1))
       
 11873 					parts.push('scale(' + formatter.point(scale) +')');
       
 11874 				if (angle)
       
 11875 					parts.push('rotate(' + formatter.number(angle) + ')');
       
 11876 				attrs.transform = parts.join(' ');
       
 11877 			} else {
       
 11878 				attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')';
       
 11879 			}
       
 11880 		}
       
 11881 		return attrs;
       
 11882 	}
       
 11883 
       
 11884 	function exportGroup(item, options) {
       
 11885 		var attrs = getTransform(item._matrix),
       
 11886 			children = item._children;
       
 11887 		var node = createElement('g', attrs);
       
 11888 		for (var i = 0, l = children.length; i < l; i++) {
       
 11889 			var child = children[i];
       
 11890 			var childNode = exportSVG(child, options);
       
 11891 			if (childNode) {
       
 11892 				if (child.isClipMask()) {
       
 11893 					var clip = createElement('clipPath');
       
 11894 					clip.appendChild(childNode);
       
 11895 					setDefinition(child, clip, 'clip');
       
 11896 					setAttributes(node, {
       
 11897 						'clip-path': 'url(#' + clip.id + ')'
       
 11898 					});
       
 11899 				} else {
       
 11900 					node.appendChild(childNode);
       
 11901 				}
       
 11902 			}
       
 11903 		}
       
 11904 		return node;
       
 11905 	}
       
 11906 
       
 11907 	function exportRaster(item) {
       
 11908 		var attrs = getTransform(item._matrix, true),
       
 11909 			size = item.getSize();
       
 11910 		attrs.x -= size.width / 2;
       
 11911 		attrs.y -= size.height / 2;
       
 11912 		attrs.width = size.width;
       
 11913 		attrs.height = size.height;
       
 11914 		attrs.href = item.toDataURL();
       
 11915 		return createElement('image', attrs);
       
 11916 	}
       
 11917 
       
 11918 	function exportPath(item, options) {
       
 11919 		if (options.matchShapes) {
       
 11920 			var shape = item.toShape(false);
       
 11921 			if (shape)
       
 11922 				return exportShape(shape, options);
       
 11923 		}
       
 11924 		var segments = item._segments,
       
 11925 			type,
       
 11926 			attrs = getTransform(item._matrix);
       
 11927 		if (segments.length === 0)
       
 11928 			return null;
       
 11929 		if (item.isPolygon()) {
       
 11930 			if (segments.length >= 3) {
       
 11931 				type = item._closed ? 'polygon' : 'polyline';
       
 11932 				var parts = [];
       
 11933 				for(i = 0, l = segments.length; i < l; i++)
       
 11934 					parts.push(formatter.point(segments[i]._point));
       
 11935 				attrs.points = parts.join(' ');
       
 11936 			} else {
       
 11937 				type = 'line';
       
 11938 				var first = segments[0]._point,
       
 11939 					last = segments[segments.length - 1]._point;
       
 11940 				attrs.set({
       
 11941 					x1: first.x,
       
 11942 					y1: first.y,
       
 11943 					x2: last.x,
       
 11944 					y2: last.y
       
 11945 				});
       
 11946 			}
       
 11947 		} else {
       
 11948 			type = 'path';
       
 11949 			attrs.d = item.getPathData(null, options.precision);
       
 11950 		}
       
 11951 		return createElement(type, attrs);
       
 11952 	}
       
 11953 
       
 11954 	function exportShape(item) {
       
 11955 		var type = item._type,
       
 11956 			radius = item._radius,
       
 11957 			attrs = getTransform(item._matrix, true, type !== 'rectangle');
       
 11958 		if (type === 'rectangle') {
       
 11959 			type = 'rect';
       
 11960 			var size = item._size,
       
 11961 				width = size.width,
       
 11962 				height = size.height;
       
 11963 			attrs.x -= width / 2;
       
 11964 			attrs.y -= height / 2;
       
 11965 			attrs.width = width;
       
 11966 			attrs.height = height;
       
 11967 			if (radius.isZero())
       
 11968 				radius = null;
       
 11969 		}
       
 11970 		if (radius) {
       
 11971 			if (type === 'circle') {
       
 11972 				attrs.r = radius;
       
 11973 			} else {
       
 11974 				attrs.rx = radius.width;
       
 11975 				attrs.ry = radius.height;
       
 11976 			}
       
 11977 		}
       
 11978 		return createElement(type, attrs);
       
 11979 	}
       
 11980 
       
 11981 	function exportCompoundPath(item, options) {
       
 11982 		var attrs = getTransform(item._matrix);
       
 11983 		var data = item.getPathData(null, options.precision);
       
 11984 		if (data)
       
 11985 			attrs.d = data;
       
 11986 		return createElement('path', attrs);
       
 11987 	}
       
 11988 
       
 11989 	function exportPlacedSymbol(item, options) {
       
 11990 		var attrs = getTransform(item._matrix, true),
       
 11991 			symbol = item.getSymbol(),
       
 11992 			symbolNode = getDefinition(symbol, 'symbol'),
       
 11993 			definition = symbol.getDefinition(),
       
 11994 			bounds = definition.getBounds();
       
 11995 		if (!symbolNode) {
       
 11996 			symbolNode = createElement('symbol', {
       
 11997 				viewBox: formatter.rectangle(bounds)
       
 11998 			});
       
 11999 			symbolNode.appendChild(exportSVG(definition, options));
       
 12000 			setDefinition(symbol, symbolNode, 'symbol');
       
 12001 		}
       
 12002 		attrs.href = '#' + symbolNode.id;
       
 12003 		attrs.x += bounds.x;
       
 12004 		attrs.y += bounds.y;
       
 12005 		attrs.width = formatter.number(bounds.width);
       
 12006 		attrs.height = formatter.number(bounds.height);
       
 12007 		attrs.overflow = 'visible';
       
 12008 		return createElement('use', attrs);
       
 12009 	}
       
 12010 
       
 12011 	function exportGradient(color) {
       
 12012 		var gradientNode = getDefinition(color, 'color');
       
 12013 		if (!gradientNode) {
       
 12014 			var gradient = color.getGradient(),
       
 12015 				radial = gradient._radial,
       
 12016 				origin = color.getOrigin().transform(),
       
 12017 				destination = color.getDestination().transform(),
       
 12018 				attrs;
       
 12019 			if (radial) {
       
 12020 				attrs = {
       
 12021 					cx: origin.x,
       
 12022 					cy: origin.y,
       
 12023 					r: origin.getDistance(destination)
       
 12024 				};
       
 12025 				var highlight = color.getHighlight();
       
 12026 				if (highlight) {
       
 12027 					highlight = highlight.transform();
       
 12028 					attrs.fx = highlight.x;
       
 12029 					attrs.fy = highlight.y;
       
 12030 				}
       
 12031 			} else {
       
 12032 				attrs = {
       
 12033 					x1: origin.x,
       
 12034 					y1: origin.y,
       
 12035 					x2: destination.x,
       
 12036 					y2: destination.y
       
 12037 				};
       
 12038 			}
       
 12039 			attrs.gradientUnits = 'userSpaceOnUse';
       
 12040 			gradientNode = createElement(
       
 12041 					(radial ? 'radial' : 'linear') + 'Gradient', attrs);
       
 12042 			var stops = gradient._stops;
       
 12043 			for (var i = 0, l = stops.length; i < l; i++) {
       
 12044 				var stop = stops[i],
       
 12045 					stopColor = stop._color,
       
 12046 					alpha = stopColor.getAlpha();
       
 12047 				attrs = {
       
 12048 					offset: stop._rampPoint,
       
 12049 					'stop-color': stopColor.toCSS(true)
       
 12050 				};
       
 12051 				if (alpha < 1)
       
 12052 					attrs['stop-opacity'] = alpha;
       
 12053 				gradientNode.appendChild(createElement('stop', attrs));
       
 12054 			}
       
 12055 			setDefinition(color, gradientNode, 'color');
       
 12056 		}
       
 12057 		return 'url(#' + gradientNode.id + ')';
       
 12058 	}
       
 12059 
       
 12060 	function exportText(item) {
       
 12061 		var node = createElement('text', getTransform(item._matrix, true));
       
 12062 		node.textContent = item._content;
       
 12063 		return node;
       
 12064 	}
       
 12065 
       
 12066 	var exporters = {
       
 12067 		Group: exportGroup,
       
 12068 		Layer: exportGroup,
       
 12069 		Raster: exportRaster,
       
 12070 		Path: exportPath,
       
 12071 		Shape: exportShape,
       
 12072 		CompoundPath: exportCompoundPath,
       
 12073 		PlacedSymbol: exportPlacedSymbol,
       
 12074 		PointText: exportText
       
 12075 	};
       
 12076 
       
 12077 	function applyStyle(item, node, isRoot) {
       
 12078 		var attrs = {},
       
 12079 			parent = !isRoot && item.getParent();
       
 12080 
       
 12081 		if (item._name != null)
       
 12082 			attrs.id = item._name;
       
 12083 
       
 12084 		Base.each(SVGStyles, function(entry) {
       
 12085 			var get = entry.get,
       
 12086 				type = entry.type,
       
 12087 				value = item[get]();
       
 12088 			if (entry.exportFilter
       
 12089 					? entry.exportFilter(item, value)
       
 12090 					: !parent || !Base.equals(parent[get](), value)) {
       
 12091 				if (type === 'color' && value != null) {
       
 12092 					var alpha = value.getAlpha();
       
 12093 					if (alpha < 1)
       
 12094 						attrs[entry.attribute + '-opacity'] = alpha;
       
 12095 				}
       
 12096 				attrs[entry.attribute] = value == null
       
 12097 					? 'none'
       
 12098 					: type === 'number'
       
 12099 						? formatter.number(value)
       
 12100 						: type === 'color'
       
 12101 							? value.gradient
       
 12102 								? exportGradient(value, item)
       
 12103 								: value.toCSS(true)
       
 12104 							: type === 'array'
       
 12105 								? value.join(',')
       
 12106 								: type === 'lookup'
       
 12107 									? entry.toSVG[value]
       
 12108 									: value;
       
 12109 			}
       
 12110 		});
       
 12111 
       
 12112 		if (attrs.opacity === 1)
       
 12113 			delete attrs.opacity;
       
 12114 
       
 12115 		if (!item._visible)
       
 12116 			attrs.visibility = 'hidden';
       
 12117 
       
 12118 		return setAttributes(node, attrs);
       
 12119 	}
       
 12120 
       
 12121 	var definitions;
       
 12122 	function getDefinition(item, type) {
       
 12123 		if (!definitions)
       
 12124 			definitions = { ids: {}, svgs: {} };
       
 12125 		return item && definitions.svgs[type + '-' + item._id];
       
 12126 	}
       
 12127 
       
 12128 	function setDefinition(item, node, type) {
       
 12129 		if (!definitions)
       
 12130 			getDefinition();
       
 12131 		var id = definitions.ids[type] = (definitions.ids[type] || 0) + 1;
       
 12132 		node.id = type + '-' + id;
       
 12133 		definitions.svgs[type + '-' + item._id] = node;
       
 12134 	}
       
 12135 
       
 12136 	function exportDefinitions(node, options) {
       
 12137 		var svg = node,
       
 12138 			defs = null;
       
 12139 		if (definitions) {
       
 12140 			svg = node.nodeName.toLowerCase() === 'svg' && node;
       
 12141 			for (var i in definitions.svgs) {
       
 12142 				if (!defs) {
       
 12143 					if (!svg) {
       
 12144 						svg = createElement('svg');
       
 12145 						svg.appendChild(node);
       
 12146 					}
       
 12147 					defs = svg.insertBefore(createElement('defs'),
       
 12148 							svg.firstChild);
       
 12149 				}
       
 12150 				defs.appendChild(definitions.svgs[i]);
       
 12151 			}
       
 12152 			definitions = null;
       
 12153 		}
       
 12154 		return options.asString
       
 12155 				? new XMLSerializer().serializeToString(svg)
       
 12156 				: svg;
       
 12157 	}
       
 12158 
       
 12159 	function exportSVG(item, options, isRoot) {
       
 12160 		var exporter = exporters[item._class],
       
 12161 			node = exporter && exporter(item, options);
       
 12162 		if (node) {
       
 12163 			var onExport = options.onExport;
       
 12164 			if (onExport)
       
 12165 				node = onExport(item, node, options) || node;
       
 12166 			var data = JSON.stringify(item._data);
       
 12167 			if (data && data !== '{}' && data !== 'null')
       
 12168 				node.setAttribute('data-paper-data', data);
       
 12169 		}
       
 12170 		return node && applyStyle(item, node, isRoot);
       
 12171 	}
       
 12172 
       
 12173 	function setOptions(options) {
       
 12174 		if (!options)
       
 12175 			options = {};
       
 12176 		formatter = new Formatter(options.precision);
       
 12177 		return options;
       
 12178 	}
       
 12179 
       
 12180 	Item.inject({
       
 12181 		exportSVG: function(options) {
       
 12182 			options = setOptions(options);
       
 12183 			return exportDefinitions(exportSVG(this, options, true), options);
       
 12184 		}
       
 12185 	});
       
 12186 
       
 12187 	Project.inject({
       
 12188 		exportSVG: function(options) {
       
 12189 			options = setOptions(options);
       
 12190 			var layers = this.layers,
       
 12191 				view = this.getView(),
       
 12192 				size = view.getViewSize(),
       
 12193 				node = createElement('svg', {
       
 12194 					x: 0,
       
 12195 					y: 0,
       
 12196 					width: size.width,
       
 12197 					height: size.height,
       
 12198 					version: '1.1',
       
 12199 					xmlns: 'http://www.w3.org/2000/svg',
       
 12200 					'xmlns:xlink': 'http://www.w3.org/1999/xlink'
       
 12201 				}),
       
 12202 				parent = node,
       
 12203 				matrix = view._matrix;
       
 12204 			if (!matrix.isIdentity())
       
 12205 				parent = node.appendChild(
       
 12206 						createElement('g', getTransform(matrix)));
       
 12207 			for (var i = 0, l = layers.length; i < l; i++)
       
 12208 				parent.appendChild(exportSVG(layers[i], options, true));
       
 12209 			return exportDefinitions(node, options);
       
 12210 		}
       
 12211 	});
       
 12212 };
       
 12213 
       
 12214 new function() {
       
 12215 
       
 12216 	function getValue(node, name, isString, allowNull) {
       
 12217 		var namespace = SVGNamespaces[name],
       
 12218 			value = namespace
       
 12219 				? node.getAttributeNS(namespace, name)
       
 12220 				: node.getAttribute(name);
       
 12221 		if (value === 'null')
       
 12222 			value = null;
       
 12223 		return value == null
       
 12224 				? allowNull
       
 12225 					? null
       
 12226 					: isString
       
 12227 						? ''
       
 12228 						: 0
       
 12229 				: isString
       
 12230 					? value
       
 12231 					: parseFloat(value);
       
 12232 	}
       
 12233 
       
 12234 	function getPoint(node, x, y, allowNull) {
       
 12235 		x = getValue(node, x, false, allowNull);
       
 12236 		y = getValue(node, y, false, allowNull);
       
 12237 		return allowNull && (x == null || y == null) ? null
       
 12238 				: new Point(x, y);
       
 12239 	}
       
 12240 
       
 12241 	function getSize(node, w, h, allowNull) {
       
 12242 		w = getValue(node, w, false, allowNull);
       
 12243 		h = getValue(node, h, false, allowNull);
       
 12244 		return allowNull && (w == null || h == null) ? null
       
 12245 				: new Size(w, h);
       
 12246 	}
       
 12247 
       
 12248 	function convertValue(value, type, lookup) {
       
 12249 		return value === 'none'
       
 12250 				? null
       
 12251 				: type === 'number'
       
 12252 					? parseFloat(value)
       
 12253 					: type === 'array'
       
 12254 						? value ? value.split(/[\s,]+/g).map(parseFloat) : []
       
 12255 						: type === 'color'
       
 12256 							? getDefinition(value) || value
       
 12257 							: type === 'lookup'
       
 12258 								? lookup[value]
       
 12259 								: value;
       
 12260 	}
       
 12261 
       
 12262 	function importGroup(node, type, options, isRoot) {
       
 12263 		var nodes = node.childNodes,
       
 12264 			isClip = type === 'clippath',
       
 12265 			item = new Group(),
       
 12266 			project = item._project,
       
 12267 			currentStyle = project._currentStyle,
       
 12268 			children = [];
       
 12269 		if (!isClip) {
       
 12270 			item = applyAttributes(item, node, isRoot);
       
 12271 			project._currentStyle = item._style.clone();
       
 12272 		}
       
 12273 		for (var i = 0, l = nodes.length; i < l; i++) {
       
 12274 			var childNode = nodes[i],
       
 12275 				child;
       
 12276 			if (childNode.nodeType === 1
       
 12277 					&& (child = importSVG(childNode, options, false))
       
 12278 					&& !(child instanceof Symbol))
       
 12279 				children.push(child);
       
 12280 		}
       
 12281 		item.addChildren(children);
       
 12282 		if (isClip)
       
 12283 			item = applyAttributes(item.reduce(), node, isRoot);
       
 12284 		project._currentStyle = currentStyle;
       
 12285 		if (isClip || type === 'defs') {
       
 12286 			item.remove();
       
 12287 			item = null;
       
 12288 		}
       
 12289 		return item;
       
 12290 	}
       
 12291 
       
 12292 	function importPoly(node, type) {
       
 12293 		var coords = node.getAttribute('points').match(
       
 12294 					/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g),
       
 12295 			points = [];
       
 12296 		for (var i = 0, l = coords.length; i < l; i += 2)
       
 12297 			points.push(new Point(
       
 12298 					parseFloat(coords[i]),
       
 12299 					parseFloat(coords[i + 1])));
       
 12300 		var path = new Path(points);
       
 12301 		if (type === 'polygon')
       
 12302 			path.closePath();
       
 12303 		return path;
       
 12304 	}
       
 12305 
       
 12306 	function importPath(node) {
       
 12307 		var data = node.getAttribute('d'),
       
 12308 			param = { pathData: data };
       
 12309 		return (data.match(/m/gi) || []).length > 1 || /z\S+/i.test(data)
       
 12310 				? new CompoundPath(param)
       
 12311 				: new Path(param);
       
 12312 	}
       
 12313 
       
 12314 	function importGradient(node, type) {
       
 12315 		var id = (getValue(node, 'href', true) || '').substring(1),
       
 12316 			isRadial = type === 'radialgradient',
       
 12317 			gradient;
       
 12318 		if (id) {
       
 12319 			gradient = definitions[id].getGradient();
       
 12320 		} else {
       
 12321 			var nodes = node.childNodes,
       
 12322 				stops = [];
       
 12323 			for (var i = 0, l = nodes.length; i < l; i++) {
       
 12324 				var child = nodes[i];
       
 12325 				if (child.nodeType === 1)
       
 12326 					stops.push(applyAttributes(new GradientStop(), child));
       
 12327 			}
       
 12328 			gradient = new Gradient(stops, isRadial);
       
 12329 		}
       
 12330 		var origin, destination, highlight;
       
 12331 		if (isRadial) {
       
 12332 			origin = getPoint(node, 'cx', 'cy');
       
 12333 			destination = origin.add(getValue(node, 'r'), 0);
       
 12334 			highlight = getPoint(node, 'fx', 'fy', true);
       
 12335 		} else {
       
 12336 			origin = getPoint(node, 'x1', 'y1');
       
 12337 			destination = getPoint(node, 'x2', 'y2');
       
 12338 		}
       
 12339 		applyAttributes(
       
 12340 			new Color(gradient, origin, destination, highlight), node);
       
 12341 		return null;
       
 12342 	}
       
 12343 
       
 12344 	var importers = {
       
 12345 		'#document': function (node, type, options, isRoot) {
       
 12346 			var nodes = node.childNodes;
       
 12347 			for (var i = 0, l = nodes.length; i < l; i++) {
       
 12348 				var child = nodes[i];
       
 12349 				if (child.nodeType === 1) {
       
 12350 					var next = child.nextSibling;
       
 12351 					document.body.appendChild(child);
       
 12352 					var item = importSVG(child, options, isRoot);
       
 12353 					if (next) {
       
 12354 						node.insertBefore(child, next);
       
 12355 					} else {
       
 12356 						node.appendChild(child);
       
 12357 					}
       
 12358 					return item;
       
 12359 				}
       
 12360 			}
       
 12361 		},
       
 12362 		g: importGroup,
       
 12363 		svg: importGroup,
       
 12364 		clippath: importGroup,
       
 12365 		polygon: importPoly,
       
 12366 		polyline: importPoly,
       
 12367 		path: importPath,
       
 12368 		lineargradient: importGradient,
       
 12369 		radialgradient: importGradient,
       
 12370 
       
 12371 		image: function (node) {
       
 12372 			var raster = new Raster(getValue(node, 'href', true));
       
 12373 			raster.on('load', function() {
       
 12374 				var size = getSize(node, 'width', 'height');
       
 12375 				this.setSize(size);
       
 12376 				var center = this._matrix._transformPoint(
       
 12377 						getPoint(node, 'x', 'y').add(size.divide(2)));
       
 12378 				this.translate(center);
       
 12379 			});
       
 12380 			return raster;
       
 12381 		},
       
 12382 
       
 12383 		symbol: function(node, type, options, isRoot) {
       
 12384 			return new Symbol(importGroup(node, type, options, isRoot), true);
       
 12385 		},
       
 12386 
       
 12387 		defs: importGroup,
       
 12388 
       
 12389 		use: function(node) {
       
 12390 			var id = (getValue(node, 'href', true) || '').substring(1),
       
 12391 				definition = definitions[id],
       
 12392 				point = getPoint(node, 'x', 'y');
       
 12393 			return definition
       
 12394 					? definition instanceof Symbol
       
 12395 						? definition.place(point)
       
 12396 						: definition.clone().translate(point)
       
 12397 					: null;
       
 12398 		},
       
 12399 
       
 12400 		circle: function(node) {
       
 12401 			return new Shape.Circle(getPoint(node, 'cx', 'cy'),
       
 12402 					getValue(node, 'r'));
       
 12403 		},
       
 12404 
       
 12405 		ellipse: function(node) {
       
 12406 			return new Shape.Ellipse({
       
 12407 				center: getPoint(node, 'cx', 'cy'),
       
 12408 				radius: getSize(node, 'rx', 'ry')
       
 12409 			});
       
 12410 		},
       
 12411 
       
 12412 		rect: function(node) {
       
 12413 			var point = getPoint(node, 'x', 'y'),
       
 12414 				size = getSize(node, 'width', 'height'),
       
 12415 				radius = getSize(node, 'rx', 'ry');
       
 12416 			return new Shape.Rectangle(new Rectangle(point, size), radius);
       
 12417 		},
       
 12418 
       
 12419 		line: function(node) {
       
 12420 			return new Path.Line(getPoint(node, 'x1', 'y1'),
       
 12421 					getPoint(node, 'x2', 'y2'));
       
 12422 		},
       
 12423 
       
 12424 		text: function(node) {
       
 12425 			var text = new PointText(getPoint(node, 'x', 'y')
       
 12426 					.add(getPoint(node, 'dx', 'dy')));
       
 12427 			text.setContent(node.textContent.trim() || '');
       
 12428 			return text;
       
 12429 		}
       
 12430 	};
       
 12431 
       
 12432 	function applyTransform(item, value, name, node) {
       
 12433 		var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
       
 12434 			matrix = new Matrix();
       
 12435 		for (var i = 0, l = transforms.length; i < l; i++) {
       
 12436 			var transform = transforms[i];
       
 12437 			if (!transform)
       
 12438 				break;
       
 12439 			var parts = transform.split(/\(\s*/),
       
 12440 				command = parts[0],
       
 12441 				v = parts[1].split(/[\s,]+/g);
       
 12442 			for (var j = 0, m = v.length; j < m; j++)
       
 12443 				v[j] = parseFloat(v[j]);
       
 12444 			switch (command) {
       
 12445 			case 'matrix':
       
 12446 				matrix.concatenate(
       
 12447 						new Matrix(v[0], v[1], v[2], v[3], v[4], v[5]));
       
 12448 				break;
       
 12449 			case 'rotate':
       
 12450 				matrix.rotate(v[0], v[1], v[2]);
       
 12451 				break;
       
 12452 			case 'translate':
       
 12453 				matrix.translate(v[0], v[1]);
       
 12454 				break;
       
 12455 			case 'scale':
       
 12456 				matrix.scale(v);
       
 12457 				break;
       
 12458 			case 'skewX':
       
 12459 				matrix.skew(v[0], 0);
       
 12460 				break;
       
 12461 			case 'skewY':
       
 12462 				matrix.skew(0, v[0]);
       
 12463 				break;
       
 12464 			}
       
 12465 		}
       
 12466 		item.transform(matrix);
       
 12467 	}
       
 12468 
       
 12469 	function applyOpacity(item, value, name) {
       
 12470 		var color = item[name === 'fill-opacity' ? 'getFillColor'
       
 12471 				: 'getStrokeColor']();
       
 12472 		if (color)
       
 12473 			color.setAlpha(parseFloat(value));
       
 12474 	}
       
 12475 
       
 12476 	var attributes = Base.each(SVGStyles, function(entry) {
       
 12477 		this[entry.attribute] = function(item, value) {
       
 12478 			item[entry.set](convertValue(value, entry.type, entry.fromSVG));
       
 12479 			if (entry.type === 'color' && item instanceof Shape) {
       
 12480 				var color = item[entry.get]();
       
 12481 				if (color)
       
 12482 					color.transform(new Matrix().translate(
       
 12483 							item.getPosition(true).negate()));
       
 12484 			}
       
 12485 		};
       
 12486 	}, {
       
 12487 		id: function(item, value) {
       
 12488 			definitions[value] = item;
       
 12489 			if (item.setName)
       
 12490 				item.setName(value);
       
 12491 		},
       
 12492 
       
 12493 		'clip-path': function(item, value) {
       
 12494 			var clip = getDefinition(value);
       
 12495 			if (clip) {
       
 12496 				clip = clip.clone();
       
 12497 				clip.setClipMask(true);
       
 12498 				if (item instanceof Group) {
       
 12499 					item.insertChild(0, clip);
       
 12500 				} else {
       
 12501 					return new Group(clip, item);
       
 12502 				}
       
 12503 			}
       
 12504 		},
       
 12505 
       
 12506 		gradientTransform: applyTransform,
       
 12507 		transform: applyTransform,
       
 12508 
       
 12509 		'fill-opacity': applyOpacity,
       
 12510 		'stroke-opacity': applyOpacity,
       
 12511 
       
 12512 		visibility: function(item, value) {
       
 12513 			item.setVisible(value === 'visible');
       
 12514 		},
       
 12515 
       
 12516 		display: function(item, value) {
       
 12517 			item.setVisible(value !== null);
       
 12518 		},
       
 12519 
       
 12520 		'stop-color': function(item, value) {
       
 12521 			if (item.setColor)
       
 12522 				item.setColor(value);
       
 12523 		},
       
 12524 
       
 12525 		'stop-opacity': function(item, value) {
       
 12526 			if (item._color)
       
 12527 				item._color.setAlpha(parseFloat(value));
       
 12528 		},
       
 12529 
       
 12530 		offset: function(item, value) {
       
 12531 			var percentage = value.match(/(.*)%$/);
       
 12532 			item.setRampPoint(percentage
       
 12533 					? percentage[1] / 100
       
 12534 					: parseFloat(value));
       
 12535 		},
       
 12536 
       
 12537 		viewBox: function(item, value, name, node, styles) {
       
 12538 			var rect = new Rectangle(convertValue(value, 'array')),
       
 12539 				size = getSize(node, 'width', 'height', true);
       
 12540 			if (item instanceof Group) {
       
 12541 				var scale = size ? rect.getSize().divide(size) : 1,
       
 12542 					matrix = new Matrix().translate(rect.getPoint()).scale(scale);
       
 12543 				item.transform(matrix.inverted());
       
 12544 			} else if (item instanceof Symbol) {
       
 12545 				if (size)
       
 12546 					rect.setSize(size);
       
 12547 				var clip = getAttribute(node, 'overflow', styles) != 'visible',
       
 12548 					group = item._definition;
       
 12549 				if (clip && !rect.contains(group.getBounds())) {
       
 12550 					clip = new Shape.Rectangle(rect).transform(group._matrix);
       
 12551 					clip.setClipMask(true);
       
 12552 					group.addChild(clip);
       
 12553 				}
       
 12554 			}
       
 12555 		}
       
 12556 	});
       
 12557 
       
 12558 	function getAttribute(node, name, styles) {
       
 12559 		var attr = node.attributes[name],
       
 12560 			value = attr && attr.value;
       
 12561 		if (!value) {
       
 12562 			var style = Base.camelize(name);
       
 12563 			value = node.style[style];
       
 12564 			if (!value && styles.node[style] !== styles.parent[style])
       
 12565 				value = styles.node[style];
       
 12566 		}
       
 12567 		return !value
       
 12568 				? undefined
       
 12569 				: value === 'none'
       
 12570 					? null
       
 12571 					: value;
       
 12572 	}
       
 12573 
       
 12574 	function applyAttributes(item, node, isRoot) {
       
 12575 		var styles = {
       
 12576 			node: DomElement.getStyles(node) || {},
       
 12577 			parent: !isRoot && DomElement.getStyles(node.parentNode) || {}
       
 12578 		};
       
 12579 		Base.each(attributes, function(apply, name) {
       
 12580 			var value = getAttribute(node, name, styles);
       
 12581 			if (value !== undefined)
       
 12582 				item = Base.pick(apply(item, value, name, node, styles), item);
       
 12583 		});
       
 12584 		return item;
       
 12585 	}
       
 12586 
       
 12587 	var definitions = {};
       
 12588 	function getDefinition(value) {
       
 12589 		var match = value && value.match(/\((?:#|)([^)']+)/);
       
 12590 		return match && definitions[match[1]];
       
 12591 	}
       
 12592 
       
 12593 	function importSVG(source, options, isRoot) {
       
 12594 		if (!source)
       
 12595 			return null;
       
 12596 		if (!options) {
       
 12597 			options = {};
       
 12598 		} else if (typeof options === 'function') {
       
 12599 			options = { onLoad: options };
       
 12600 		}
       
 12601 
       
 12602 		var node = source,
       
 12603 			scope = paper;
       
 12604 
       
 12605 		function onLoadCallback(svg) {
       
 12606 			paper = scope;
       
 12607 			var item = importSVG(svg, options, isRoot),
       
 12608 				onLoad = options.onLoad,
       
 12609 				view = scope.project && scope.getView();
       
 12610 			if (onLoad)
       
 12611 				onLoad.call(this, item);
       
 12612 			view.update();
       
 12613 		}
       
 12614 
       
 12615 		if (isRoot) {
       
 12616 			if (typeof source === 'string' && !/^.*</.test(source)) {
       
 12617 				node = document.getElementById(source);
       
 12618 				if (node) {
       
 12619 					source = null;
       
 12620 				} else {
       
 12621 					return Http.request('get', source, onLoadCallback);
       
 12622 				}
       
 12623 			} else if (typeof File !== 'undefined' && source instanceof File) {
       
 12624 				var reader = new FileReader();
       
 12625 				reader.onload = function() {
       
 12626 					onLoadCallback(reader.result);
       
 12627 				};
       
 12628 				return reader.readAsText(source);
       
 12629 			}
       
 12630 		}
       
 12631 
       
 12632 		if (typeof source === 'string')
       
 12633 			node = new DOMParser().parseFromString(source, 'image/svg+xml');
       
 12634 		if (!node.nodeName)
       
 12635 			throw new Error('Unsupported SVG source: ' + source);
       
 12636 		var type = node.nodeName.toLowerCase(),
       
 12637 			importer = importers[type],
       
 12638 			item,
       
 12639 			data = node.getAttribute && node.getAttribute('data-paper-data'),
       
 12640 			settings = scope.settings,
       
 12641 			applyMatrix = settings.applyMatrix;
       
 12642 		settings.applyMatrix = false;
       
 12643 		item = importer && importer(node, type, options, isRoot) || null;
       
 12644 		settings.applyMatrix = applyMatrix;
       
 12645 		if (item) {
       
 12646 			if (type !== '#document' && !(item instanceof Group))
       
 12647 				item = applyAttributes(item, node, isRoot);
       
 12648 			var onImport = options.onImport;
       
 12649 			if (onImport)
       
 12650 				item = onImport(node, item, options) || item;
       
 12651 			if (options.expandShapes && item instanceof Shape) {
       
 12652 				item.remove();
       
 12653 				item = item.toPath();
       
 12654 			}
       
 12655 			if (data)
       
 12656 				item._data = JSON.parse(data);
       
 12657 		}
       
 12658 		if (isRoot) {
       
 12659 			definitions = {};
       
 12660 			if (applyMatrix && item)
       
 12661 				item.matrix.apply(true, true);
       
 12662 		}
       
 12663 		return item;
       
 12664 	}
       
 12665 
       
 12666 	Item.inject({
       
 12667 		importSVG: function(node, options) {
       
 12668 			return this.addChild(importSVG(node, options, true));
       
 12669 		}
       
 12670 	});
       
 12671 
       
 12672 	Project.inject({
       
 12673 		importSVG: function(node, options) {
       
 12674 			this.activate();
       
 12675 			return importSVG(node, options, true);
       
 12676 		}
       
 12677 	});
       
 12678 };
       
 12679 
       
 12680 Base.exports.PaperScript = (function() {
       
 12681 	var exports, define,
       
 12682 		scope = this;
       
 12683 !function(e,r){return"object"==typeof exports&&"object"==typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):(r(e.acorn||(e.acorn={})),void 0)}(this,function(e){"use strict";function r(e){fr=e||{};for(var r in mr)Object.prototype.hasOwnProperty.call(fr,r)||(fr[r]=mr[r]);hr=fr.sourceFile||null}function t(e,r){var t=vr(dr,e);r+=" ("+t.line+":"+t.column+")";var n=new SyntaxError(r);throw n.pos=e,n.loc=t,n.raisedAt=br,n}function n(e){function r(e){if(1==e.length)return t+="return str === "+JSON.stringify(e[0])+";";t+="switch(str){";for(var r=0;r<e.length;++r)t+="case "+JSON.stringify(e[r])+":";t+="return true}return false;"}e=e.split(" ");var t="",n=[];e:for(var a=0;a<e.length;++a){for(var o=0;o<n.length;++o)if(n[o][0].length==e[a].length){n[o].push(e[a]);continue e}n.push([e[a]])}if(n.length>3){n.sort(function(e,r){return r.length-e.length}),t+="switch(str.length){";for(var a=0;a<n.length;++a){var i=n[a];t+="case "+i[0].length+":",r(i)}t+="}"}else r(e);return new Function("str",t)}function a(){this.line=Ar,this.column=br-Sr}function o(){Ar=1,br=Sr=0,Er=!0,u()}function i(e,r){gr=br,fr.locations&&(kr=new a),wr=e,u(),Cr=r,Er=e.beforeExpr}function s(){var e=fr.onComment&&fr.locations&&new a,r=br,n=dr.indexOf("*/",br+=2);if(-1===n&&t(br-2,"Unterminated comment"),br=n+2,fr.locations){Kt.lastIndex=r;for(var o;(o=Kt.exec(dr))&&o.index<br;)++Ar,Sr=o.index+o[0].length}fr.onComment&&fr.onComment(!0,dr.slice(r+2,n),r,br,e,fr.locations&&new a)}function c(){for(var e=br,r=fr.onComment&&fr.locations&&new a,t=dr.charCodeAt(br+=2);pr>br&&10!==t&&13!==t&&8232!==t&&8233!==t;)++br,t=dr.charCodeAt(br);fr.onComment&&fr.onComment(!1,dr.slice(e+2,br),e,br,r,fr.locations&&new a)}function u(){for(;pr>br;){var e=dr.charCodeAt(br);if(32===e)++br;else if(13===e){++br;var r=dr.charCodeAt(br);10===r&&++br,fr.locations&&(++Ar,Sr=br)}else if(10===e||8232===e||8233===e)++br,fr.locations&&(++Ar,Sr=br);else if(e>8&&14>e)++br;else if(47===e){var r=dr.charCodeAt(br+1);if(42===r)s();else{if(47!==r)break;c()}}else if(160===e)++br;else{if(!(e>=5760&&Jt.test(String.fromCharCode(e))))break;++br}}}function l(){var e=dr.charCodeAt(br+1);return e>=48&&57>=e?E(!0):(++br,i(xt))}function f(){var e=dr.charCodeAt(br+1);return Er?(++br,k()):61===e?x(Et,2):x(wt,1)}function d(){var e=dr.charCodeAt(br+1);return 61===e?x(Et,2):x(Dt,1)}function p(e){var r=dr.charCodeAt(br+1);return r===e?x(124===e?Lt:Ut,2):61===r?x(Et,2):x(124===e?Rt:Tt,1)}function h(){var e=dr.charCodeAt(br+1);return 61===e?x(Et,2):x(Vt,1)}function m(e){var r=dr.charCodeAt(br+1);return r===e?45==r&&62==dr.charCodeAt(br+2)&&Gt.test(dr.slice(Lr,br))?(br+=3,c(),u(),g()):x(St,2):61===r?x(Et,2):x(At,1)}function v(e){var r=dr.charCodeAt(br+1),t=1;return r===e?(t=62===e&&62===dr.charCodeAt(br+2)?3:2,61===dr.charCodeAt(br+t)?x(Et,t+1):x(jt,t)):33==r&&60==e&&45==dr.charCodeAt(br+2)&&45==dr.charCodeAt(br+3)?(br+=4,c(),u(),g()):(61===r&&(t=61===dr.charCodeAt(br+2)?3:2),x(Ot,t))}function b(e){var r=dr.charCodeAt(br+1);return 61===r?x(qt,61===dr.charCodeAt(br+2)?3:2):x(61===e?Ct:It,1)}function y(e){switch(e){case 46:return l();case 40:return++br,i(mt);case 41:return++br,i(vt);case 59:return++br,i(yt);case 44:return++br,i(bt);case 91:return++br,i(ft);case 93:return++br,i(dt);case 123:return++br,i(pt);case 125:return++br,i(ht);case 58:return++br,i(gt);case 63:return++br,i(kt);case 48:var r=dr.charCodeAt(br+1);if(120===r||88===r)return C();case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return E(!1);case 34:case 39:return A(e);case 47:return f(e);case 37:case 42:return d();case 124:case 38:return p(e);case 94:return h();case 43:case 45:return m(e);case 60:case 62:return v(e);case 61:case 33:return b(e);case 126:return x(It,1)}return!1}function g(e){if(e?br=yr+1:yr=br,fr.locations&&(xr=new a),e)return k();if(br>=pr)return i(Br);var r=dr.charCodeAt(br);if(Qt(r)||92===r)return L();var n=y(r);if(n===!1){var o=String.fromCharCode(r);if("\\"===o||$t.test(o))return L();t(br,"Unexpected character '"+o+"'")}return n}function x(e,r){var t=dr.slice(br,br+r);br+=r,i(e,t)}function k(){for(var e,r,n="",a=br;;){br>=pr&&t(a,"Unterminated regular expression");var o=dr.charAt(br);if(Gt.test(o)&&t(a,"Unterminated regular expression"),e)e=!1;else{if("["===o)r=!0;else if("]"===o&&r)r=!1;else if("/"===o&&!r)break;e="\\"===o}++br}var n=dr.slice(a,br);++br;var s=I();return s&&!/^[gmsiy]*$/.test(s)&&t(a,"Invalid regexp flag"),i(jr,new RegExp(n,s))}function w(e,r){for(var t=br,n=0,a=0,o=null==r?1/0:r;o>a;++a){var i,s=dr.charCodeAt(br);if(i=s>=97?s-97+10:s>=65?s-65+10:s>=48&&57>=s?s-48:1/0,i>=e)break;++br,n=n*e+i}return br===t||null!=r&&br-t!==r?null:n}function C(){br+=2;var e=w(16);return null==e&&t(yr+2,"Expected hexadecimal number"),Qt(dr.charCodeAt(br))&&t(br,"Identifier directly after number"),i(Or,e)}function E(e){var r=br,n=!1,a=48===dr.charCodeAt(br);e||null!==w(10)||t(r,"Invalid number"),46===dr.charCodeAt(br)&&(++br,w(10),n=!0);var o=dr.charCodeAt(br);(69===o||101===o)&&(o=dr.charCodeAt(++br),(43===o||45===o)&&++br,null===w(10)&&t(r,"Invalid number"),n=!0),Qt(dr.charCodeAt(br))&&t(br,"Identifier directly after number");var s,c=dr.slice(r,br);return n?s=parseFloat(c):a&&1!==c.length?/[89]/.test(c)||Tr?t(r,"Invalid number"):s=parseInt(c,8):s=parseInt(c,10),i(Or,s)}function A(e){br++;for(var r="";;){br>=pr&&t(yr,"Unterminated string constant");var n=dr.charCodeAt(br);if(n===e)return++br,i(Dr,r);if(92===n){n=dr.charCodeAt(++br);var a=/^[0-7]+/.exec(dr.slice(br,br+3));for(a&&(a=a[0]);a&&parseInt(a,8)>255;)a=a.slice(0,a.length-1);if("0"===a&&(a=null),++br,a)Tr&&t(br-2,"Octal literal in strict mode"),r+=String.fromCharCode(parseInt(a,8)),br+=a.length-1;else switch(n){case 110:r+="\n";break;case 114:r+="\r";break;case 120:r+=String.fromCharCode(S(2));break;case 117:r+=String.fromCharCode(S(4));break;case 85:r+=String.fromCharCode(S(8));break;case 116:r+="	";break;case 98:r+="\b";break;case 118:r+="";break;case 102:r+="\f";break;case 48:r+="\0";break;case 13:10===dr.charCodeAt(br)&&++br;case 10:fr.locations&&(Sr=br,++Ar);break;default:r+=String.fromCharCode(n)}}else(13===n||10===n||8232===n||8233===n)&&t(yr,"Unterminated string constant"),r+=String.fromCharCode(n),++br}}function S(e){var r=w(16,e);return null===r&&t(yr,"Bad character escape sequence"),r}function I(){Bt=!1;for(var e,r=!0,n=br;;){var a=dr.charCodeAt(br);if(Yt(a))Bt&&(e+=dr.charAt(br)),++br;else{if(92!==a)break;Bt||(e=dr.slice(n,br)),Bt=!0,117!=dr.charCodeAt(++br)&&t(br,"Expecting Unicode escape sequence \\uXXXX"),++br;var o=S(4),i=String.fromCharCode(o);i||t(br-1,"Invalid Unicode escape"),(r?Qt(o):Yt(o))||t(br-4,"Invalid Unicode escape"),e+=i}r=!1}return Bt?e:dr.slice(n,br)}function L(){var e=I(),r=Fr;return Bt||(Wt(e)?r=lt[e]:(fr.forbidReserved&&(3===fr.ecmaVersion?Mt:zt)(e)||Tr&&Xt(e))&&t(yr,"The keyword '"+e+"' is reserved")),i(r,e)}function U(){Ir=yr,Lr=gr,Ur=kr,g()}function R(e){if(Tr=e,br=Lr,fr.locations)for(;Sr>br;)Sr=dr.lastIndexOf("\n",Sr-2)+1,--Ar;u(),g()}function V(){this.type=null,this.start=yr,this.end=null}function T(){this.start=xr,this.end=null,null!==hr&&(this.source=hr)}function q(){var e=new V;return fr.locations&&(e.loc=new T),fr.ranges&&(e.range=[yr,0]),e}function O(e){var r=new V;return r.start=e.start,fr.locations&&(r.loc=new T,r.loc.start=e.loc.start),fr.ranges&&(r.range=[e.range[0],0]),r}function j(e,r){return e.type=r,e.end=Lr,fr.locations&&(e.loc.end=Ur),fr.ranges&&(e.range[1]=Lr),e}function D(e){return fr.ecmaVersion>=5&&"ExpressionStatement"===e.type&&"Literal"===e.expression.type&&"use strict"===e.expression.value}function F(e){return wr===e?(U(),!0):void 0}function B(){return!fr.strictSemicolons&&(wr===Br||wr===ht||Gt.test(dr.slice(Lr,yr)))}function M(){F(yt)||B()||X()}function z(e){wr===e?U():X()}function X(){t(yr,"Unexpected token")}function N(e){"Identifier"!==e.type&&"MemberExpression"!==e.type&&t(e.start,"Assigning to rvalue"),Tr&&"Identifier"===e.type&&Nt(e.name)&&t(e.start,"Assigning to "+e.name+" in strict mode")}function W(e){Ir=Lr=br,fr.locations&&(Ur=new a),Rr=Tr=null,Vr=[],g();var r=e||q(),t=!0;for(e||(r.body=[]);wr!==Br;){var n=J();r.body.push(n),t&&D(n)&&R(!0),t=!1}return j(r,"Program")}function J(){(wr===wt||wr===Et&&"/="==Cr)&&g(!0);var e=wr,r=q();switch(e){case Mr:case Nr:U();var n=e===Mr;F(yt)||B()?r.label=null:wr!==Fr?X():(r.label=lr(),M());for(var a=0;a<Vr.length;++a){var o=Vr[a];if(null==r.label||o.name===r.label.name){if(null!=o.kind&&(n||"loop"===o.kind))break;if(r.label&&n)break}}return a===Vr.length&&t(r.start,"Unsyntactic "+e.keyword),j(r,n?"BreakStatement":"ContinueStatement");case Wr:return U(),M(),j(r,"DebuggerStatement");case Pr:return U(),Vr.push(Zt),r.body=J(),Vr.pop(),z(tt),r.test=P(),M(),j(r,"DoWhileStatement");case _r:if(U(),Vr.push(Zt),z(mt),wr===yt)return $(r,null);if(wr===rt){var i=q();return U(),G(i,!0),j(i,"VariableDeclaration"),1===i.declarations.length&&F(ut)?_(r,i):$(r,i)}var i=K(!1,!0);return F(ut)?(N(i),_(r,i)):$(r,i);case Gr:return U(),cr(r,!0);case Kr:return U(),r.test=P(),r.consequent=J(),r.alternate=F(Hr)?J():null,j(r,"IfStatement");case Qr:return Rr||t(yr,"'return' outside of function"),U(),F(yt)||B()?r.argument=null:(r.argument=K(),M()),j(r,"ReturnStatement");case Yr:U(),r.discriminant=P(),r.cases=[],z(pt),Vr.push(en);for(var s,c;wr!=ht;)if(wr===zr||wr===Jr){var u=wr===zr;s&&j(s,"SwitchCase"),r.cases.push(s=q()),s.consequent=[],U(),u?s.test=K():(c&&t(Ir,"Multiple default clauses"),c=!0,s.test=null),z(gt)}else s||X(),s.consequent.push(J());return s&&j(s,"SwitchCase"),U(),Vr.pop(),j(r,"SwitchStatement");case Zr:return U(),Gt.test(dr.slice(Lr,yr))&&t(Lr,"Illegal newline after throw"),r.argument=K(),M(),j(r,"ThrowStatement");case et:if(U(),r.block=H(),r.handler=null,wr===Xr){var l=q();U(),z(mt),l.param=lr(),Tr&&Nt(l.param.name)&&t(l.param.start,"Binding "+l.param.name+" in strict mode"),z(vt),l.guard=null,l.body=H(),r.handler=j(l,"CatchClause")}return r.guardedHandlers=qr,r.finalizer=F($r)?H():null,r.handler||r.finalizer||t(r.start,"Missing catch or finally clause"),j(r,"TryStatement");case rt:return U(),G(r),M(),j(r,"VariableDeclaration");case tt:return U(),r.test=P(),Vr.push(Zt),r.body=J(),Vr.pop(),j(r,"WhileStatement");case nt:return Tr&&t(yr,"'with' in strict mode"),U(),r.object=P(),r.body=J(),j(r,"WithStatement");case pt:return H();case yt:return U(),j(r,"EmptyStatement");default:var f=Cr,d=K();if(e===Fr&&"Identifier"===d.type&&F(gt)){for(var a=0;a<Vr.length;++a)Vr[a].name===f&&t(d.start,"Label '"+f+"' is already declared");var p=wr.isLoop?"loop":wr===Yr?"switch":null;return Vr.push({name:f,kind:p}),r.body=J(),Vr.pop(),r.label=d,j(r,"LabeledStatement")}return r.expression=d,M(),j(r,"ExpressionStatement")}}function P(){z(mt);var e=K();return z(vt),e}function H(e){var r,t=q(),n=!0,a=!1;for(t.body=[],z(pt);!F(ht);){var o=J();t.body.push(o),n&&e&&D(o)&&(r=a,R(a=!0)),n=!1}return a&&!r&&R(!1),j(t,"BlockStatement")}function $(e,r){return e.init=r,z(yt),e.test=wr===yt?null:K(),z(yt),e.update=wr===vt?null:K(),z(vt),e.body=J(),Vr.pop(),j(e,"ForStatement")}function _(e,r){return e.left=r,e.right=K(),z(vt),e.body=J(),Vr.pop(),j(e,"ForInStatement")}function G(e,r){for(e.declarations=[],e.kind="var";;){var n=q();if(n.id=lr(),Tr&&Nt(n.id.name)&&t(n.id.start,"Binding "+n.id.name+" in strict mode"),n.init=F(Ct)?K(!0,r):null,e.declarations.push(j(n,"VariableDeclarator")),!F(bt))break}return e}function K(e,r){var t=Q(r);if(!e&&wr===bt){var n=O(t);for(n.expressions=[t];F(bt);)n.expressions.push(Q(r));return j(n,"SequenceExpression")}return t}function Q(e){var r=Y(e);if(wr.isAssign){var t=O(r);return t.operator=Cr,t.left=r,U(),t.right=Q(e),N(r),j(t,"AssignmentExpression")}return r}function Y(e){var r=Z(e);if(F(kt)){var t=O(r);return t.test=r,t.consequent=K(!0),z(gt),t.alternate=K(!0,e),j(t,"ConditionalExpression")}return r}function Z(e){return er(rr(),-1,e)}function er(e,r,t){var n=wr.binop;if(null!=n&&(!t||wr!==ut)&&n>r){var a=O(e);a.left=e,a.operator=Cr,U(),a.right=er(rr(),n,t);var o=j(a,/&&|\|\|/.test(a.operator)?"LogicalExpression":"BinaryExpression");return er(o,r,t)}return e}function rr(){if(wr.prefix){var e=q(),r=wr.isUpdate;return e.operator=Cr,e.prefix=!0,Er=!0,U(),e.argument=rr(),r?N(e.argument):Tr&&"delete"===e.operator&&"Identifier"===e.argument.type&&t(e.start,"Deleting local variable in strict mode"),j(e,r?"UpdateExpression":"UnaryExpression")}for(var n=tr();wr.postfix&&!B();){var e=O(n);e.operator=Cr,e.prefix=!1,e.argument=n,N(n),U(),n=j(e,"UpdateExpression")}return n}function tr(){return nr(ar())}function nr(e,r){if(F(xt)){var t=O(e);return t.object=e,t.property=lr(!0),t.computed=!1,nr(j(t,"MemberExpression"),r)}if(F(ft)){var t=O(e);return t.object=e,t.property=K(),t.computed=!0,z(dt),nr(j(t,"MemberExpression"),r)}if(!r&&F(mt)){var t=O(e);return t.callee=e,t.arguments=ur(vt,!1),nr(j(t,"CallExpression"),r)}return e}function ar(){switch(wr){case ot:var e=q();return U(),j(e,"ThisExpression");case Fr:return lr();case Or:case Dr:case jr:var e=q();return e.value=Cr,e.raw=dr.slice(yr,gr),U(),j(e,"Literal");case it:case st:case ct:var e=q();return e.value=wr.atomValue,e.raw=wr.keyword,U(),j(e,"Literal");case mt:var r=xr,t=yr;U();var n=K();return n.start=t,n.end=gr,fr.locations&&(n.loc.start=r,n.loc.end=kr),fr.ranges&&(n.range=[t,gr]),z(vt),n;case ft:var e=q();return U(),e.elements=ur(dt,!0,!0),j(e,"ArrayExpression");case pt:return ir();case Gr:var e=q();return U(),cr(e,!1);case at:return or();default:X()}}function or(){var e=q();return U(),e.callee=nr(ar(),!0),e.arguments=F(mt)?ur(vt,!1):qr,j(e,"NewExpression")}function ir(){var e=q(),r=!0,n=!1;for(e.properties=[],U();!F(ht);){if(r)r=!1;else if(z(bt),fr.allowTrailingCommas&&F(ht))break;var a,o={key:sr()},i=!1;if(F(gt)?(o.value=K(!0),a=o.kind="init"):fr.ecmaVersion>=5&&"Identifier"===o.key.type&&("get"===o.key.name||"set"===o.key.name)?(i=n=!0,a=o.kind=o.key.name,o.key=sr(),wr!==mt&&X(),o.value=cr(q(),!1)):X(),"Identifier"===o.key.type&&(Tr||n))for(var s=0;s<e.properties.length;++s){var c=e.properties[s];if(c.key.name===o.key.name){var u=a==c.kind||i&&"init"===c.kind||"init"===a&&("get"===c.kind||"set"===c.kind);u&&!Tr&&"init"===a&&"init"===c.kind&&(u=!1),u&&t(o.key.start,"Redefinition of property")}}e.properties.push(o)}return j(e,"ObjectExpression")}function sr(){return wr===Or||wr===Dr?ar():lr(!0)}function cr(e,r){wr===Fr?e.id=lr():r?X():e.id=null,e.params=[];var n=!0;for(z(mt);!F(vt);)n?n=!1:z(bt),e.params.push(lr());var a=Rr,o=Vr;if(Rr=!0,Vr=[],e.body=H(!0),Rr=a,Vr=o,Tr||e.body.body.length&&D(e.body.body[0]))for(var i=e.id?-1:0;i<e.params.length;++i){var s=0>i?e.id:e.params[i];if((Xt(s.name)||Nt(s.name))&&t(s.start,"Defining '"+s.name+"' in strict mode"),i>=0)for(var c=0;i>c;++c)s.name===e.params[c].name&&t(s.start,"Argument name clash in strict mode")}return j(e,r?"FunctionDeclaration":"FunctionExpression")}function ur(e,r,t){for(var n=[],a=!0;!F(e);){if(a)a=!1;else if(z(bt),r&&fr.allowTrailingCommas&&F(e))break;t&&wr===bt?n.push(null):n.push(K(!0))}return n}function lr(e){var r=q();return r.name=wr===Fr?Cr:e&&!fr.forbidReserved&&wr.keyword||X(),Er=!1,U(),j(r,"Identifier")}e.version="0.4.0";var fr,dr,pr,hr;e.parse=function(e,t){return dr=String(e),pr=dr.length,r(t),o(),W(fr.program)};var mr=e.defaultOptions={ecmaVersion:5,strictSemicolons:!1,allowTrailingCommas:!0,forbidReserved:!1,locations:!1,onComment:null,ranges:!1,program:null,sourceFile:null},vr=e.getLineInfo=function(e,r){for(var t=1,n=0;;){Kt.lastIndex=n;var a=Kt.exec(e);if(!(a&&a.index<r))break;++t,n=a.index+a[0].length}return{line:t,column:r-n}};e.tokenize=function(e,t){function n(e){return g(e),a.start=yr,a.end=gr,a.startLoc=xr,a.endLoc=kr,a.type=wr,a.value=Cr,a}dr=String(e),pr=dr.length,r(t),o();var a={};return n.jumpTo=function(e,r){if(br=e,fr.locations){Ar=1,Sr=Kt.lastIndex=0;for(var t;(t=Kt.exec(dr))&&t.index<e;)++Ar,Sr=t.index+t[0].length}Er=r,u()},n};var br,yr,gr,xr,kr,wr,Cr,Er,Ar,Sr,Ir,Lr,Ur,Rr,Vr,Tr,qr=[],Or={type:"num"},jr={type:"regexp"},Dr={type:"string"},Fr={type:"name"},Br={type:"eof"},Mr={keyword:"break"},zr={keyword:"case",beforeExpr:!0},Xr={keyword:"catch"},Nr={keyword:"continue"},Wr={keyword:"debugger"},Jr={keyword:"default"},Pr={keyword:"do",isLoop:!0},Hr={keyword:"else",beforeExpr:!0},$r={keyword:"finally"},_r={keyword:"for",isLoop:!0},Gr={keyword:"function"},Kr={keyword:"if"},Qr={keyword:"return",beforeExpr:!0},Yr={keyword:"switch"},Zr={keyword:"throw",beforeExpr:!0},et={keyword:"try"},rt={keyword:"var"},tt={keyword:"while",isLoop:!0},nt={keyword:"with"},at={keyword:"new",beforeExpr:!0},ot={keyword:"this"},it={keyword:"null",atomValue:null},st={keyword:"true",atomValue:!0},ct={keyword:"false",atomValue:!1},ut={keyword:"in",binop:7,beforeExpr:!0},lt={"break":Mr,"case":zr,"catch":Xr,"continue":Nr,"debugger":Wr,"default":Jr,"do":Pr,"else":Hr,"finally":$r,"for":_r,"function":Gr,"if":Kr,"return":Qr,"switch":Yr,"throw":Zr,"try":et,"var":rt,"while":tt,"with":nt,"null":it,"true":st,"false":ct,"new":at,"in":ut,"instanceof":{keyword:"instanceof",binop:7,beforeExpr:!0},"this":ot,"typeof":{keyword:"typeof",prefix:!0,beforeExpr:!0},"void":{keyword:"void",prefix:!0,beforeExpr:!0},"delete":{keyword:"delete",prefix:!0,beforeExpr:!0}},ft={type:"[",beforeExpr:!0},dt={type:"]"},pt={type:"{",beforeExpr:!0},ht={type:"}"},mt={type:"(",beforeExpr:!0},vt={type:")"},bt={type:",",beforeExpr:!0},yt={type:";",beforeExpr:!0},gt={type:":",beforeExpr:!0},xt={type:"."},kt={type:"?",beforeExpr:!0},wt={binop:10,beforeExpr:!0},Ct={isAssign:!0,beforeExpr:!0},Et={isAssign:!0,beforeExpr:!0},At={binop:9,prefix:!0,beforeExpr:!0},St={postfix:!0,prefix:!0,isUpdate:!0},It={prefix:!0,beforeExpr:!0},Lt={binop:1,beforeExpr:!0},Ut={binop:2,beforeExpr:!0},Rt={binop:3,beforeExpr:!0},Vt={binop:4,beforeExpr:!0},Tt={binop:5,beforeExpr:!0},qt={binop:6,beforeExpr:!0},Ot={binop:7,beforeExpr:!0},jt={binop:8,beforeExpr:!0},Dt={binop:10,beforeExpr:!0};e.tokTypes={bracketL:ft,bracketR:dt,braceL:pt,braceR:ht,parenL:mt,parenR:vt,comma:bt,semi:yt,colon:gt,dot:xt,question:kt,slash:wt,eq:Ct,name:Fr,eof:Br,num:Or,regexp:jr,string:Dr};for(var Ft in lt)e.tokTypes["_"+Ft]=lt[Ft];var Bt,Mt=n("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"),zt=n("class enum extends super const export import"),Xt=n("implements interface let package private protected public static yield"),Nt=n("eval arguments"),Wt=n("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"),Jt=/[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/,Pt="\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",Ht="\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f",$t=new RegExp("["+Pt+"]"),_t=new RegExp("["+Pt+Ht+"]"),Gt=/[\n\r\u2028\u2029]/,Kt=/\r\n|[\n\r\u2028\u2029]/g,Qt=e.isIdentifierStart=function(e){return 65>e?36===e:91>e?!0:97>e?95===e:123>e?!0:e>=170&&$t.test(String.fromCharCode(e))},Yt=e.isIdentifierChar=function(e){return 48>e?36===e:58>e?!0:65>e?!1:91>e?!0:97>e?95===e:123>e?!0:e>=170&&_t.test(String.fromCharCode(e))},Zt={kind:"loop"},en={kind:"switch"}});
       
 12684 
       
 12685 	var binaryOperators = {
       
 12686 		'+': '__add',
       
 12687 		'-': '__subtract',
       
 12688 		'*': '__multiply',
       
 12689 		'/': '__divide',
       
 12690 		'%': '__modulo',
       
 12691 		'==': 'equals',
       
 12692 		'!=': 'equals'
       
 12693 	};
       
 12694 
       
 12695 	var unaryOperators = {
       
 12696 		'-': '__negate',
       
 12697 		'+': null
       
 12698 	};
       
 12699 
       
 12700 	var fields = Base.each(
       
 12701 		['add', 'subtract', 'multiply', 'divide', 'modulo', 'negate'],
       
 12702 		function(name) {
       
 12703 			this['__' + name] = '#' + name;
       
 12704 		},
       
 12705 		{}
       
 12706 	);
       
 12707 	Point.inject(fields);
       
 12708 	Size.inject(fields);
       
 12709 	Color.inject(fields);
       
 12710 
       
 12711 	function __$__(left, operator, right) {
       
 12712 		var handler = binaryOperators[operator];
       
 12713 		if (left && left[handler]) {
       
 12714 			var res = left[handler](right);
       
 12715 			return operator === '!=' ? !res : res;
       
 12716 		}
       
 12717 		switch (operator) {
       
 12718 		case '+': return left + right;
       
 12719 		case '-': return left - right;
       
 12720 		case '*': return left * right;
       
 12721 		case '/': return left / right;
       
 12722 		case '%': return left % right;
       
 12723 		case '==': return left == right;
       
 12724 		case '!=': return left != right;
       
 12725 		}
       
 12726 	}
       
 12727 
       
 12728 	function $__(operator, value) {
       
 12729 		var handler = unaryOperators[operator];
       
 12730 		if (handler && value && value[handler])
       
 12731 			return value[handler]();
       
 12732 		switch (operator) {
       
 12733 		case '+': return +value;
       
 12734 		case '-': return -value;
       
 12735 		}
       
 12736 	}
       
 12737 
       
 12738 	function parse(code, options) {
       
 12739 		return scope.acorn.parse(code, options);
       
 12740 	}
       
 12741 
       
 12742 	function compile(code, url, options) {
       
 12743 		if (!code)
       
 12744 			return '';
       
 12745 		options = options || {};
       
 12746 		url = url || '';
       
 12747 
       
 12748 		var insertions = [];
       
 12749 
       
 12750 		function getOffset(offset) {
       
 12751 			for (var i = 0, l = insertions.length; i < l; i++) {
       
 12752 				var insertion = insertions[i];
       
 12753 				if (insertion[0] >= offset)
       
 12754 					break;
       
 12755 				offset += insertion[1];
       
 12756 			}
       
 12757 			return offset;
       
 12758 		}
       
 12759 
       
 12760 		function getCode(node) {
       
 12761 			return code.substring(getOffset(node.range[0]),
       
 12762 					getOffset(node.range[1]));
       
 12763 		}
       
 12764 
       
 12765 		function getBetween(left, right) {
       
 12766 			return code.substring(getOffset(left.range[1]),
       
 12767 					getOffset(right.range[0]));
       
 12768 		}
       
 12769 
       
 12770 		function replaceCode(node, str) {
       
 12771 			var start = getOffset(node.range[0]),
       
 12772 				end = getOffset(node.range[1]),
       
 12773 				insert = 0;
       
 12774 			for (var i = insertions.length - 1; i >= 0; i--) {
       
 12775 				if (start > insertions[i][0]) {
       
 12776 					insert = i + 1;
       
 12777 					break;
       
 12778 				}
       
 12779 			}
       
 12780 			insertions.splice(insert, 0, [start, str.length - end + start]);
       
 12781 			code = code.substring(0, start) + str + code.substring(end);
       
 12782 		}
       
 12783 
       
 12784 		function walkAST(node, parent) {
       
 12785 			if (!node)
       
 12786 				return;
       
 12787 			for (var key in node) {
       
 12788 				if (key === 'range' || key === 'loc')
       
 12789 					continue;
       
 12790 				var value = node[key];
       
 12791 				if (Array.isArray(value)) {
       
 12792 					for (var i = 0, l = value.length; i < l; i++)
       
 12793 						walkAST(value[i], node);
       
 12794 				} else if (value && typeof value === 'object') {
       
 12795 					walkAST(value, node);
       
 12796 				}
       
 12797 			}
       
 12798 			switch (node.type) {
       
 12799 			case 'UnaryExpression':
       
 12800 				if (node.operator in unaryOperators
       
 12801 						&& node.argument.type !== 'Literal') {
       
 12802 					var arg = getCode(node.argument);
       
 12803 					replaceCode(node, '$__("' + node.operator + '", '
       
 12804 							+ arg + ')');
       
 12805 				}
       
 12806 				break;
       
 12807 			case 'BinaryExpression':
       
 12808 				if (node.operator in binaryOperators
       
 12809 						&& node.left.type !== 'Literal') {
       
 12810 					var left = getCode(node.left),
       
 12811 						right = getCode(node.right),
       
 12812 						between = getBetween(node.left, node.right),
       
 12813 						operator = node.operator;
       
 12814 					replaceCode(node, '__$__(' + left + ','
       
 12815 							+ between.replace(new RegExp('\\' + operator),
       
 12816 								'"' + operator + '"')
       
 12817 							+ ', ' + right + ')');
       
 12818 				}
       
 12819 				break;
       
 12820 			case 'UpdateExpression':
       
 12821 			case 'AssignmentExpression':
       
 12822 				var parentType = parent && parent.type;
       
 12823 				if (!(
       
 12824 						parentType === 'ForStatement'
       
 12825 						|| parentType === 'BinaryExpression'
       
 12826 							&& /^[=!<>]/.test(parent.operator)
       
 12827 						|| parentType === 'MemberExpression' && parent.computed
       
 12828 				)) {
       
 12829 					if (node.type === 'UpdateExpression') {
       
 12830 						var arg = getCode(node.argument);
       
 12831 						var str = arg + ' = __$__(' + arg
       
 12832 								+ ', "' + node.operator[0] + '", 1)';
       
 12833 						if (!node.prefix
       
 12834 								&& (parentType === 'AssignmentExpression'
       
 12835 									|| parentType === 'VariableDeclarator'))
       
 12836 							str = arg + '; ' + str;
       
 12837 						replaceCode(node, str);
       
 12838 					} else {
       
 12839 						if (/^.=$/.test(node.operator)
       
 12840 								&& node.left.type !== 'Literal') {
       
 12841 							var left = getCode(node.left),
       
 12842 								right = getCode(node.right);
       
 12843 							replaceCode(node, left + ' = __$__(' + left + ', "'
       
 12844 									+ node.operator[0] + '", ' + right + ')');
       
 12845 						}
       
 12846 					}
       
 12847 				}
       
 12848 				break;
       
 12849 			}
       
 12850 		}
       
 12851 		var sourceMap = null,
       
 12852 			browser = paper.browser,
       
 12853 			version = browser.versionNumber,
       
 12854 			lineBreaks = /\r\n|\n|\r/mg;
       
 12855 		if (browser.chrome && version >= 30
       
 12856 				|| browser.webkit && version >= 537.76
       
 12857 				|| browser.firefox && version >= 23) {
       
 12858 			var offset = 0;
       
 12859 			if (window.location.href.indexOf(url) === 0) {
       
 12860 				var html = document.getElementsByTagName('html')[0].innerHTML;
       
 12861 				offset = html.substr(0, html.indexOf(code) + 1).match(
       
 12862 						lineBreaks).length + 1;
       
 12863 			}
       
 12864 			var mappings = ['AAAA'];
       
 12865 			mappings.length = (code.match(lineBreaks) || []).length + 1 + offset;
       
 12866 			sourceMap = {
       
 12867 				version: 3,
       
 12868 				file: url,
       
 12869 				names:[],
       
 12870 				mappings: mappings.join(';AACA'),
       
 12871 				sourceRoot: '',
       
 12872 				sources: [url]
       
 12873 			};
       
 12874 			var source = options.source || !url && code;
       
 12875 			if (source)
       
 12876 				sourceMap.sourcesContent = [source];
       
 12877 		}
       
 12878 		walkAST(parse(code, { ranges: true }));
       
 12879 		if (sourceMap) {
       
 12880 			code = new Array(offset + 1).join('\n') + code
       
 12881 					+ "\n//# sourceMappingURL=data:application/json;base64,"
       
 12882 					+ (btoa(unescape(encodeURIComponent(
       
 12883 						JSON.stringify(sourceMap)))))
       
 12884 					+ "\n//# sourceURL=" + (url || 'paperscript');
       
 12885 		}
       
 12886 		return code;
       
 12887 	}
       
 12888 
       
 12889 	function execute(code, scope, url, options) {
       
 12890 		paper = scope;
       
 12891 		var view = scope.getView(),
       
 12892 			tool = /\s+on(?:Key|Mouse)(?:Up|Down|Move|Drag)\b/.test(code)
       
 12893 					? new Tool()
       
 12894 					: null,
       
 12895 			toolHandlers = tool ? tool._events : [],
       
 12896 			handlers = ['onFrame', 'onResize'].concat(toolHandlers),
       
 12897 			params = [],
       
 12898 			args = [],
       
 12899 			func;
       
 12900 		code = compile(code, url, options);
       
 12901 		function expose(scope, hidden) {
       
 12902 			for (var key in scope) {
       
 12903 				if ((hidden || !/^_/.test(key)) && new RegExp('([\\b\\s\\W]|^)'
       
 12904 						+ key.replace(/\$/g, '\\$') + '\\b').test(code)) {
       
 12905 					params.push(key);
       
 12906 					args.push(scope[key]);
       
 12907 				}
       
 12908 			}
       
 12909 		}
       
 12910 		expose({ __$__: __$__, $__: $__, paper: scope, view: view, tool: tool },
       
 12911 				true);
       
 12912 		expose(scope);
       
 12913 		handlers = Base.each(handlers, function(key) {
       
 12914 			if (new RegExp('\\s+' + key + '\\b').test(code)) {
       
 12915 				params.push(key);
       
 12916 				this.push(key + ': ' + key);
       
 12917 			}
       
 12918 		}, []).join(', ');
       
 12919 		if (handlers)
       
 12920 			code += '\nreturn { ' + handlers + ' };';
       
 12921 		var browser = paper.browser;
       
 12922 		if (browser.chrome || browser.firefox) {
       
 12923 			var script = document.createElement('script'),
       
 12924 				head = document.head || document.getElementsByTagName('head')[0];
       
 12925 			if (browser.firefox)
       
 12926 				code = '\n' + code;
       
 12927 			script.appendChild(document.createTextNode(
       
 12928 				'paper._execute = function(' + params + ') {' + code + '\n}'
       
 12929 			));
       
 12930 			head.appendChild(script);
       
 12931 			func = paper._execute;
       
 12932 			delete paper._execute;
       
 12933 			head.removeChild(script);
       
 12934 		} else {
       
 12935 			func = Function(params, code);
       
 12936 		}
       
 12937 		var res = func.apply(scope, args) || {};
       
 12938 		Base.each(toolHandlers, function(key) {
       
 12939 			var value = res[key];
       
 12940 			if (value)
       
 12941 				tool[key] = value;
       
 12942 		});
       
 12943 		if (view) {
       
 12944 			if (res.onResize)
       
 12945 				view.setOnResize(res.onResize);
       
 12946 			view.emit('resize', {
       
 12947 				size: view.size,
       
 12948 				delta: new Point()
       
 12949 			});
       
 12950 			if (res.onFrame)
       
 12951 				view.setOnFrame(res.onFrame);
       
 12952 			view.update();
       
 12953 		}
       
 12954 	}
       
 12955 
       
 12956 	function loadScript(script) {
       
 12957 		if (/^text\/(?:x-|)paperscript$/.test(script.type)
       
 12958 				&& PaperScope.getAttribute(script, 'ignore') !== 'true') {
       
 12959 			var canvasId = PaperScope.getAttribute(script, 'canvas'),
       
 12960 				canvas = document.getElementById(canvasId),
       
 12961 				src = script.src,
       
 12962 				scopeAttribute = 'data-paper-scope';
       
 12963 			if (!canvas)
       
 12964 				throw new Error('Unable to find canvas with id "'
       
 12965 						+ canvasId + '"');
       
 12966 			var scope = PaperScope.get(canvas.getAttribute(scopeAttribute))
       
 12967 						|| new PaperScope().setup(canvas);
       
 12968 			canvas.setAttribute(scopeAttribute, scope._id);
       
 12969 			if (src) {
       
 12970 				Http.request('get', src, function(code) {
       
 12971 					execute(code, scope, src);
       
 12972 				});
       
 12973 			} else {
       
 12974 				execute(script.innerHTML, scope, script.baseURI);
       
 12975 			}
       
 12976 			script.setAttribute('data-paper-ignore', 'true');
       
 12977 			return scope;
       
 12978 		}
       
 12979 	}
       
 12980 
       
 12981 	function loadAll() {
       
 12982 		Base.each(document.getElementsByTagName('script'), loadScript);
       
 12983 	}
       
 12984 
       
 12985 	function load(script) {
       
 12986 		return script ? loadScript(script) : loadAll();
       
 12987 	}
       
 12988 
       
 12989 	if (document.readyState === 'complete') {
       
 12990 		setTimeout(loadAll);
       
 12991 	} else {
       
 12992 		DomEvent.add(window, { load: loadAll });
       
 12993 	}
       
 12994 
       
 12995 	return {
       
 12996 		compile: compile,
       
 12997 		execute: execute,
       
 12998 		load: load,
       
 12999 		parse: parse
       
 13000 	};
       
 13001 
       
 13002 }).call(this);
       
 13003 
       
 13004 paper = new (PaperScope.inject(Base.exports, {
       
 13005 	enumerable: true,
       
 13006 	Base: Base,
       
 13007 	Numerical: Numerical,
       
 13008 	Key: Key
       
 13009 }))();
       
 13010 
       
 13011 if (typeof define === 'function' && define.amd) {
       
 13012 	define('paper', paper);
       
 13013 } else if (typeof module === 'object' && module) {
       
 13014 	module.exports = paper;
       
 13015 }
       
 13016 
       
 13017 return paper;
       
 13018 };