PageSourceSearch

https://www.paulmillerbmw.com/v9/media/js/jquerytransform/v0.9.3/jquery.transform.js

js paulmillerbmw.com collected 2026-09-25 08:09:16 UTC 49,694 bytes, 1,961 lines download raw bytes

1/*!
2 * jQuery 2d Transform v0.9.3
3 * http://wiki.github.com/heygrady/transform/
4 *
5 * Copyright 2010, Grady Kuhnline
6 * Dual licensed under the MIT or GPL Version 2 licenses.
7 * http://jquery.org/license
8 * 
9 * Date: Sat Dec 4 15:46:09 2010 -0800
10 */
11///////////////////////////////////////////////////////
12// Transform
13///////////////////////////////////////////////////////
14(function($, window, document, undefined) {
15	/**
16	 * @var Regex identify the matrix filter in IE
17	 */
18	var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/,
19		rfxnum = /^([\+\-]=)?([\d+.\-]+)(.*)$/,
20		rperc = /%/;
21	
22	// Steal some code from Modernizr
23	var m = document.createElement( 'modernizr' ),
24		m_style = m.style;
25		
26	function stripUnits(arg) {
27		return parseFloat(arg);
28	}
29	
30	/**
31	 * Find the prefix that this browser uses
32	 */	
33	function getVendorPrefix() {
34		var property = {
35			transformProperty : '',
36			MozTransform : '-moz-',
37			WebkitTransform : '-webkit-',
38			OTransform : '-o-',
39			msTransform : '-ms-'
40		};
41		for (var p in property) {
42			if (typeof m_style[p] != 'undefined') {
43				return property[p];
44			}
45		}
46		return null;
47	}
48	
49	function supportCssTransforms() {
50		if (typeof(window.Modernizr) !== 'undefined') {
51			return Modernizr.csstransforms;
52		}
53		
54		var props = [ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ];
55		for ( var i in props ) {
56			if ( m_style[ props[i] ] !== undefined  ) {
57				return true;
58			}
59		}
60	}
61		
62	// Capture some basic properties
63	var vendorPrefix			= getVendorPrefix(),
64		transformProperty		= vendorPrefix !== null ? vendorPrefix + 'transform' : false,
65		transformOriginProperty	= vendorPrefix !== null ? vendorPrefix + 'transform-origin' : false;
66	
67	// store support in the jQuery Support object
68	$.support.csstransforms = supportCssTransforms();
69	
70	// IE9 public preview 6 requires the DOM names
71	if (vendorPrefix == '-ms-') {
72		transformProperty = 'msTransform';
73		transformOriginProperty = 'msTransformOrigin';
74	}
75	
76	/**
77	 * Class for creating cross-browser transformations
78	 * @constructor
79	 */
80	$.extend({
81		transform: function(elem) {
82			// Cache the transform object on the element itself
83			elem.transform = this;
84			
85			/**
86			 * The element we're working with
87			 * @var jQueryCollection
88			 */
89			this.$elem = $(elem);
90						
91			/**
92			 * Remember the matrix we're applying to help the safeOuterLength func
93			 */
94			this.applyingMatrix = false;
95			this.matrix = null;
96			
97			/**
98			 * Remember the css height and width to save time
99			 * This is only really used in IE
100			 * @var Number
101			 */
102			this.height = null;
103			this.width = null;
104			this.outerHeight = null;
105			this.outerWidth = null;
106			
107			/**
108			 * We need to know the box-sizing in IE for building the outerHeight and outerWidth
109			 * @var string
110			 */
111			this.boxSizingValue = null;
112			this.boxSizingProperty = null;
113			
114			this.attr = null;
115			this.transformProperty = transformProperty;
116			this.transformOriginProperty = transformOriginProperty;
117		}
118	});
119	
120	$.extend($.transform, {
121		/**
122		 * @var Array list of all valid transform functions
123		 */
124		funcs: ['matrix', 'origin', 'reflect', 'reflectX', 'reflectXY', 'reflectY', 'rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY']
125	});
126	
127	/**
128	 * Create Transform as a jQuery plugin
129	 * @param Object funcs
130	 * @param Object options
131	 */
132	$.fn.transform = function(funcs, options) {
133		return this.each(function() {
134			var t = this.transform || new $.transform(this);
135			if (funcs) {
136				t.exec(funcs, options);
137			}
138		});
139	};
140	
141	$.transform.prototype = {
142		/**
143		 * Applies all of the transformations
144		 * @param Object funcs
145		 * @param Object options
146		 * forceMatrix - uses the matrix in all browsers
147		 * preserve - tries to preserve the values from previous runs
148		 */
149		exec: function(funcs, options) {
150			// extend options
151			options = $.extend(true, {
152				forceMatrix: false,
153				preserve: false
154			}, options);
155	
156			// preserve the funcs from the previous run
157			this.attr = null;
158			if (options.preserve) {
159				funcs = $.extend(true, this.getAttrs(true, true), funcs);
160			} else {
161				funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness
162			}
163			
164			// Record the custom attributes on the element itself
165			this.setAttrs(funcs);
166			
167			// apply the funcs
168			if ($.support.csstransforms && !options.forceMatrix) {
169				// CSS3 is supported
170				return this.execFuncs(funcs);
171			} else if ($.browser.msie || ($.support.csstransforms && options.forceMatrix)) {
172				// Internet Explorer or Forced matrix
173				return this.execMatrix(funcs);
174			}
175			return false;
176		},
177		
178		/**
179		 * Applies all of the transformations as functions
180		 * @param Object funcs
181		 */
182		execFuncs: function(funcs) {
183			var values = [];
184			
185			// construct a CSS string
186			for (var func in funcs) {
187				// handle origin separately
188				if (func == 'origin') {
189					this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]);
190				} else if ($.inArray(func, $.transform.funcs) !== -1) {
191					values.push(this.createTransformFunc(func, funcs[func]));
192				}
193			}
194			this.$elem.css(transformProperty, values.join(' '));
195			return true;
196		},
197		
198		/**
199		 * Applies all of the transformations as a matrix
200		 * @param Object funcs
201		 */
202		execMatrix: function(funcs) {
203			var matrix,
204				tempMatrix,
205				args;
206			
207			var elem = this.$elem[0],
208				_this = this;
209			function normalPixels(val, i) {
210				if (rperc.test(val)) {
211					// this really only applies to translation
212					return parseFloat(val) / 100 * _this['safeOuter' + (i ? 'Height' : 'Width')]();
213				}
214				return toPx(elem, val);
215			}
216			
217			var rtranslate = /translate[X|Y]?/,
218				trans = [];
219				
220			for (var func in funcs) {
221				switch ($.type(funcs[func])) {
222					case 'array': args = funcs[func]; break;
223					case 'string': args = $.map(funcs[func].split(','), $.trim); break;
224					default: args = [funcs[func]];
225				}
226				
227				if ($.matrix[func]) {
228					
229					if ($.cssAngle[func]) {
230						// normalize on degrees
231						args = $.map(args, $.angle.toDegree);						
232					} else if (!$.cssNumber[func]) {
233						// normalize to pixels
234						args = $.map(args, normalPixels);
235					} else {
236						// strip units
237						args = $.map(args, stripUnits);
238					}
239					
240					tempMatrix = $.matrix[func].apply(this, args);
241					if (rtranslate.test(func)) {
242						//defer translation
243						trans.push(tempMatrix);
244					} else {
245						matrix = matrix ? matrix.x(tempMatrix) : tempMatrix;
246					}
247				} else if (func == 'origin') {
248					this[func].apply(this, args);
249				}
250			}
251			
252			// check that we have a matrix
253			matrix = matrix || $.matrix.identity();
254			
255			// Apply translation
256			$.each(trans, function(i, val) { matrix = matrix.x(val); });
257
258			// pull out the relevant values
259			var a = parseFloat(matrix.e(1,1).toFixed(6)),
260				b = parseFloat(matrix.e(2,1).toFixed(6)),
261				c = parseFloat(matrix.e(1,2).toFixed(6)),
262				d = parseFloat(matrix.e(2,2).toFixed(6)),
263				tx = matrix.rows === 3 ? parseFloat(matrix.e(1,3).toFixed(6)) : 0,
264				ty = matrix.rows === 3 ? parseFloat(matrix.e(2,3).toFixed(6)) : 0;
265			
266			//apply the transform to the element
267			if ($.support.csstransforms && vendorPrefix === '-moz-') {
268				// -moz-
269				this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)');
270			} else if ($.support.csstransforms) {
271				// -webkit, -o-, w3c
272				// NOTE: WebKit and Opera don't allow units on the translate variables
273				this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')');
274			} else if ($.browser.msie) {
275				// IE requires the special transform Filter
276				
277				//TODO: Use Nearest Neighbor during animation FilterType=\'nearest neighbor\'
278				var filterType = ', FilterType=\'nearest neighbor\''; //bilinear
279				var style = this.$elem[0].style;
280				var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(' +
281						'M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d +
282						', sizingMethod=\'auto expand\'' + filterType + ')';
283				var filter = style.filter || $.curCSS( this.$elem[0], "filter" ) || "";
284				style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter;
285				
286				// Let's know that we're applying post matrix fixes and the height/width will be static for a bit
287				this.applyingMatrix = true;
288				this.matrix = matrix;
289				
290				// IE can't set the origin or translate directly
291				this.fixPosition(matrix, tx, ty);
292				
293				this.applyingMatrix = false;
294				this.matrix = null;
295			}
296			return true;
297		},
298		
299		/**
300		 * Sets the transform-origin
301		 * This really needs to be percentages
302		 * @param Number x length
303		 * @param Number y length
304		 */
305		origin: function(x, y) {
306			// use CSS in supported browsers
307			if ($.support.csstransforms) {
308				if (typeof y === 'undefined') {
309					this.$elem.css(transformOriginProperty, x);
310				} else {
311					this.$elem.css(transformOriginProperty, x + ' ' + y);
312				}
313				return true;
314			}
315			
316			// correct for keyword lengths
317			switch (x) {
318				case 'left': x = '0'; break;
319				case 'right': x = '100%'; break;
320				case 'center': // no break
321				case undefined: x = '50%';
322			}
323			switch (y) {
324				case 'top': y = '0'; break;
325				case 'bottom': y = '100%'; break;
326				case 'center': // no break
327				case undefined: y = '50%'; //TODO: does this work?
328			}
329			
330			// store mixed values with units, assumed pixels
331			this.setAttr('origin', [
332				rperc.test(x) ? x : toPx(this.$elem[0], x) + 'px',
333				rperc.test(y) ? y : toPx(this.$elem[0], y) + 'px'
334			]);
335			//console.log(this.getAttr('origin'));
336			return true;
337		},
338		
339		/**
340		 * Create a function suitable for a CSS value
341		 * @param string func
342		 * @param Mixed value
343		 */
344		createTransformFunc: function(func, value) {
345			if (func.substr(0, 7) === 'reflect') {
346				// let's fake reflection, false value 
347				// falsey sets an identity matrix
348				var m = value ? $.matrix[func]() : $.matrix.identity();
349				return 'matrix(' + m.e(1,1) + ', ' + m.e(2,1) + ', ' + m.e(1,2) + ', ' + m.e(2,2) + ', 0, 0)';
350			}
351			
352			//value = _correctUnits(func, value);
353			
354			if (func == 'matrix') {
355				if (vendorPrefix === '-moz-') {
356					value[4] = value[4] ? value[4] + 'px' : 0;
357					value[5] = value[5] ? value[5] + 'px' : 0;
358				}
359			}
360			return func + '(' + ($.isArray(value) ? value.join(', ') : value) + ')';
361		},
362		
363		/**
364		 * @param Matrix matrix
365		 * @param Number tx
366		 * @param Number ty
367		 * @param Number height
368		 * @param Number width
369		 */
370		fixPosition: function(matrix, tx, ty, height, width) {
371			// now we need to fix it!
372			var	calc = new $.matrix.calc(matrix, this.safeOuterHeight(), this.safeOuterWidth()),
373				origin = this.getAttr('origin'); // mixed percentages and px
374			
375			// translate a 0, 0 origin to the current origin
376			var offset = calc.originOffset(new $.matrix.V2(
377				rperc.test(origin[0]) ? parseFloat(origin[0])/100*calc.outerWidth : parseFloat(origin[0]),
378				rperc.test(origin[1]) ? parseFloat(origin[1])/100*calc.outerHeight : parseFloat(origin[1])
379			));
380			
381			// IE glues the top-most and left-most pixels of the transformed object to top/left of the original object
382			//TODO: This seems wrong in the calculations
383			var sides = calc.sides();
384
385			// Protect against an item that is already positioned
386			var cssPosition = this.$elem.css('position');
387			if (cssPosition == 'static') {
388				cssPosition = 'relative';
389			}
390			
391			//TODO: if the element is already positioned, we should attempt to respect it (somehow)
392			//NOTE: we could preserve our offset top and left in an attr on the elem
393			var pos = {top: 0, left: 0};
394			
395			// Approximates transform-origin, tx, and ty
396			var css = {
397				'position': cssPosition,
398				'top': (offset.top + ty + sides.top + pos.top) + 'px',
399				'left': (offset.left + tx + sides.left + pos.left) + 'px',
400				'zoom': 1
401			};
402
403			this.$elem.css(css);
404		}
405	};
406	
407	/**
408	 * Ensure that values have the appropriate units on them
409	 * @param string func
410	 * @param Mixed value
411	 */
412	function toPx(elem, val) {
413		var parts = rfxnum.exec($.trim(val));
414		
415		if (parts[3] && parts[3] !== 'px') {
416			var prop = 'paddingBottom',
417				orig = $.style( elem, prop );
418				
419			$.style( elem, prop, val );
420			val = cur( elem, prop );
421			$.style( elem, prop, orig );
422			return val;
423		}
424		return parseFloat( val );
425	}
426	
427	function cur(elem, prop) {
428		if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
429			return elem[ prop ];
430		}
431
432		var r = parseFloat( $.css( elem, prop ) );
433		return r && r > -10000 ? r : 0;
434	}
435})(jQuery, this, this.document);
436
437
438///////////////////////////////////////////////////////
439// Safe Outer Length
440///////////////////////////////////////////////////////
441(function($, window, document, undefined) {
442	$.extend($.transform.prototype, {
443		/**
444		 * @param void
445		 * @return Number
446		 */
447		safeOuterHeight: function() {
448			return this.safeOuterLength('height');
449		},
450		
451		/**
452		 * @param void
453		 * @return Number
454		 */
455		safeOuterWidth: function() {
456			return this.safeOuterLength('width');
457		},
458		
459		/**
460		 * Returns reliable outer dimensions for an object that may have been transformed.
461		 * Only use this if the matrix isn't handy
462		 * @param String dim height or width
463		 * @return Number
464		 */
465		safeOuterLength: function(dim) {
466			var funcName = 'outer' + (dim == 'width' ? 'Width' : 'Height');
467			
468			if (!$.support.csstransforms && $.browser.msie) {
469				// make the variables more generic
470				dim = dim == 'width' ? 'width' : 'height';
471				
472				// if we're transforming and have a matrix; we can shortcut.
473				// the true outerHeight is the transformed outerHeight divided by the ratio.
474				// the ratio is equal to the height of a 1px by 1px box that has been transformed by the same matrix.
475				if (this.applyingMatrix && !this[funcName] && this.matrix) {
476					// calculate and return the correct size
477					var calc = new $.matrix.calc(this.matrix, 1, 1),
478						ratio = calc.offset(),
479						length = this.$elem[funcName]() / ratio[dim];
480					this[funcName] = length;
481					
482					return length;
483				} else if (this.applyingMatrix && this[funcName]) {
484					// return the cached calculation
485					return this[funcName];
486				}
487				
488				// map dimensions to box sides			
489				var side = {
490					height: ['top', 'bottom'],
491					width: ['left', 'right']
492				};
493				
494				// setup some variables
495				var elem = this.$elem[0],
496					outerLen = parseFloat($.curCSS(elem, dim, true)), //TODO: this can be cached on animations that do not animate height/width
497					boxSizingProp = this.boxSizingProperty,
498					boxSizingValue = this.boxSizingValue;
499				
500				// IE6 && IE7 will never have a box-sizing property, so fake it
501				if (!this.boxSizingProperty) {
502					boxSizingProp = this.boxSizingProperty = _findBoxSizingProperty() || 'box-sizing';
503					boxSizingValue = this.boxSizingValue = this.$elem.css(boxSizingProp) || 'content-box';
504				}
505				
506				// return it immediately if we already know it
507				if (this[funcName] && this[dim] == outerLen) {
508					return this[funcName];
509				} else {
510					this[dim] = outerLen;
511				}
512				
513				// add in the padding and border
514				if (boxSizingProp && (boxSizingValue == 'padding-box' || boxSizingValue == 'content-box')) {
515					outerLen += parseFloat($.curCSS(elem, 'padding-' + side[dim][0], true)) || 0 +
516								  parseFloat($.curCSS(elem, 'padding-' + side[dim][1], true)) || 0;
517				}
518				if (boxSizingProp && boxSizingValue == 'content-box') {
519					outerLen += parseFloat($.curCSS(elem, 'border-' + side[dim][0] + '-width', true)) || 0 +
520								  parseFloat($.curCSS(elem, 'border-' + side[dim][1] + '-width', true)) || 0;
521				}
522				
523				// remember and return the outerHeight
524				this[funcName] = outerLen;
525				return outerLen;
526			}
527			return this.$elem[funcName]();
528		}
529	});
530	
531	/**
532	 * Determine the correct property for checking the box-sizing property
533	 * @param void
534	 * @return string
535	 */
536	var _boxSizingProperty = null;
537	function _findBoxSizingProperty () {
538		if (_boxSizingProperty) {
539			return _boxSizingProperty;
540		} 
541		
542		var property = {
543				boxSizing : 'box-sizing',
544				MozBoxSizing : '-moz-box-sizing',
545				WebkitBoxSizing : '-webkit-box-sizing',
546				OBoxSizing : '-o-box-sizing'
547			},
548			elem = document.body;
549		
550		for (var p in property) {
551			if (typeof elem.style[p] != 'undefined') {
552				_boxSizingProperty = property[p];
553				return _boxSizingProperty;
554			}
555		}
556		return null;
557	}
558})(jQuery, this, this.document);
559
560
561///////////////////////////////////////////////////////
562// Attr
563///////////////////////////////////////////////////////
564(function($, window, document, undefined) {
565	var rfuncvalue = /([\w\-]*?)\((.*?)\)/g, // with values
566		attr = 'data-transform',
567		rspace = /\s/,
568		rcspace = /,\s?/;
569	
570	$.extend($.transform.prototype, {		
571		/**
572		 * This overrides all of the attributes
573		 * @param Object funcs a list of transform functions to store on this element
574		 * @return void
575		 */
576		setAttrs: function(funcs) {
577			var string = '',
578				value;
579			for (var func in funcs) {
580				value = funcs[func];
581				if ($.isArray(value)) {
582					value = value.join(', ');
583				}
584				string += ' ' + func + '(' + value + ')'; 
585			}
586			this.attr = $.trim(string);
587			this.$elem.attr(attr, this.attr);
588		},
589		
590		/**
591		 * This sets only a specific atribute
592		 * @param string func name of a transform function
593		 * @param mixed value with proper units
594		 * @return void
595		 */
596		setAttr: function(func, value) {
597			// stringify the value
598			if ($.isArray(value)) {
599				value = value.join(', ');
600			}
601			
602			// pull from a local variable to look it up
603			var transform = this.attr || this.$elem.attr(attr);
604			if (!transform || transform.indexOf(func) == -1) {
605				// we don't have any existing values, save it
606				// we don't have this function yet, save it
607				this.attr = $.trim(transform + ' ' + func + '(' + value + ')');
608				this.$elem.attr(attr, this.attr);
609			} else {
610				// replace the existing value
611				var funcs = [],	parts;
612				
613				// regex split
614				rfuncvalue.lastIndex = 0; // reset the regex pointer
615				while (parts = rfuncvalue.exec(transform)) {
616					if (func == parts[1]) {
617						funcs.push(func + '(' + value + ')');
618					} else {
619						funcs.push(parts[0]);
620					}
621				}
622				this.attr = funcs.join(' ');
623				this.$elem.attr(attr, this.attr);
624			}
625		},
626		
627		/**
628		 * @return Object
629		 */
630		getAttrs: function() {
631			var transform = this.attr || this.$elem.attr(attr);
632			if (!transform) {
633				// We don't have any existing values, return empty object
634				return {};
635			}
636			
637			// replace the existing value
638			var attrs = {}, parts, value;
639			
640			rfuncvalue.lastIndex = 0; // reset the regex pointer
641			while ((parts = rfuncvalue.exec(transform)) !== null) {
642				if (parts) {
643					value = parts[2].split(rcspace);
644					attrs[parts[1]] = value.length == 1 ? value[0] : value;
645				}
646			}
647			return attrs;
648		},
649		
650		/**
651		 * @param String func 
652		 * @return mixed
653		 */
654		getAttr: function(func) {
655			var attrs = this.getAttrs();
656			if (typeof attrs[func] !== 'undefined') {
657				return attrs[func];
658			}
659			
660			//TODO: move the origin to a function
661			if (func === 'origin' && $.support.csstransforms) {
662				// supported browsers return percentages always
663				return this.$elem.css(this.transformOriginProperty).split(rspace);
664			} else if (func === 'origin') {
665				// just force IE to also return a percentage
666				return ['50%', '50%'];
667			}
668			
669			return $.cssDefault[func] || 0;
670		}
671	});
672	
673	// Define 
674	if (typeof($.cssAngle) == 'undefined') {
675		$.cssAngle = {};
676	}
677	$.extend($.cssAngle, {
678		rotate: true,
679		skew: true,
680		skewX: true,
681		skewY: true
682	});
683	
684	// Define default values
685	if (typeof($.cssDefault) == 'undefined') {
686		$.cssDefault = {};
687	}
688	
689	$.extend($.cssDefault, {
690		scale: [1, 1],
691		scaleX: 1,
692		scaleY: 1,
693		matrix: [1, 0, 0, 1, 0, 0],
694		origin: ['50%', '50%'], // TODO: allow this to be a function, like get
695		reflect: [1, 0, 0, 1, 0, 0],
696		reflectX: [1, 0, 0, 1, 0, 0],
697		reflectXY: [1, 0, 0, 1, 0, 0],
698		reflectY: [1, 0, 0, 1, 0, 0]
699	});
700	
701	// Define functons with multiple values
702	if (typeof($.cssMultipleValues) == 'undefined') {
703		$.cssMultipleValues = {};
704	}
705	$.extend($.cssMultipleValues, {
706		matrix: 6,
707		origin: {
708			length: 2,
709			duplicate: true
710		},
711		reflect: 6,
712		reflectX: 6,
713		reflectXY: 6,
714		reflectY: 6,
715		scale: {
716			length: 2,
717			duplicate: true
718		},
719		skew: 2,
720		translate: 2
721	});
722	
723	// specify unitless funcs
724	$.extend($.cssNumber, {
725		matrix: true,
726		reflect: true,
727		reflectX: true,
728		reflectXY: true,
729		reflectY: true,
730		scale: true,
731		scaleX: true,
732		scaleY: true
733	});
734	
735	// override all of the css functions
736	$.each($.transform.funcs, function(i, func) {
737		$.cssHooks[func] = {
738			set: function(elem, value) {
739				var transform = elem.transform || new $.transform(elem),
740					funcs = {};
741				funcs[func] = value;
742				transform.exec(funcs, {preserve: true});
743			},
744			get: function(elem, computed) {
745				var transform = elem.transform || new $.transform(elem);
746				return transform.getAttr(func);
747			}
748		};
749	});
750	
751	// Support Reflection animation better by returning a matrix
752	$.each(['reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
753		$.cssHooks[func].get = function(elem, computed) {
754			var transform = elem.transform || new $.transform(elem);
755			return transform.getAttr('matrix') || $.cssDefault[func];
756		};
757	});
758})(jQuery, this, this.document);
759///////////////////////////////////////////////////////
760// Animation
761///////////////////////////////////////////////////////
762(function($, window, document, undefined) {
763	/**
764	 * @var Regex looks for units on a string
765	 */
766	var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
767	
768	/**
769	 * Doctors prop values in the event that they contain spaces
770	 * @param Object prop
771	 * @param String speed
772	 * @param String easing
773	 * @param Function callback
774	 * @return bool
775	 */
776	var _animate = $.fn.animate;
777	$.fn.animate = function( prop, speed, easing, callback ) {
778		var optall = $.speed(speed, easing, callback),
779			mv = $.cssMultipleValues;
780		
781		// Speed always creates a complete function that must be reset
782		optall.complete = optall.old;
783		
784		// Capture multiple values
785		if (!$.isEmptyObject(prop)) {
786			if (typeof optall.original === 'undefined') {
787				optall.original = {};
788			}
789			$.each( prop, function( name, val ) {
790				if (mv[name]
791					|| $.cssAngle[name]
792					|| (!$.cssNumber[name] && $.inArray(name, $.transform.funcs) !== -1)) {
793					
794					// Handle special easing
795					var specialEasing = null;
796					if (jQuery.isArray(prop[name])) {
797						var mvlen = 1, len = val.length;
798						if (mv[name]) {
799							mvlen = (typeof mv[name].length === 'undefined' ? mv[name] : mv[name].length);
800						}
801						if ( len > mvlen
802							|| (len < mvlen && len == 2)
803							|| (len == 2 && mvlen == 2 && isNaN(parseFloat(val[len - 1])))) {
804							
805							specialEasing = val[len - 1];
806							val.splice(len - 1, 1);
807						}
808					}
809					
810					// Store the original values onto the optall
811					optall.original[name] = val.toString();
812					
813					// reduce to a unitless number (to trick animate)
814					prop[name] = parseFloat(val);
815				}
816			} );
817		}
818		
819		//NOTE: we edited prop above to trick animate
820		//NOTE: we pre-convert to an optall so we can doctor it
821		return _animate.apply(this, [arguments[0], optall]);
822	};
823	
824	var prop = 'paddingBottom';
825	function cur(elem, prop) {
826		if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
827			//return elem[ prop ];
828		}
829
830		var r = parseFloat( $.css( elem, prop ) );
831		return r && r > -10000 ? r : 0;
832	}
833	
834	var _custom = $.fx.prototype.custom;
835	$.fx.prototype.custom = function(from, to, unit) {
836		var multiple = $.cssMultipleValues[this.prop],
837			angle = $.cssAngle[this.prop];
838		
839		//TODO: simply check for the existence of CSS Hooks?
840		if (multiple || (!$.cssNumber[this.prop] && $.inArray(this.prop, $.transform.funcs) !== -1)) {
841			this.values = [];
842			
843			if (!multiple) {
844				multiple = 1;
845			}
846			
847			// Pull out the known values
848			var values = this.options.original[this.prop],
849				currentValues = $(this.elem).css(this.prop),
850				defaultValues = $.cssDefault[this.prop] || 0;
851			
852			// make sure the current css value is an array
853			if (!$.isArray(currentValues)) {
854				currentValues = [currentValues];
855			}
856			
857			// make sure the new values are an array
858			if (!$.isArray(values)) {
859				if ($.type(values) === 'string') {
860					values = values.split(',');
861				} else {
862					values = [values];
863				}
864			}
865			
866			// make sure we have enough new values
867			var length = multiple.length || multiple, i = 0;
868			while (values.length < length) {
869				values.push(multiple.duplicate ? values[0] : defaultValues[i] || 0);
870				i++;
871			}
872			
873			// calculate a start, end and unit for each new value
874			var start, parts, end, //unit,
875				fx = this,
876				transform = fx.elem.transform;
877				orig = $.style(fx.elem, prop);
878
879			$.each(values, function(i, val) {
880				// find a sensible start value
881				if (currentValues[i]) {
882					start = currentValues[i];
883				} else if (defaultValues[i] && !multiple.duplicate) {
884					start = defaultValues[i];
885				} else if (multiple.duplicate) {
886					start = currentValues[0];
887				} else {
888					start = 0;
889				}
890				
891				// Force the correct unit on the start
892				if (angle) {
893					start = $.angle.toDegree(start);
894				} else if (!$.cssNumber[fx.prop]) {
895					parts = rfxnum.exec($.trim(start));
896					if (parts[3] && parts[3] !== 'px') {
897						if (parts[3] === '%') {
898							start = parseFloat( parts[2] ) / 100 * transform['safeOuter' + (i ? 'Height' : 'Width')]();
899						} else {
900							$.style( fx.elem, prop, start);
901							start = cur(fx.elem, prop);
902							$.style( fx.elem, prop, orig);
903						}
904					}
905				}
906				start = parseFloat(start);
907				
908				// parse the value with a regex
909				parts = rfxnum.exec($.trim(val));
910				
911				if (parts) {
912					// we found a sensible value and unit
913					end = parseFloat( parts[2] );
914					unit = parts[3] || "px"; //TODO: change to an appropriate default unit
915					
916					if (angle) {
917						end = $.angle.toDegree(end + unit);
918						unit = 'deg';
919					} else if (!$.cssNumber[fx.prop] && unit === '%') {
920						start = (start / transform['safeOuter' + (i ? 'Height' : 'Width')]()) * 100;
921					} else if (!$.cssNumber[fx.prop] && unit !== 'px') {
922						$.style( fx.elem, prop, (end || 1) + unit);
923						start = ((end || 1) / cur(fx.elem, prop)) * start;
924						$.style( fx.elem, prop, orig);
925					}
926					
927					// If a +=/-= token was provided, we're doing a relative animation
928					if (parts[1]) {
929						end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
930					}
931				} else {
932					// I don't know when this would happen
933					end = val;
934					unit = ''; 
935				}
936								
937				// Save the values
938				fx.values.push({
939					start: start,
940					end: end,
941					unit: unit
942				});				
943			});
944		}
945		return _custom.apply(this, arguments);
946	};
947	
948	/**
949	 * Animates a multi value attribute
950	 * @param Object fx
951	 * @return null
952	 */
953	$.fx.multipleValueStep = {
954		_default: function(fx) {
955			$.each(fx.values, function(i, val) {
956				fx.values[i].now = val.start + ((val.end - val.start) * fx.pos);
957			});
958		}
959	};
960	$.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
961		$.fx.multipleValueStep[func] = function(fx) {
962			var d = fx.decomposed,
963				$m = $.matrix;
964				m = $m.identity();
965			
966			d.now = {};
967			
968			// increment each part of the decomposition and recompose it		
969			$.each(d.start, function(k) {				
970				// calculate the current value
971				d.now[k] = parseFloat(d.start[k]) + ((parseFloat(d.end[k]) - parseFloat(d.start[k])) * fx.pos);
972				
973				// skip functions that won't affect the transform
974				if (((k === 'scaleX' || k === 'scaleY') && d.now[k] === 1) ||
975					(k !== 'scaleX' && k !== 'scaleY' && d.now[k] === 0)) {
976					return true;
977				}
978				
979				// calculating
980				m = m.x($m[k](d.now[k]));
981			});
982			
983			// save the correct matrix values for the value of now
984			var val;
985			$.each(fx.values, function(i) {
986				switch (i) {
987					case 0: val = parseFloat(m.e(1, 1).toFixed(6)); break;
988					case 1: val = parseFloat(m.e(2, 1).toFixed(6)); break;
989					case 2: val = parseFloat(m.e(1, 2).toFixed(6)); break;
990					case 3: val = parseFloat(m.e(2, 2).toFixed(6)); break;
991					case 4: val = parseFloat(m.e(1, 3).toFixed(6)); break;
992					case 5: val = parseFloat(m.e(2, 3).toFixed(6)); break;
993				}
994				fx.values[i].now = val;
995			});
996		};
997	});
998	/**
999	 * Step for animating tranformations
1000	 */
1001	$.each($.transform.funcs, function(i, func) {
1002		$.fx.step[func] = function(fx) {
1003			var transform = fx.elem.transform || new $.transform(fx.elem),
1004				funcs = {};
1005			
1006			if ($.cssMultipleValues[func] || (!$.cssNumber[func] && $.inArray(func, $.transform.funcs) !== -1)) {
1007				($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
1008				funcs[fx.prop] = [];
1009				$.each(fx.values, function(i, val) {
1010					funcs[fx.prop].push(val.now + ($.cssNumber[fx.prop] ? '' : val.unit));
1011				});
1012			} else {
1013				funcs[fx.prop] = fx.now + ($.cssNumber[fx.prop] ? '' : fx.unit);
1014			}
1015			
1016			transform.exec(funcs, {preserve: true});
1017		};
1018	});
1019	
1020	// Support matrix animation
1021	$.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
1022		$.fx.step[func] = function(fx) {
1023			var transform = fx.elem.transform || new $.transform(fx.elem),
1024				funcs = {};
1025				
1026			if (!fx.initialized) {
1027				fx.initialized = true;
1028
1029				// Reflections need a sensible end value set
1030				if (func !== 'matrix') {
1031					var values = $.matrix[func]().elements;
1032					var val;
1033					$.each(fx.values, function(i) {
1034						switch (i) {
1035							case 0: val = values[0]; break;
1036							case 1: val = values[2]; break;
1037							case 2: val = values[1]; break;
1038							case 3: val = values[3]; break;
1039							default: val = 0;
1040						}
1041						fx.values[i].end = val;
1042					});
1043				}
1044				
1045				// Decompose the start and end
1046				fx.decomposed = {};
1047				var v = fx.values;
1048				
1049				fx.decomposed.start = $.matrix.matrix(v[0].start, v[1].start, v[2].start, v[3].start, v[4].start, v[5].start).decompose();
1050				fx.decomposed.end = $.matrix.matrix(v[0].end, v[1].end, v[2].end, v[3].end, v[4].end, v[5].end).decompose();
1051			}
1052			
1053			($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
1054			funcs.matrix = [];
1055			$.each(fx.values, function(i, val) {
1056				funcs.matrix.push(val.now);
1057			});
1058			
1059			transform.exec(funcs, {preserve: true});
1060		};
1061	});
1062})(jQuery, this, this.document);
1063///////////////////////////////////////////////////////
1064// Angle
1065///////////////////////////////////////////////////////
1066(function($, window, document, undefined) {
1067	/**
1068	 * Converting a radian to a degree
1069	 * @const
1070	 */
1071	var RAD_DEG = 180/Math.PI;
1072	
1073	/**
1074	 * Converting a radian to a grad
1075	 * @const
1076	 */
1077	var RAD_GRAD = 200/Math.PI;
1078	
1079	/**
1080	 * Converting a degree to a radian
1081	 * @const
1082	 */
1083	var DEG_RAD = Math.PI/180;
1084	
1085	/**
1086	 * Converting a degree to a grad
1087	 * @const
1088	 */
1089	var DEG_GRAD = 2/1.8;
1090	
1091	/**
1092	 * Converting a grad to a degree
1093	 * @const
1094	 */
1095	var GRAD_DEG = 0.9;
1096	
1097	/**
1098	 * Converting a grad to a radian
1099	 * @const
1100	 */
1101	var GRAD_RAD = Math.PI/200;
1102	
1103	
1104	var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
1105	
1106	/**
1107	 * Functions for converting angles
1108	 * @var Object
1109	 */
1110	$.extend({
1111		angle: {
1112			/**
1113			 * available units for an angle
1114			 * @var Regex
1115			 */
1116			runit: /(deg|g?rad)/,
1117			
1118			/**
1119			 * Convert a radian into a degree
1120			 * @param Number rad
1121			 * @return Number
1122			 */
1123			radianToDegree: function(rad) {
1124				return rad * RAD_DEG;
1125			},
1126			
1127			/**
1128			 * Convert a radian into a degree
1129			 * @param Number rad
1130			 * @return Number
1131			 */
1132			radianToGrad: function(rad) {
1133				return rad * RAD_GRAD;
1134			},
1135			
1136			/**
1137			 * Convert a degree into a radian
1138			 * @param Number deg
1139			 * @return Number
1140			 */
1141			degreeToRadian: function(deg) {
1142				return deg * DEG_RAD;
1143			},
1144			
1145			/**
1146			 * Convert a degree into a radian
1147			 * @param Number deg
1148			 * @return Number
1149			 */
1150			degreeToGrad: function(deg) {
1151				return deg * DEG_GRAD;
1152			},
1153			
1154			/**
1155			 * Convert a grad into a degree
1156			 * @param Number grad
1157			 * @return Number
1158			 */
1159			gradToDegree: function(grad) {
1160				return grad * GRAD_DEG;
1161			},
1162			
1163			/**
1164			 * Convert a grad into a radian
1165			 * @param Number grad
1166			 * @return Number
1167			 */
1168			gradToRadian: function(grad) {
1169				return grad * GRAD_RAD;
1170			},
1171			
1172			/**
1173			 * Convert an angle with a unit to a degree
1174			 * @param String val angle with a unit
1175			 * @return Number
1176			 */
1177			toDegree: function (val) {
1178				var parts = rfxnum.exec(val);
1179				if (parts) {
1180					val = parseFloat( parts[2] );
1181					switch (parts[3] || 'deg') {
1182						case 'grad':
1183							val = $.angle.gradToDegree(val);
1184							break;
1185						case 'rad':
1186							val = $.angle.radianToDegree(val);
1187							break;
1188					}
1189					return val;
1190				}
1191				return 0;
1192			}
1193		}
1194	});
1195})(jQuery, this, this.document);
1196///////////////////////////////////////////////////////
1197// Matrix
1198///////////////////////////////////////////////////////
1199(function($, window, document, undefined) {
1200	/**
1201	 * Matrix object for creating matrices relevant for 2d Transformations
1202	 * @var Object
1203	 */
1204	if (typeof($.matrix) == 'undefined') {
1205		$.extend({
1206			matrix: {}
1207		});
1208	}
1209	var $m = $.matrix;
1210	
1211	$.extend( $m, {
1212		/**
1213		 * A 2-value vector
1214		 * @param Number x
1215		 * @param Number y
1216		 * @constructor
1217		 */
1218		V2: function(x, y){
1219			if ($.isArray(arguments[0])) {
1220				this.elements = arguments[0].slice(0, 2);
1221			} else {
1222				this.elements = [x, y];
1223			}
1224			this.length = 2;
1225		},
1226		
1227		/**
1228		 * A 2-value vector
1229		 * @param Number x
1230		 * @param Number y
1231		 * @param Number z
1232		 * @constructor
1233		 */
1234		V3: function(x, y, z){
1235			if ($.isArray(arguments[0])) {
1236				this.elements = arguments[0].slice(0, 3);
1237			} else {
1238				this.elements = [x, y, z];
1239			}
1240			this.length = 3;
1241		},
1242		
1243		/**
1244		 * A 2x2 Matrix, useful for 2D-transformations without translations
1245		 * @param Number mn
1246		 * @constructor
1247		 */
1248		M2x2: function(m11, m12, m21, m22) {
1249			if ($.isArray(arguments[0])) {
1250				this.elements = arguments[0].slice(0, 4);
1251			} else {
1252				this.elements = Array.prototype.slice.call(arguments).slice(0, 4);
1253			}
1254			this.rows = 2;
1255			this.cols = 2;
1256		},
1257		
1258		/**
1259		 * A 3x3 Matrix, useful for 3D-transformations without translations
1260		 * @param Number mn
1261		 * @constructor
1262		 */
1263		M3x3: function(m11, m12, m13, m21, m22, m23, m31, m32, m33) {
1264			if ($.isArray(arguments[0])) {
1265				this.elements = arguments[0].slice(0, 9);
1266			} else {
1267				this.elements = Array.prototype.slice.call(arguments).slice(0, 9);
1268			}
1269			this.rows = 3;
1270			this.cols = 3;
1271		}
1272	});
1273	
1274	/** generic matrix prototype */
1275	var Matrix = {
1276		/**
1277		 * Return a specific element from the matrix
1278		 * @param Number row where 1 is the 0th row
1279		 * @param Number col where 1 is the 0th column
1280		 * @return Number
1281		 */
1282		e: function(row, col) {
1283			var rows = this.rows,
1284				cols = this.cols;
1285			
1286			// return 0 on nonsense rows and columns
1287			if (row > rows || col >
1287 rows || row < 1 || col < 1) {
1288				return 0;
1289			}
1290			
1291			return this.elements[(row - 1) * cols + col - 1];
1292		},
1293		
1294		/**
1295		 * Taken from Zoomooz
1296	     * https://github.com/jaukia/zoomooz/blob/c7a37b9a65a06ba730bd66391bbd6fe8e55d3a49/js/jquery.zoomooz.js
1297		 */
1298		decompose: function() {
1299			var a = this.e(1, 1),
1300				b = this.e(2, 1),
1301				c = this.e(1, 2),
1302				d = this.e(2, 2),
1303				e = this.e(1, 3),
1304				f = this.e(2, 3);
1305				
1306			// In case the matrix can't be decomposed
1307			if (Math.abs(a * d - b * c) < 0.01) {
1308				return {
1309					rotate: 0 + 'deg',
1310					skewX: 0 + 'deg',
1311					scaleX: 1,
1312					scaleY: 1,
1313					translateX: 0 + 'px',
1314					translateY: 0 + 'px'
1315				};
1316			}
1317			
1318			// Translate is easy
1319			var tx = e, ty = f;
1320			
1321			// factor out the X scale
1322			var sx = Math.sqrt(a * a + b * b);
1323			a = a/sx;
1324			b = b/sx;
1325			
1326			// factor out the skew
1327			var k = a * c + b * d;
1328			c -= a * k;
1329			d -= b * k;
1330			
1331			// factor out the Y scale
1332			var sy = Math.sqrt(c * c + d * d);
1333			c = c / sy;
1334			d = d / sy;
1335			k = k / sy;
1336			
1337			// account for negative scale
1338			if ((a * d - b * c) < 0.0) {
1339				a = -a;
1340				b = -b;
1341				//c = -c; // accomplishes nothing to negate it
1342				//d = -d; // accomplishes nothing to negate it
1343				sx = -sx;
1344				//sy = -sy //Scale Y shouldn't ever be negated
1345			}
1346			
1347			// calculate the rotation angle and skew angle
1348			var rad2deg = $.angle.radianToDegree;
1349			var r = rad2deg(Math.atan2(b, a));
1350			k = rad2deg(Math.atan(k));
1351			
1352			return {
1353				rotate: r + 'deg',
1354				skewX: k + 'deg',
1355				scaleX: sx,
1356				scaleY: sy,
1357				translateX: tx + 'px',
1358				translateY: ty + 'px'
1359			};
1360		}
1361	};
1362	
1363	/** Extend all of the matrix types with the same prototype */
1364	$.extend($m.M2x2.prototype, Matrix, {
1365		toM3x3: function() {
1366			var a = this.elements;
1367			return new $m.M3x3(
1368				a[0], a[1], 0,
1369				a[2], a[3], 0,
1370				0,    0,    1
1371			);	
1372		},
1373		
1374		/**
1375		 * Multiply a 2x2 matrix by a similar matrix or a vector
1376		 * @param M2x2 | V2 matrix
1377		 * @return M2x2 | V2
1378		 */
1379		x: function(matrix) {
1380			var isVector = typeof(matrix.rows) === 'undefined';
1381			
1382			// Ensure the right-sized matrix
1383			if (!isVector && matrix.rows == 3) {
1384				return this.toM3x3().x(matrix);
1385			}
1386			
1387			var a = this.elements,
1388				b = matrix.elements;
1389			
1390			if (isVector && b.length == 2) {
1391				// b is actually a vector
1392				return new $m.V2(
1393					a[0] * b[0] + a[1] * b[1],
1394					a[2] * b[0] + a[3] * b[1]
1395				);
1396			} else if (b.length == a.length) {
1397				// b is a 2x2 matrix
1398				return new $m.M2x2(
1399					a[0] * b[0] + a[1] * b[2],
1400					a[0] * b[1] + a[1] * b[3],
1401					
1402					a[2] * b[0] + a[3] * b[2],
1403					a[2] * b[1] + a[3] * b[3]
1404				);
1405			}
1406			return false; // fail
1407		},
1408		
1409		/**
1410		 * Generates an inverse of the current matrix
1411		 * @param void
1412		 * @return M2x2
1413		 * @link http://www.dr-lex.be/random/matrix_inv.html
1414		 */
1415		inverse: function() {
1416			var d = 1/this.determinant(),
1417				a = this.elements;
1418			return new $m.M2x2(
1419				d *  a[3], d * -a[1],
1420				d * -a[2], d *  a[0]
1421			);
1422		},
1423		
1424		/**
1425		 * Calculates the determinant of the current matrix
1426		 * @param void
1427		 * @return Number
1428		 * @link http://www.dr-lex.be/random/matrix_inv.html
1429		 */
1430		determinant: function() {
1431			var a = this.elements;
1432			return a[0] * a[3] - a[1] * a[2];
1433		}
1434	});
1435	
1436	$.extend($m.M3x3.prototype, Matrix, {
1437		/**
1438		 * Multiply a 3x3 matrix by a similar matrix or a vector
1439		 * @param M3x3 | V3 matrix
1440		 * @return M3x3 | V3
1441		 */
1442		x: function(matrix) {
1443			var isVector = typeof(matrix.rows) === 'undefined';
1444			
1445			// Ensure the right-sized matrix
1446			if (!isVector && matrix.rows < 3) {
1447				matrix = matrix.toM3x3();
1448			}
1449			
1450			var a = this.elements,
1451				b = matrix.elements;
1452			
1453			if (isVector && b.length == 3) {
1454				// b is actually a vector
1455				return new $m.V3(
1456					a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
1457					a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
1458					a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
1459				);
1460			} else if (b.length == a.length) {
1461				// b is a 3x3 matrix
1462				return new $m.M3x3(
1463					a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
1464					a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
1465					a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
1466
1467					a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
1468					a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
1469					a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
1470
1471					a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
1472					a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
1473					a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
1474				);
1475			}
1476			return false; // fail
1477		},
1478		
1479		/**
1480		 * Generates an inverse of the current matrix
1481		 * @param void
1482		 * @return M3x3
1483		 * @link http://www.dr-lex.be/random/matrix_inv.html
1484		 */
1485		inverse: function() {
1486			var d = 1/this.determinant(),
1487				a = this.elements;
1488			return new $m.M3x3(
1489				d * (  a[8] * a[4] - a[7] * a[5]),
1490				d * (-(a[8] * a[1] - a[7] * a[2])),
1491				d * (  a[5] * a[1] - a[4] * a[2]),
1492				
1493				d * (-(a[8] * a[3] - a[6] * a[5])),
1494				d * (  a[8] * a[0] - a[6] * a[2]),
1495				d * (-(a[5] * a[0] - a[3] * a[2])),
1496				
1497				d * (  a[7] * a[3] - a[6] * a[4]),
1498				d * (-(a[7] * a[0] - a[6] * a[1])),
1499				d * (  a[4] * a[0] - a[3] * a[1])
1500			);
1501		},
1502		
1503		/**
1504		 * Calculates the determinant of the current matrix
1505		 * @param void
1506		 * @return Number
1507		 * @link http://www.dr-lex.be/random/matrix_inv.html
1508		 */
1509		determinant: function() {
1510			var a = this.elements;
1511			return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
1512		}
1513	});
1514	
1515	/** generic vector prototype */
1516	var Vector = {		
1517		/**
1518		 * Return a specific element from the vector
1519		 * @param Number i where 1 is the 0th value
1520		 * @return Number
1521		 */
1522		e: function(i) {
1523			return this.elements[i - 1];
1524		}
1525	};
1526	
1527	/** Extend all of the vector types with the same prototype */
1528	$.extend($m.V2.prototype, Vector);
1529	$.extend($m.V3.prototype, Vector);
1530})(jQuery, this, this.document);
1531///////////////////////////////////////////////////////
1532// Matrix Calculations
1533///////////////////////////////////////////////////////
1534(function($, window, document, undefined) {
1535	/**
1536	 * Matrix object for creating matrices relevant for 2d Transformations
1537	 * @var Object
1538	 */
1539	if (typeof($.matrix) == 'undefined') {
1540		$.extend({
1541			matrix: {}
1542		});
1543	}
1544	
1545	$.extend( $.matrix, {
1546		/**
1547		 * Class for calculating coordinates on a matrix
1548		 * @param Matrix matrix
1549		 * @param Number outerHeight
1550		 * @param Number outerWidth
1551		 * @constructor
1552		 */
1553		calc: function(matrix, outerHeight, outerWidth) {
1554			/**
1555			 * @var Matrix
1556			 */
1557			this.matrix = matrix;
1558			
1559			/**
1560			 * @var Number
1561			 */
1562			this.outerHeight = outerHeight;
1563			
1564			/**
1565			 * @var Number
1566			 */
1567			this.outerWidth = outerWidth;
1568		}
1569	});
1570	
1571	$.matrix.calc.prototype = {
1572		/**
1573		 * Calculate a coord on the new object
1574		 * @return Object
1575		 */
1576		coord: function(x, y, z) {
1577			//default z and w
1578			z = typeof(z) !== 'undefined' ? z : 0;
1579			
1580			var matrix = this.matrix,
1581				vector;
1582				
1583			switch (matrix.rows) {
1584				case 2:
1585					vector = matrix.x(new $.matrix.V2(x, y));
1586					break;
1587				case 3:
1588					vector = matrix.x(new $.matrix.V3(x, y, z));
1589					break;
1590			}
1591			
1592			return vector;
1593		},
1594		
1595		/**
1596		 * Calculate the corners of the new object
1597		 * @return Object
1598		 */
1599		corners: function(x, y) {
1600			// Try to save the corners if this is called a lot
1601			var save = !(typeof(x) !=='undefined' || typeof(y) !=='undefined'),
1602				c;
1603			if (!this.c || !save) {
1604				y = y || this.outerHeight;
1605				x = x || this.outerWidth;
1606				
1607				c = {
1608					tl: this.coord(0, 0),
1609					bl: this.coord(0, y),
1610					tr: this.coord(x, 0),
1611					br: this.coord(x, y)
1612				};
1613			} else {
1614				c = this.c;
1615			}
1616			
1617			if (save) {
1618				this.c = c;
1619			}
1620			return c;
1621		},
1622		
1623		/**
1624		 * Calculate the sides of the new object
1625		 * @return Object
1626		 */
1627		sides: function(corners) {
1628			// The corners of the box
1629			var c = corners || this.corners();
1630			
1631			return {
1632				top: Math.min(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
1633				bottom: Math.max(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
1634				left: Math.min(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1)),
1635				right: Math.max(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1))
1636			};
1637		},
1638		
1639		/**
1640		 * Calculate the offset of the new object
1641		 * @return Object
1642		 */
1643		offset: function(corners) {
1644			// The corners of the box
1645			var s = this.sides(corners);
1646			
1647			// return size
1648			return {
1649				height: Math.abs(s.bottom - s.top), 
1650				width: Math.abs(s.right - s.left)
1651			};
1652		},
1653		
1654		/**
1655		 * Calculate the area of the new object
1656		 * @return Number
1657		 * @link http://en.wikipedia.org/wiki/Quadrilateral#Area_of_a_convex_quadrilateral
1658		 */
1659		area: function(corners) {
1660			// The corners of the box
1661			var c = corners || this.corners();
1662			
1663			// calculate the two diagonal vectors
1664			var v1 = {
1665					x: c.tr.e(1) - c.tl.e(1) + c.br.e(1) - c.bl.e(1),
1666					y: c.tr.e(2) - c.tl.e(2) + c.br.e(2) - c.bl.e(2)
1667				},
1668				v2 = {
1669					x: c.bl.e(1) - c.tl.e(1) + c.br.e(1) - c.tr.e(1),
1670					y: c.bl.e(2) - c.tl.e(2) + c.br.e(2) - c.tr.e(2)
1671				};
1672				
1673			return 0.25 * Math.abs(v1.e(1) * v2.e(2) - v1.e(2) * v2.e(1));
1674		},
1675		
1676		/**
1677		 * Calculate the non-affinity of the new object
1678		 * @return Number
1679		 */
1680		nonAffinity: function() {
1681			// The corners of the box
1682			var sides = this.sides(),
1683				xDiff = sides.top - sides.bottom,
1684				yDiff = sides.left - sides.right;
1685			
1686			return parseFloat(parseFloat(Math.abs(
1687				(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) /
1688				(sides.top * sides.bottom + sides.left * sides.right)
1689			)).toFixed(8));
1690		},
1691		
1692		/**
1693		 * Calculate a proper top and left for IE
1694		 * @param Object toOrigin
1695		 * @param Object fromOrigin
1696		 * @return Object
1697		 */
1698		originOffset: function(toOrigin, fromOrigin) {
1699			// the origin to translate to
1700			toOrigin = toOrigin ? toOrigin : new $.matrix.V2(
1701				this.outerWidth * 0.5,
1702				this.outerHeight * 0.5
1703			);
1704			
1705			// the origin to translate from (IE has a fixed origin of 0, 0)
1706			fromOrigin = fromOrigin ? fromOrigin : new $.matrix.V2(
1707				0,
1708				0
1709			);
1710			
1711			// transform the origins
1712			var toCenter = this.coord(toOrigin.e(1), toOrigin.e(2));
1713			var fromCenter = this.coord(fromOrigin.e(1), fromOrigin.e(2));
1714			
1715			// return the offset
1716			return {
1717				top: (fromCenter.e(2) - fromOrigin.e(2)) - (toCenter.e(2) - toOrigin.e(2)),
1718				left: (fromCenter.e(1) - fromOrigin.e(1)) - (toCenter.e(1) - toOrigin.e(1))
1719			};
1720		}
1721	};
1722})(jQuery, this, this.document);
1723///////////////////////////////////////////////////////
1724// 2d Matrix Functions
1725///////////////////////////////////////////////////////
1726(function($, window, document, undefined) {
1727	/**
1728	 * Matrix object for creating matrices relevant for 2d Transformations
1729	 * @var Object
1730	 */
1731	if (typeof($.matrix) == 'undefined') {
1732		$.extend({
1733			matrix: {}
1734		});
1735	}
1736	var $m = $.matrix,
1737		$m2x2 = $m.M2x2,
1738		$m3x3 = $m.M3x3;
1739	
1740	$.extend( $m, {
1741		/**
1742		 * Identity matrix
1743		 * @param Number size
1744		 * @return Matrix
1745		 */
1746		identity: function(size) {
1747			size = size || 2;
1748			var length = size * size,
1749				elements = new Array(length),
1750				mod = size + 1;
1751			for (var i = 0; i < length; i++) {
1752				elements[i] = (i % mod) === 0 ? 1 : 0;
1753			}
1754			return new $m['M'+size+'x'+size](elements);
1755		},
1756		
1757		/**
1758		 * Matrix
1759		 * @return Matrix
1760		 */
1761		matrix: function() {
1762			var args = Array.prototype.slice.call(arguments);
1763			// arguments are in column-major order
1764			switch (arguments.length) {
1765				case 4:
1766					return new $m2x2(
1767						args[0], args[2],
1768						args[1], args[3]
1769					);
1770				case 6:
1771					return new $m3x3(
1772						args[0], args[2], args[4],
1773						args[1], args[3], args[5],
1774						0,       0,       1
1775					);
1776			}
1777		},
1778		
1779		/**
1780		 * Reflect (same as rotate(180))
1781		 * @return Matrix
1782		 */
1783		reflect: function() {
1784			return new $m2x2(
1785				-1,  0,
1786				 0, -1
1787			);
1788		},
1789		
1790		/**
1791		 * Reflect across the x-axis (mirrored upside down)
1792		 * @return Matrix
1793		 */
1794		reflectX: function() {	
1795			return new $m2x2(
1796				1,  0,
1797				0, -1
1798			);
1799		},
1800		
1801		/**
1802		 * Reflect by swapping x an y (same as reflectX + rotate(-90))
1803		 * @return Matrix
1804		 */
1805		reflectXY: function() {
1806			return new $m2x2(
1807				0, 1,
1808				1, 0
1809			);
1810		},
1811		
1812		/**
1813		 * Reflect across the y-axis (mirrored)
1814		 * @return Matrix
1815		 */
1816		reflectY: function() {
1817			return new $m2x2(
1818				-1, 0,
1819				 0, 1
1820			);
1821		},
1822		
1823		/**
1824		 * Rotates around the origin
1825		 * @param Number deg
1826		 * @return Matrix
1827		 * @link http://www.w3.org/TR/SVG/coords.html#RotationDefined
1828		 */
1829		rotate: function(deg) {
1830			//TODO: detect units
1831			var rad = $.angle.degreeToRadian(deg),
1832				costheta = Math.cos(rad),
1833				sintheta = Math.sin(rad);
1834			
1835			var a = costheta,
1836				b = sintheta,
1837				c = -sintheta,
1838				d = costheta;
1839				
1840			return new $m2x2(
1841				a, c,
1842				b, d
1843			);
1844		},
1845		
1846		/**
1847		 * Scale
1848		 * @param Number sx
1849		 * @param Number sy
1850		 * @return Matrix
1851		 * @link http://www.w3.org/TR/SVG/coords.html#ScalingDefined
1852		 */
1853		scale: function (sx, sy) {
1854			sx = sx || sx === 0 ? sx : 1;
1855			sy = sy || sy === 0 ? sy : sx;
1856			
1857			return new $m2x2(
1858				sx, 0,
1859				0, sy
1860			);
1861		},
1862		
1863		/**
1864		 * Scale on the X-axis
1865		 * @param Number sx
1866		 * @return Matrix
1867		 */
1868		scaleX: function (sx) {
1869			return $m.scale(sx, 1);
1870		},
1871		
1872		/**
1873		 * Scale on the Y-axis
1874		 * @param Number sy
1875		 * @return Matrix
1876		 */
1877		scaleY: function (sy) {
1878			return $m.scale(1, sy);
1879		},
1880		
1881		/**
1882		 * Skews on the X-axis and Y-axis
1883		 * @param Number degX
1884		 * @param Number degY
1885		 * @return Matrix
1886		 */
1887		skew: function (degX, degY) {
1888			degX = degX || 0;
1889			degY = degY || 0;
1890			
1891			//TODO: detect units
1892			var radX = $.angle.degreeToRadian(degX),
1893				radY = $.angle.degreeToRadian(degY),
1894				x = Math.tan(radX),
1895				y = Math.tan(radY);
1896			
1897			return new $m2x2(
1898				1, x,
1899				y, 1
1900			);
1901		},
1902		
1903		/**
1904		 * Skews on the X-axis
1905		 * @param Number degX
1906		 * @return Matrix
1907		 * @link http://www.w3.org/TR/SVG/coords.html#SkewXDefined
1908		 */
1909		skewX: function (degX) {
1910			return $m.skew(degX);
1911		},
1912		
1913		/**
1914		 * Skews on the Y-axis
1915		 * @param Number degY
1916		 * @return Matrix
1917		 * @link http://www.w3.org/TR/SVG/coords.html#SkewYDefined
1918		 */
1919		skewY: function (degY) {
1920			return $m.skew(0, degY);
1921		},
1922		
1923		/**
1924		 * Translate
1925		 * @param Number tx
1926		 * @param Number ty
1927		 * @return Matrix
1928		 * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1929		 */
1930		translate: function (tx, ty) {
1931			tx = tx || 0;
1932			ty = ty || 0;
1933			
1934			return new $m3x3(
1935				1, 0, tx,
1936				0, 1, ty,
1937				0, 0, 1
1938			);
1939		},
1940		
1941		/**
1942		 * Translate on the X-axis
1943		 * @param Number tx
1944		 * @return Matrix
1945		 * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1946		 */
1947		translateX: function (tx) {
1948			return $m.translate(tx);
1949		},
1950		
1951		/**
1952		 * Translate on the Y-axis
1953		 * @param Number ty
1954		 * @return Matrix
1955		 * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
1956		 */
1957		translateY: function (ty) {
1958			return $m.translate(0, ty);
1959		}
1960	});
1961})(jQuery, this, this.document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.