]> _ Git - fluidbook-html5.git/commitdiff
(no commit message)
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 17 Jun 2013 11:22:15 +0000 (11:22 +0000)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 17 Jun 2013 11:22:15 +0000 (11:22 +0000)
101 files changed:
.htaccess [new file with mode: 0644]
PROD [new file with mode: 0644]
_index.html [new file with mode: 0644]
images/arrow-button.png [new file with mode: 0644]
images/chapters-arrow.png [new file with mode: 0644]
images/cur-zoom-in.png [new file with mode: 0644]
images/cur-zoom-out.png [new file with mode: 0644]
images/shadeleft-reflet.png [new file with mode: 0644]
images/shadeleft.png [new file with mode: 0644]
images/shaderight-reflet.png [new file with mode: 0644]
images/shaderight.png [new file with mode: 0644]
js/libs/Three.js [new file with mode: 0644]
js/libs/cube/fb.js [new file with mode: 0644]
js/libs/cube/util.js [new file with mode: 0644]
js/libs/fix/detect-zoom.js [new file with mode: 0644]
js/libs/fix/ios-orientation.js [new file with mode: 0644]
js/libs/flashdetect.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.background.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.bookmarks.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.cache.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.coquillette.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.desktop.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.help.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.l10n.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.loader.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.nav.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.pad.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.resize.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.search.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.service.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.stats.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.support.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.touch.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.utils.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.video.js [new file with mode: 0644]
js/libs/fluidbook/fluidbook.viewport.js [new file with mode: 0644]
js/libs/fluidbook/views/fluidbook.chapters.js [new file with mode: 0644]
js/libs/fluidbook/views/fluidbook.index.js [new file with mode: 0644]
js/libs/gsap/TimelineLite.js [new file with mode: 0644]
js/libs/gsap/TimelineMax.js [new file with mode: 0644]
js/libs/gsap/TweenLite.js [new file with mode: 0644]
js/libs/gsap/TweenMax.js [new file with mode: 0644]
js/libs/gsap/easing/EasePack.js [new file with mode: 0644]
js/libs/gsap/jquery.gsap.js [new file with mode: 0644]
js/libs/gsap/plugins/AttrPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/BezierPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/CSSPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/CSSRulePlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/ColorPropsPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/DirectionalRotationPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/EaselPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/KineticPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/RaphaelPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/RoundPropsPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/ScrollToPlugin.js [new file with mode: 0644]
js/libs/gsap/plugins/TEMPLATE_Plugin.js [new file with mode: 0644]
js/libs/gsap/plugins/TextPlugin.js [new file with mode: 0644]
js/libs/jquery/jquery.hashchange.js [new file with mode: 0644]
js/libs/jquery/jquery.js [new file with mode: 0644]
js/libs/jquery/jquery.localscroll.js [new file with mode: 0644]
js/libs/jquery/jquery.migrate.js [new file with mode: 0644]
js/libs/jquery/jquery.mousewheel.js [new file with mode: 0644]
js/libs/jquery/jquery.scrollto.js [new file with mode: 0644]
js/libs/jquery/jquery.transform.js [new file with mode: 0644]
js/libs/jquery/jquery.transit.js [new file with mode: 0644]
js/libs/json2.js [new file with mode: 0644]
js/libs/modernizr/modernizr.js [new file with mode: 0644]
js/libs/modernizr/tests.js [new file with mode: 0644]
js/libs/phonegap/2.8.1/cordova-android.js [new file with mode: 0644]
js/libs/phonegap/2.8.1/cordova-ios.js [new file with mode: 0644]
js/libs/phonegap/plugins/android/webintent.js [new file with mode: 0644]
js/libs/phonegap/plugins/ios/ExternalFileUtil.js [new file with mode: 0644]
js/main.js [new file with mode: 0644]
js/tester.js [new file with mode: 0644]
js/widget.js [new file with mode: 0644]
plugins/com/promotal/catalogue/plugin.css [new file with mode: 0644]
plugins/com/promotal/catalogue/plugin.js [new file with mode: 0644]
style/fluidbook.css [new file with mode: 0644]
style/fonts/Ubuntu-B-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-B-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-BI-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-BI-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-L-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-L-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-LI-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-LI-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-M-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-M-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-MI-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-MI-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-R-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-R-webfont.woff [new file with mode: 0644]
style/fonts/Ubuntu-RI-webfont.ttf [new file with mode: 0644]
style/fonts/Ubuntu-RI-webfont.woff [new file with mode: 0644]
style/fonts/slkscr-webfont.ttf [new file with mode: 0644]
style/fonts/slkscr-webfont.woff [new file with mode: 0644]
style/widget.css [new file with mode: 0644]
swf/_src/Fluidbook Video Player.as3proj [new file with mode: 0644]
web.config [new file with mode: 0644]
widget.html [new file with mode: 0644]

diff --git a/.htaccess b/.htaccess
new file mode 100644 (file)
index 0000000..f99e52e
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,21 @@
+<IfModule mod_mime.c>\r
+       AddType video/ogg .ogm\r
+       AddType video/ogg .ogv\r
+       AddType video/ogg .ogg\r
+       AddType video/mp4 .mp4\r
+       AddType video/webm .webm\r
+       AddType image/svg+xml .svg\r
+       AddType image/svg+xml .svgz\r
+       AddType application/json .json\r
+       AddType application/vnd.ms-fontobject .eot\r
+       AddType application/octet-stream .otf\r
+       AddType application/octet-stream .ttf\r
+       AddType application/x-font-woff .woff\r
+       AddType text/cache-manifest .appcache\r
+\r
+       AddEncoding gzip svgz\r
+</IfModule>\r
+\r
+<IfModule mod_expires.c>\r
+       ExpiresByType text/cache-manifest "access plus 0 seconds"\r
+</IfModule>
\ No newline at end of file
diff --git a/PROD b/PROD
new file mode 100644 (file)
index 0000000..e5517e4
--- /dev/null
+++ b/PROD
@@ -0,0 +1 @@
+HEAD
\ No newline at end of file
diff --git a/_index.html b/_index.html
new file mode 100644 (file)
index 0000000..60bb478
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>\r
+<html>\r
+       <head>\r
+               <title><!-- $titre --></title>\r
+               <meta charset="utf-8">\r
+               <meta name="HandheldFriendly"  content="True">\r
+               <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=IE8">\r
+               <meta name="apple-mobile-web-app-capable" content="yes">\r
+               <meta name="viewport" content="initial-scale=1,minimum-scale=1">\r
+               <!-- $description -->\r
+               <!-- $style -->\r
+               <!-- $script -->\r
+               <!-- $ga -->\r
+       </head>\r
+       <body>\r
+               <div id="message"></div>\r
+\r
+               <div id="main">\r
+                       <header>\r
+                               <nav id="nav"></nav>\r
+                               <div id="search"></div>\r
+                               <a id="logo" href="#"></a>\r
+                       </header>\r
+                       <div id="interface"></div>\r
+                       <div id="helpView"></div>\r
+                       <div id="fluidbook">\r
+                               <div id="shadow"></div>\r
+                               <div id="pagesnumbers"><div class="left"></div><div class="right"></div></div>\r
+                               <div id="pages" class="double">\r
+                                       <div id="currentDoublePage" class="doublePage"></div>\r
+                                       <div id="links"></div>\r
+                               </div>\r
+                       </div>\r
+                       <a id="down" href="#"></a>\r
+                       <footer><!-- $credits --></footer>\r
+               </div>\r
+               <div id="view"></div>\r
+\r
+               <div id="pagesContents"><!-- $pagesContents --></div>\r
+               <div id="op"></div>\r
+               <div id="ol"></div>\r
+               <div id="fontsLoader">\r
+                       <div class="silkscreen"></div>\r
+                       <div class="puritan"></div>\r
+                       <div class="puritanbold"></div>\r
+               </div>\r
+\r
+               <div id="coquillette"></div>\r
+               <div id="hiddencontents"><!-- $hiddenContents --></div>\r
+               <div id="splash"><!-- $splash --></div>\r
+       </body>\r
+</html>
\ No newline at end of file
diff --git a/images/arrow-button.png b/images/arrow-button.png
new file mode 100644 (file)
index 0000000..e4ff2f8
Binary files /dev/null and b/images/arrow-button.png differ
diff --git a/images/chapters-arrow.png b/images/chapters-arrow.png
new file mode 100644 (file)
index 0000000..7dad456
Binary files /dev/null and b/images/chapters-arrow.png differ
diff --git a/images/cur-zoom-in.png b/images/cur-zoom-in.png
new file mode 100644 (file)
index 0000000..bebcece
Binary files /dev/null and b/images/cur-zoom-in.png differ
diff --git a/images/cur-zoom-out.png b/images/cur-zoom-out.png
new file mode 100644 (file)
index 0000000..c8c1485
Binary files /dev/null and b/images/cur-zoom-out.png differ
diff --git a/images/shadeleft-reflet.png b/images/shadeleft-reflet.png
new file mode 100644 (file)
index 0000000..b41f888
Binary files /dev/null and b/images/shadeleft-reflet.png differ
diff --git a/images/shadeleft.png b/images/shadeleft.png
new file mode 100644 (file)
index 0000000..98fcac0
Binary files /dev/null and b/images/shadeleft.png differ
diff --git a/images/shaderight-reflet.png b/images/shaderight-reflet.png
new file mode 100644 (file)
index 0000000..7b5dd6e
Binary files /dev/null and b/images/shaderight-reflet.png differ
diff --git a/images/shaderight.png b/images/shaderight.png
new file mode 100644 (file)
index 0000000..49a0e67
Binary files /dev/null and b/images/shaderight.png differ
diff --git a/js/libs/Three.js b/js/libs/Three.js
new file mode 100644 (file)
index 0000000..b36e7d8
--- /dev/null
@@ -0,0 +1,794 @@
+// Three.js - http://github.com/mrdoob/three.js
+'use strict';var THREE=THREE||{REVISION:"48"};if(!self.Int32Array)self.Int32Array=Array,self.Float32Array=Array;
+(function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;c<b.length&&!window.requestAnimationFrame;++c)window.requestAnimationFrame=window[b[c]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[b[c]+"CancelAnimationFrame"]||window[b[c]+"CancelRequestAnimationFrame"];if(!window.requestAnimationFrame)window.requestAnimationFrame=function(b){var c=(new Date).getTime(),g=Math.max(0,16-(c-a)),e=window.setTimeout(function(){b(c+g)},g);a=c+g;return e};if(!window.cancelAnimationFrame)window.cancelAnimationFrame=
+function(a){clearTimeout(a)}})();THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1};THREE.Clock.prototype.start=function(){this.oldTime=this.startTime=Date.now();this.running=!0};THREE.Clock.prototype.stop=function(){this.getElapsedTime();this.running=!1};THREE.Clock.prototype.getElapsedTime=function(){return this.elapsedTime+=this.getDelta()};
+THREE.Clock.prototype.getDelta=function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=Date.now(),a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a};THREE.Color=function(a){void 0!==a&&this.setHex(a);return this};
+THREE.Color.prototype={constructor:THREE.Color,r:1,g:1,b:1,copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);
+this.b=Math.sqrt(this.b);return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSV:function(a,b,c){var d,f,g;if(0===c)this.r=this.g=this.b=0;else switch(d=Math.floor(6*a),f=6*a-d,a=c*(1-b),g=c*(1-b*f),b=c*(1-b*(1-f)),d){case 1:this.r=g;this.g=c;this.b=a;break;case 2:this.r=a;this.g=c;this.b=b;break;case 3:this.r=a;this.g=g;this.b=c;break;case 4:this.r=b;this.g=a;this.b=c;break;case 5:this.r=c;this.g=a;this.b=g;break;case 6:case 0:this.r=c,this.g=b,this.b=a}return this},setHex:function(a){a=
+Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},getHex:function(){return Math.floor(255*this.r)<<16^Math.floor(255*this.g)<<8^Math.floor(255*this.b)},getContextStyle:function(){return"rgb("+Math.floor(255*this.r)+","+Math.floor(255*this.g)+","+Math.floor(255*this.b)+")"},clone:function(){return(new THREE.Color).setRGB(this.r,this.g,this.b)}};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0};
+THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},
+divideScalar:function(a){a?(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)},
+lerpSelf:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},isZero:function(){return 1.0E-4>this.lengthSq()}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0};
+THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},
+addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},
+divideScalar:function(a){a?(this.x/=a,this.y/=a,this.z/=a):this.z=this.y=this.x=0;return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},
+lerpSelf:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){var b=this.x,c=this.y,d=this.z;this.x=c*a.z-d*a.y;this.y=d*a.x-b*a.z;this.z=b*a.y-c*a.x;return this},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){return(new THREE.Vector3).sub(this,a).lengthSq()},getPositionFromMatrix:function(a){this.x=
+a.n14;this.y=a.n24;this.z=a.n34;return this},getRotationFromMatrix:function(a,b){var c=b?b.x:1,d=b?b.y:1,f=b?b.z:1,g=a.n11/c,e=a.n12/d,c=a.n21/c,d=a.n22/d,h=a.n23/f,i=a.n33/f;this.y=Math.asin(a.n13/f);f=Math.cos(this.y);1.0E-5<Math.abs(f)?(this.x=Math.atan2(-h/f,i/f),this.z=Math.atan2(-e/f,g/f)):(this.x=0,this.z=Math.atan2(c,d));return this},getScaleFromMatrix:function(a){var b=this.set(a.n11,a.n21,a.n31).length(),c=this.set(a.n12,a.n22,a.n32).length(),a=this.set(a.n13,a.n23,a.n33).length();this.x=
+b;this.y=c;this.z=a},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},isZero:function(){return 1.0E-4>this.lengthSq()}};THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1};
+THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;
+this.z=a.z-b.z;this.w=a.w-b.w;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},divideScalar:function(a){a?(this.x/=a,this.y/=a,this.z/=a,this.w/=a):(this.z=this.y=this.x=0,this.w=1);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.dot(this)},length:function(){return Math.sqrt(this.lengthSq())},
+normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},lerpSelf:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this}};THREE.Frustum=function(){this.planes=[new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4,new THREE.Vector4]};
+THREE.Frustum.prototype.setFromMatrix=function(a){var b,c=this.planes;c[0].set(a.n41-a.n11,a.n42-a.n12,a.n43-a.n13,a.n44-a.n14);c[1].set(a.n41+a.n11,a.n42+a.n12,a.n43+a.n13,a.n44+a.n14);c[2].set(a.n41+a.n21,a.n42+a.n22,a.n43+a.n23,a.n44+a.n24);c[3].set(a.n41-a.n21,a.n42-a.n22,a.n43-a.n23,a.n44-a.n24);c[4].set(a.n41-a.n31,a.n42-a.n32,a.n43-a.n33,a.n44-a.n34);c[5].set(a.n41+a.n31,a.n42+a.n32,a.n43+a.n33,a.n44+a.n34);for(a=0;6>a;a++)b=c[a],b.divideScalar(Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z))};
+THREE.Frustum.prototype.contains=function(a){for(var b=this.planes,c=a.matrixWorld,d=THREE.Frustum.__v1.set(c.getColumnX().length(),c.getColumnY().length(),c.getColumnZ().length()),d=-a.geometry.boundingSphere.radius*Math.max(d.x,Math.max(d.y,d.z)),f=0;6>f;f++)if(a=b[f].x*c.n14+b[f].y*c.n24+b[f].z*c.n34+b[f].w,a<=d)return!1;return!0};THREE.Frustum.__v1=new THREE.Vector3;
+THREE.Ray=function(a,b){function c(a,b,c){p.sub(c,a);s=p.dot(b);t=n.add(a,r.copy(b).multiplyScalar(s));return w=c.distanceTo(t)}function d(a,b,c,d){p.sub(d,b);n.sub(c,b);r.sub(a,b);u=p.dot(p);v=p.dot(n);A=p.dot(r);F=n.dot(n);B=n.dot(r);D=1/(u*F-v*v);H=(F*A-v*B)*D;I=(u*B-v*A)*D;return 0<=H&&0<=I&&1>H+I}this.origin=a||new THREE.Vector3;this.direction=b||new THREE.Vector3;this.intersectObjects=function(a){var b,c,d=[];for(b=0,c=a.length;b<c;b++)Array.prototype.push.apply(d,this.intersectObject(a[b]));
+d.sort(function(a,b){return a.distance-b.distance});return d};var f=1.0E-4;this.setPrecision=function(a){f=a};var g=new THREE.Vector3,e=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,j=new THREE.Vector3,k=new THREE.Vector3,q=new THREE.Vector3,m=new THREE.Vector3,o=new THREE.Vector3;this.intersectObject=function(a){var b,n=[];if(a instanceof THREE.Particle){var p=c(this.origin,this.direction,a.matrixWorld.getPosition());if(p>a.scale.x)return[];b={distance:p,point:a.position,face:null,object:a};
+n.push(b)}else if(a instanceof THREE.Mesh){var p=c(this.origin,this.direction,a.matrixWorld.getPosition()),r=THREE.Frustum.__v1.set(a.matrixWorld.getColumnX().length(),a.matrixWorld.getColumnY().length(),a.matrixWorld.getColumnZ().length());if(p>a.geometry.boundingSphere.radius*Math.max(r.x,Math.max(r.y,r.z)))return n;var s,l,t=a.geometry,u=t.vertices,E;a.matrixRotationWorld.extractRotation(a.matrixWorld);for(p=0,r=t.faces.length;p<r;p++)if(b=t.faces[p],j.copy(this.origin),k.copy(this.direction),
+E=a.matrixWorld,q=E.multiplyVector3(q.copy(b.centroid)).subSelf(j),m=a.matrixRotationWorld.multiplyVector3(m.copy(b.normal)),s=k.dot(m),!(Math.abs(s)<f)&&(l=m.dot(q)/s,!(0>l)&&(a.doubleSided||(a.flipSided?0<s:0>s))))if(o.add(j,k.multiplyScalar(l)),b instanceof THREE.Face3)g=E.multiplyVector3(g.copy(u[b.a].position)),e=E.multiplyVector3(e.copy(u[b.b].position)),h=E.multiplyVector3(h.copy(u[b.c].position)),d(o,g,e,h)&&(b={distance:j.distanceTo(o),point:o.clone(),face:b,object:a},n.push(b));else if(b instanceof
+THREE.Face4&&(g=E.multiplyVector3(g.copy(u[b.a].position)),e=E.multiplyVector3(e.copy(u[b.b].position)),h=E.multiplyVector3(h.copy(u[b.c].position)),i=E.multiplyVector3(i.copy(u[b.d].position)),d(o,g,e,i)||d(o,e,h,i)))b={distance:j.distanceTo(o),point:o.clone(),face:b,object:a},n.push(b)}return n};var p=new THREE.Vector3,n=new THREE.Vector3,r=new THREE.Vector3,s,t,w,u,v,A,F,B,D,H,I};
+THREE.Rectangle=function(){function a(){g=d-b;e=f-c}var b,c,d,f,g,e,h=!0;this.getX=function(){return b};this.getY=function(){return c};this.getWidth=function(){return g};this.getHeight=function(){return e};this.getLeft=function(){return b};this.getTop=function(){return c};this.getRight=function(){return d};this.getBottom=function(){return f};this.set=function(g,e,k,q){h=!1;b=g;c=e;d=k;f=q;a()};this.addPoint=function(g,e){h?(h=!1,b=g,c=e,d=g,f=e):(b=b<g?b:g,c=c<e?c:e,d=d>g?d:g,f=f>e?f:e);a()};this.add3Points=
+function(g,e,k,q,m,o){h?(h=!1,b=g<k?g<m?g:m:k<m?k:m,c=e<q?e<o?e:o:q<o?q:o,d=g>k?g>m?g:m:k>m?k:m,f=e>q?e>o?e:o:q>o?q:o):(b=g<k?g<m?g<b?g:b:m<b?m:b:k<m?k<b?k:b:m<b?m:b,c=e<q?e<o?e<c?e:c:o<c?o:c:q<o?q<c?q:c:o<c?o:c,d=g>k?g>m?g>d?g:d:m>d?m:d:k>m?k>d?k:d:m>d?m:d,f=e>q?e>o?e>f?e:f:o>f?o:f:q>o?q>f?q:f:o>f?o:f);a()};this.addRectangle=function(g){h?(h=!1,b=g.getLeft(),c=g.getTop(),d=g.getRight(),f=g.getBottom()):(b=b<g.getLeft()?b:g.getLeft(),c=c<g.getTop()?c:g.getTop(),d=d>g.getRight()?d:g.getRight(),f=f>
+g.getBottom()?f:g.getBottom());a()};this.inflate=function(g){b-=g;c-=g;d+=g;f+=g;a()};this.minSelf=function(g){b=b>g.getLeft()?b:g.getLeft();c=c>g.getTop()?c:g.getTop();d=d<g.getRight()?d:g.getRight();f=f<g.getBottom()?f:g.getBottom();a()};this.intersects=function(a){return d<a.getLeft()||b>a.getRight()||f<a.getTop()||c>a.getBottom()?!1:!0};this.empty=function(){h=!0;f=d=c=b=0;a()};this.isEmpty=function(){return h}};
+THREE.Math={clamp:function(a,b,c){return a<b?b:a>c?c:a},clampBottom:function(a,b){return a<b?b:a},mapLinear:function(a,b,c,d,f){return d+(a-b)*(f-d)/(c-b)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(0.5-Math.random())},sign:function(a){return 0>a?-1:0<a?1:0}};THREE.Matrix3=function(){this.m=[]};
+THREE.Matrix3.prototype={constructor:THREE.Matrix3,transposeIntoArray:function(a){var b=this.m;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this}};THREE.Matrix4=function(a,b,c,d,f,g,e,h,i,j,k,q,m,o,p,n){this.set(void 0!==a?a:1,b||0,c||0,d||0,f||0,void 0!==g?g:1,e||0,h||0,i||0,j||0,void 0!==k?k:1,q||0,m||0,o||0,p||0,void 0!==n?n:1);this.m33=new THREE.Matrix3};
+THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,f,g,e,h,i,j,k,q,m,o,p,n){this.n11=a;this.n12=b;this.n13=c;this.n14=d;this.n21=f;this.n22=g;this.n23=e;this.n24=h;this.n31=i;this.n32=j;this.n33=k;this.n34=q;this.n41=m;this.n42=o;this.n43=p;this.n44=n;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){this.set(a.n11,a.n12,a.n13,a.n14,a.n21,a.n22,a.n23,a.n24,a.n31,a.n32,a.n33,a.n34,a.n41,a.n42,a.n43,a.n44);return this},lookAt:function(a,
+b,c){var d=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,g=THREE.Matrix4.__v3;g.sub(a,b).normalize();if(0===g.length())g.z=1;d.cross(c,g).normalize();0===d.length()&&(g.x+=1.0E-4,d.cross(c,g).normalize());f.cross(g,d);this.n11=d.x;this.n12=f.x;this.n13=g.x;this.n21=d.y;this.n22=f.y;this.n23=g.y;this.n31=d.z;this.n32=f.z;this.n33=g.z;return this},multiply:function(a,b){var c=a.n11,d=a.n12,f=a.n13,g=a.n14,e=a.n21,h=a.n22,i=a.n23,j=a.n24,k=a.n31,q=a.n32,m=a.n33,o=a.n34,p=a.n41,n=a.n42,r=a.n43,s=a.n44,t=b.n11,
+w=b.n12,u=b.n13,v=b.n14,A=b.n21,F=b.n22,B=b.n23,D=b.n24,H=b.n31,I=b.n32,Q=b.n33,P=b.n34,L=b.n41,K=b.n42,O=b.n43,y=b.n44;this.n11=c*t+d*A+f*H+g*L;this.n12=c*w+d*F+f*I+g*K;this.n13=c*u+d*B+f*Q+g*O;this.n14=c*v+d*D+f*P+g*y;this.n21=e*t+h*A+i*H+j*L;this.n22=e*w+h*F+i*I+j*K;this.n23=e*u+h*B+i*Q+j*O;this.n24=e*v+h*D+i*P+j*y;this.n31=k*t+q*A+m*H+o*L;this.n32=k*w+q*F+m*I+o*K;this.n33=k*u+q*B+m*Q+o*O;this.n34=k*v+q*D+m*P+o*y;this.n41=p*t+n*A+r*H+s*L;this.n42=p*w+n*F+r*I+s*K;this.n43=p*u+n*B+r*Q+s*O;this.n44=
+p*v+n*D+r*P+s*y;return this},multiplySelf:function(a){return this.multiply(this,a)},multiplyToArray:function(a,b,c){this.multiply(a,b);c[0]=this.n11;c[1]=this.n21;c[2]=this.n31;c[3]=this.n41;c[4]=this.n12;c[5]=this.n22;c[6]=this.n32;c[7]=this.n42;c[8]=this.n13;c[9]=this.n23;c[10]=this.n33;c[11]=this.n43;c[12]=this.n14;c[13]=this.n24;c[14]=this.n34;c[15]=this.n44;return this},multiplyScalar:function(a){this.n11*=a;this.n12*=a;this.n13*=a;this.n14*=a;this.n21*=a;this.n22*=a;this.n23*=a;this.n24*=a;
+this.n31*=a;this.n32*=a;this.n33*=a;this.n34*=a;this.n41*=a;this.n42*=a;this.n43*=a;this.n44*=a;return this},multiplyVector3:function(a){var b=a.x,c=a.y,d=a.z,f=1/(this.n41*b+this.n42*c+this.n43*d+this.n44);a.x=(this.n11*b+this.n12*c+this.n13*d+this.n14)*f;a.y=(this.n21*b+this.n22*c+this.n23*d+this.n24)*f;a.z=(this.n31*b+this.n32*c+this.n33*d+this.n34)*f;return a},multiplyVector4:function(a){var b=a.x,c=a.y,d=a.z,f=a.w;a.x=this.n11*b+this.n12*c+this.n13*d+this.n14*f;a.y=this.n21*b+this.n22*c+this.n23*
+d+this.n24*f;a.z=this.n31*b+this.n32*c+this.n33*d+this.n34*f;a.w=this.n41*b+this.n42*c+this.n43*d+this.n44*f;return a},rotateAxis:function(a){var b=a.x,c=a.y,d=a.z;a.x=b*this.n11+c*this.n12+d*this.n13;a.y=b*this.n21+c*this.n22+d*this.n23;a.z=b*this.n31+c*this.n32+d*this.n33;a.normalize();return a},crossVector:function(a){var b=new THREE.Vector4;b.x=this.n11*a.x+this.n12*a.y+this.n13*a.z+this.n14*a.w;b.y=this.n21*a.x+this.n22*a.y+this.n23*a.z+this.n24*a.w;b.z=this.n31*a.x+this.n32*a.y+this.n33*a.z+
+this.n34*a.w;b.w=a.w?this.n41*a.x+this.n42*a.y+this.n43*a.z+this.n44*a.w:1;return b},determinant:function(){var a=this.n11,b=this.n12,c=this.n13,d=this.n14,f=this.n21,g=this.n22,e=this.n23,h=this.n24,i=this.n31,j=this.n32,k=this.n33,q=this.n34,m=this.n41,o=this.n42,p=this.n43,n=this.n44;return d*e*j*m-c*h*j*m-d*g*k*m+b*h*k*m+c*g*q*m-b*e*q*m-d*e*i*o+c*h*i*o+d*f*k*o-a*h*k*o-c*f*q*o+a*e*q*o+d*g*i*p-b*h*i*p-d*f*j*p+a*h*j*p+b*f*q*p-a*g*q*p-c*g*i*n+b*e*i*n+c*f*j*n-a*e*j*n-b*f*k*n+a*g*k*n},transpose:function(){var a;
+a=this.n21;this.n21=this.n12;this.n12=a;a=this.n31;this.n31=this.n13;this.n13=a;a=this.n32;this.n32=this.n23;this.n23=a;a=this.n41;this.n41=this.n14;this.n14=a;a=this.n42;this.n42=this.n24;this.n24=a;a=this.n43;this.n43=this.n34;this.n34=a;return this},clone:function(){var a=new THREE.Matrix4;a.n11=this.n11;a.n12=this.n12;a.n13=this.n13;a.n14=this.n14;a.n21=this.n21;a.n22=this.n22;a.n23=this.n23;a.n24=this.n24;a.n31=this.n31;a.n32=this.n32;a.n33=this.n33;a.n34=this.n34;a.n41=this.n41;a.n42=this.n42;
+a.n43=this.n43;a.n44=this.n44;return a},flattenToArray:function(a){a[0]=this.n11;a[1]=this.n21;a[2]=this.n31;a[3]=this.n41;a[4]=this.n12;a[5]=this.n22;a[6]=this.n32;a[7]=this.n42;a[8]=this.n13;a[9]=this.n23;a[10]=this.n33;a[11]=this.n43;a[12]=this.n14;a[13]=this.n24;a[14]=this.n34;a[15]=this.n44;return a},flattenToArrayOffset:function(a,b){a[b]=this.n11;a[b+1]=this.n21;a[b+2]=this.n31;a[b+3]=this.n41;a[b+4]=this.n12;a[b+5]=this.n22;a[b+6]=this.n32;a[b+7]=this.n42;a[b+8]=this.n13;a[b+9]=this.n23;a[b+
+10]=this.n33;a[b+11]=this.n43;a[b+12]=this.n14;a[b+13]=this.n24;a[b+14]=this.n34;a[b+15]=this.n44;return a},setTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},setScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},setRotationX:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},setRotationY:function(a){var b=Math.cos(a),a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},setRotationZ:function(a){var b=
+Math.cos(a),a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},setRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),f=1-c,g=a.x,e=a.y,h=a.z,i=f*g,j=f*e;this.set(i*g+c,i*e-d*h,i*h+d*e,0,i*e+d*h,j*e+c,j*h-d*g,0,i*h-d*e,j*h+d*g,f*h*h+c,0,0,0,0,1);return this},setPosition:function(a){this.n14=a.x;this.n24=a.y;this.n34=a.z;return this},getPosition:function(){return THREE.Matrix4.__v1.set(this.n14,this.n24,this.n34)},getColumnX:function(){return THREE.Matrix4.__v1.set(this.n11,
+this.n21,this.n31)},getColumnY:function(){return THREE.Matrix4.__v1.set(this.n12,this.n22,this.n32)},getColumnZ:function(){return THREE.Matrix4.__v1.set(this.n13,this.n23,this.n33)},getInverse:function(a){var b=a.n11,c=a.n12,d=a.n13,f=a.n14,g=a.n21,e=a.n22,h=a.n23,i=a.n24,j=a.n31,k=a.n32,q=a.n33,m=a.n34,o=a.n41,p=a.n42,n=a.n43,r=a.n44;this.n11=h*m*p-i*q*p+i*k*n-e*m*n-h*k*r+e*q*r;this.n12=f*q*p-d*m*p-f*k*n+c*m*n+d*k*r-c*q*r;this.n13=d*i*p-f*h*p+f*e*n-c*i*n-d*e*r+c*h*r;this.n14=f*h*k-d*i*k-f*e*q+c*
+i*q+d*e*m-c*h*m;this.n21=i*q*o-h*m*o-i*j*n+g*m*n+h*j*r-g*q*r;this.n22=d*m*o-f*q*o+f*j*n-b*m*n-d*j*r+b*q*r;this.n23=f*h*o-d*i*o-f*g*n+b*i*n+d*g*r-b*h*r;this.n24=d*i*j-f*h*j+f*g*q-b*i*q-d*g*m+b*h*m;this.n31=e*m*o-i*k*o+i*j*p-g*m*p-e*j*r+g*k*r;this.n32=f*k*o-c*m*o-f*j*p+b*m*p+c*j*r-b*k*r;this.n33=c*i*o-f*e*o+f*g*p-b*i*p-c*g*r+b*e*r;this.n34=f*e*j-c*i*j-f*g*k+b*i*k+c*g*m-b*e*m;this.n41=h*k*o-e*q*o-h*j*p+g*q*p+e*j*n-g*k*n;this.n42=c*q*o-d*k*o+d*j*p-b*q*p-c*j*n+b*k*n;this.n43=d*e*o-c*h*o-d*g*p+b*h*p+c*
+g*n-b*e*n;this.n44=c*h*j-d*e*j+d*g*k-b*h*k-c*g*q+b*e*q;this.multiplyScalar(1/a.determinant());return this},setRotationFromEuler:function(a,b){var c=a.x,d=a.y,f=a.z,g=Math.cos(c),c=Math.sin(c),e=Math.cos(d),d=Math.sin(d),h=Math.cos(f),f=Math.sin(f);switch(b){case "YXZ":var i=e*h,j=e*f,k=d*h,q=d*f;this.n11=i+q*c;this.n12=k*c-j;this.n13=g*d;this.n21=g*f;this.n22=g*h;this.n23=-c;this.n31=j*c-k;this.n32=q+i*c;this.n33=g*e;break;case "ZXY":i=e*h;j=e*f;k=d*h;q=d*f;this.n11=i-q*c;this.n12=-g*f;this.n13=k+
+j*c;this.n21=j+k*c;this.n22=g*h;this.n23=q-i*c;this.n31=-g*d;this.n32=c;this.n33=g*e;break;case "ZYX":i=g*h;j=g*f;k=c*h;q=c*f;this.n11=e*h;this.n12=k*d-j;this.n13=i*d+q;this.n21=e*f;this.n22=q*d+i;this.n23=j*d-k;this.n31=-d;this.n32=c*e;this.n33=g*e;break;case "YZX":i=g*e;j=g*d;k=c*e;q=c*d;this.n11=e*h;this.n12=q-i*f;this.n13=k*f+j;this.n21=f;this.n22=g*h;this.n23=-c*h;this.n31=-d*h;this.n32=j*f+k;this.n33=i-q*f;break;case "XZY":i=g*e;j=g*d;k=c*e;q=c*d;this.n11=e*h;this.n12=-f;this.n13=d*h;this.n21=
+i*f+q;this.n22=g*h;this.n23=j*f-k;this.n31=k*f-j;this.n32=c*h;this.n33=q*f+i;break;default:i=g*h,j=g*f,k=c*h,q=c*f,this.n11=e*h,this.n12=-e*f,this.n13=d,this.n21=j+k*d,this.n22=i-q*d,this.n23=-c*e,this.n31=q-i*d,this.n32=k+j*d,this.n33=g*e}return this},setRotationFromQuaternion:function(a){var b=a.x,c=a.y,d=a.z,f=a.w,g=b+b,e=c+c,h=d+d,a=b*g,i=b*e,b=b*h,j=c*e,c=c*h,d=d*h,g=f*g,e=f*e,f=f*h;this.n11=1-(j+d);this.n12=i-f;this.n13=b+e;this.n21=i+f;this.n22=1-(a+d);this.n23=c-g;this.n31=b-e;this.n32=c+
+g;this.n33=1-(a+j);return this},scale:function(a){var b=a.x,c=a.y,a=a.z;this.n11*=b;this.n12*=c;this.n13*=a;this.n21*=b;this.n22*=c;this.n23*=a;this.n31*=b;this.n32*=c;this.n33*=a;this.n41*=b;this.n42*=c;this.n43*=a;return this},compose:function(a,b,c){var d=THREE.Matrix4.__m1,f=THREE.Matrix4.__m2;d.identity();d.setRotationFromQuaternion(b);f.setScale(c.x,c.y,c.z);this.multiply(d,f);this.n14=a.x;this.n24=a.y;this.n34=a.z;return this},decompose:function(a,b,c){var d=THREE.Matrix4.__v1,f=THREE.Matrix4.__v2,
+g=THREE.Matrix4.__v3;d.set(this.n11,this.n21,this.n31);f.set(this.n12,this.n22,this.n32);g.set(this.n13,this.n23,this.n33);a=a instanceof THREE.Vector3?a:new THREE.Vector3;b=b instanceof THREE.Quaternion?b:new THREE.Quaternion;c=c instanceof THREE.Vector3?c:new THREE.Vector3;c.x=d.length();c.y=f.length();c.z=g.length();a.x=this.n14;a.y=this.n24;a.z=this.n34;d=THREE.Matrix4.__m1;d.copy(this);d.n11/=c.x;d.n21/=c.x;d.n31/=c.x;d.n12/=c.y;d.n22/=c.y;d.n32/=c.y;d.n13/=c.z;d.n23/=c.z;d.n33/=c.z;b.setFromRotationMatrix(d);
+return[a,b,c]},extractPosition:function(a){this.n14=a.n14;this.n24=a.n24;this.n34=a.n34;return this},extractRotation:function(a){var b=THREE.Matrix4.__v1,c=1/b.set(a.n11,a.n21,a.n31).length(),d=1/b.set(a.n12,a.n22,a.n32).length(),b=1/b.set(a.n13,a.n23,a.n33).length();this.n11=a.n11*c;this.n21=a.n21*c;this.n31=a.n31*c;this.n12=a.n12*d;this.n22=a.n22*d;this.n32=a.n32*d;this.n13=a.n13*b;this.n23=a.n23*b;this.n33=a.n33*b;return this},rotateByAxis:function(a,b){if(1===a.x&&0===a.y&&0===a.z)return this.rotateX(b);
+if(0===a.x&&1===a.y&&0===a.z)return this.rotateY(b);if(0===a.x&&0===a.y&&1===a.z)return this.rotateZ(b);var c=a.x,d=a.y,f=a.z,g=Math.sqrt(c*c+d*d+f*f),c=c/g,d=d/g,f=f/g,g=c*c,e=d*d,h=f*f,i=Math.cos(b),j=Math.sin(b),k=1-i,q=c*d*k,m=c*f*k,k=d*f*k,c=c*j,o=d*j,j=f*j,f=g+(1-g)*i,g=q+j,d=m-o,q=q-j,e=e+(1-e)*i,j=k+c,m=m+o,k=k-c,h=h+(1-h)*i,i=this.n11,c=this.n21,o=this.n31,p=this.n41,n=this.n12,r=this.n22,s=this.n32,t=this.n42,w=this.n13,u=this.n23,v=this.n33,A=this.n43;this.n11=f*i+g*n+d*w;this.n21=f*c+
+g*r+d*u;this.n31=f*o+g*s+d*v;this.n41=f*p+g*t+d*A;this.n12=q*i+e*n+j*w;this.n22=q*c+e*r+j*u;this.n32=q*o+e*s+j*v;this.n42=q*p+e*t+j*A;this.n13=m*i+k*n+h*w;this.n23=m*c+k*r+h*u;this.n33=m*o+k*s+h*v;this.n43=m*p+k*t+h*A;return this},rotateX:function(a){var b=this.n12,c=this.n22,d=this.n32,f=this.n42,g=this.n13,e=this.n23,h=this.n33,i=this.n43,j=Math.cos(a),a=Math.sin(a);this.n12=j*b+a*g;this.n22=j*c+a*e;this.n32=j*d+a*h;this.n42=j*f+a*i;this.n13=j*g-a*b;this.n23=j*e-a*c;this.n33=j*h-a*d;this.n43=j*
+i-a*f;return this},rotateY:function(a){var b=this.n11,c=this.n21,d=this.n31,f=this.n41,g=this.n13,e=this.n23,h=this.n33,i=this.n43,j=Math.cos(a),a=Math.sin(a);this.n11=j*b-a*g;this.n21=j*c-a*e;this.n31=j*d-a*h;this.n41=j*f-a*i;this.n13=j*g+a*b;this.n23=j*e+a*c;this.n33=j*h+a*d;this.n43=j*i+a*f;return this},rotateZ:function(a){var b=this.n11,c=this.n21,d=this.n31,f=this.n41,g=this.n12,e=this.n22,h=this.n32,i=this.n42,j=Math.cos(a),a=Math.sin(a);this.n11=j*b+a*g;this.n21=j*c+a*e;this.n31=j*d+a*h;this.n41=
+j*f+a*i;this.n12=j*g-a*b;this.n22=j*e-a*c;this.n32=j*h-a*d;this.n42=j*i-a*f;return this},translate:function(a){var b=a.x,c=a.y,a=a.z;this.n14=this.n11*b+this.n12*c+this.n13*a+this.n14;this.n24=this.n21*b+this.n22*c+this.n23*a+this.n24;this.n34=this.n31*b+this.n32*c+this.n33*a+this.n34;this.n44=this.n41*b+this.n42*c+this.n43*a+this.n44;return this}};
+THREE.Matrix4.makeInvert3x3=function(a){var b=a.m33,c=b.m,d=a.n33*a.n22-a.n32*a.n23,f=-a.n33*a.n21+a.n31*a.n23,g=a.n32*a.n21-a.n31*a.n22,e=-a.n33*a.n12+a.n32*a.n13,h=a.n33*a.n11-a.n31*a.n13,i=-a.n32*a.n11+a.n31*a.n12,j=a.n23*a.n12-a.n22*a.n13,k=-a.n23*a.n11+a.n21*a.n13,q=a.n22*a.n11-a.n21*a.n12,a=a.n11*d+a.n21*e+a.n31*j;if(0===a)return null;a=1/a;c[0]=a*d;c[1]=a*f;c[2]=a*g;c[3]=a*e;c[4]=a*h;c[5]=a*i;c[6]=a*j;c[7]=a*k;c[8]=a*q;return b};
+THREE.Matrix4.makeFrustum=function(a,b,c,d,f,g){var e;e=new THREE.Matrix4;e.n11=2*f/(b-a);e.n12=0;e.n13=(b+a)/(b-a);e.n14=0;e.n21=0;e.n22=2*f/(d-c);e.n23=(d+c)/(d-c);e.n24=0;e.n31=0;e.n32=0;e.n33=-(g+f)/(g-f);e.n34=-2*g*f/(g-f);e.n41=0;e.n42=0;e.n43=-1;e.n44=0;return e};THREE.Matrix4.makePerspective=function(a,b,c,d){var f,a=c*Math.tan(a*Math.PI/360);f=-a;return THREE.Matrix4.makeFrustum(f*b,a*b,f,a,c,d)};
+THREE.Matrix4.makeOrtho=function(a,b,c,d,f,g){var e,h,i,j;e=new THREE.Matrix4;h=b-a;i=c-d;j=g-f;e.n11=2/h;e.n12=0;e.n13=0;e.n14=-((b+a)/h);e.n21=0;e.n22=2/i;e.n23=0;e.n24=-((c+d)/i);e.n31=0;e.n32=0;e.n33=-2/j;e.n34=-((g+f)/j);e.n41=0;e.n42=0;e.n43=0;e.n44=1;return e};THREE.Matrix4.__v1=new THREE.Vector3;THREE.Matrix4.__v2=new THREE.Vector3;THREE.Matrix4.__v3=new THREE.Vector3;THREE.Matrix4.__m1=new THREE.Matrix4;THREE.Matrix4.__m2=new THREE.Matrix4;
+THREE.Object3D=function(){this.id=THREE.Object3DCount++;this.name="";this.parent=void 0;this.children=[];this.up=new THREE.Vector3(0,1,0);this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.eulerOrder="XYZ";this.scale=new THREE.Vector3(1,1,1);this.flipSided=this.doubleSided=!1;this.renderDepth=null;this.rotationAutoUpdate=!0;this.matrix=new THREE.Matrix4;this.matrixWorld=new THREE.Matrix4;this.matrixRotationWorld=new THREE.Matrix4;this.matrixWorldNeedsUpdate=this.matrixAutoUpdate=
+!0;this.quaternion=new THREE.Quaternion;this.useQuaternion=!1;this.boundRadius=0;this.boundRadiusScale=1;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this._vector=new THREE.Vector3};
+THREE.Object3D.prototype={constructor:THREE.Object3D,applyMatrix:function(a){this.matrix.multiply(a,this.matrix);this.scale.getScaleFromMatrix(this.matrix);this.rotation.getRotationFromMatrix(this.matrix,this.scale);this.position.getPositionFromMatrix(this.matrix)},translate:function(a,b){this.matrix.rotateAxis(b);this.position.addSelf(b.multiplyScalar(a))},translateX:function(a){this.translate(a,this._vector.set(1,0,0))},translateY:function(a){this.translate(a,this._vector.set(0,1,0))},translateZ:function(a){this.translate(a,
+this._vector.set(0,0,1))},lookAt:function(a){this.matrix.lookAt(a,this.position,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)},add:function(a){if(a===this)console.warn("THREE.Object3D.add: An object can't be added as a child of itself.");else if(-1===this.children.indexOf(a)){void 0!==a.parent&&a.parent.remove(a);a.parent=this;this.children.push(a);for(var b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__addObject(a)}},remove:function(a){var b=
+this.children.indexOf(a);if(-1!==b){a.parent=void 0;this.children.splice(b,1);for(b=this;void 0!==b.parent;)b=b.parent;void 0!==b&&b instanceof THREE.Scene&&b.__removeObject(a)}},getChildByName:function(a,b){var c,d,f;for(c=0,d=this.children.length;c<d;c++){f=this.children[c];if(f.name===a||b&&(f=f.getChildByName(a,b),void 0!==f))return f}},updateMatrix:function(){this.matrix.setPosition(this.position);this.useQuaternion?this.matrix.setRotationFromQuaternion(this.quaternion):this.matrix.setRotationFromEuler(this.rotation,
+this.eulerOrder);if(1!==this.scale.x||1!==this.scale.y||1!==this.scale.z)this.matrix.scale(this.scale),this.boundRadiusScale=Math.max(this.scale.x,Math.max(this.scale.y,this.scale.z));this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=0,c=this.children.length;b<
+c;b++)this.children[b].updateMatrixWorld(a)}};THREE.Object3DCount=0;
+THREE.Projector=function(){function a(){var a=e[g]=e[g]||new THREE.RenderableObject;g++;return a}function b(){var a=j[i]=j[i]||new THREE.RenderableVertex;i++;return a}function c(a,b){return b.z-a.z}function d(a,b){var c=0,d=1,f=a.z+a.w,g=b.z+b.w,e=-a.z+a.w,h=-b.z+b.w;if(0<=f&&0<=g&&0<=e&&0<=h)return!0;if(0>f&&0>g||0>e&&0>h)return!1;0>f?c=Math.max(c,f/(f-g)):0>g&&(d=Math.min(d,f/(f-g)));0>e?c=Math.max(c,e/(e-h)):0>h&&(d=Math.min(d,e/(e-h)));if(d<c)return!1;a.lerpSelf(b,c);b.lerpSelf(a,1-d);return!0}
+var f,g,e=[],h,i,j=[],k,q,m=[],o,p=[],n,r,s=[],t,w,u=[],v={objects:[],sprites:[],lights:[],elements:[]},A=new THREE.Vector3,F=new THREE.Vector4,B=new THREE.Matrix4,D=new THREE.Matrix4,H=new THREE.Frustum,I=new THREE.Vector4,Q=new THREE.Vector4;this.projectVector=function(a,b){b.matrixWorldInverse.getInverse(b.matrixWorld);B.multiply(b.projectionMatrix,b.matrixWorldInverse);B.multiplyVector3(a);return a};this.unprojectVector=function(a,b){b.projectionMatrixInverse.getInverse(b.projectionMatrix);B.multiply(b.matrixWorld,
+b.projectionMatrixInverse);B.multiplyVector3(a);return a};this.pickingRay=function(a,b){var c;a.z=-1;c=new THREE.Vector3(a.x,a.y,1);this.unprojectVector(a,b);this.unprojectVector(c,b);c.subSelf(a).normalize();return new THREE.Ray(a,c)};this.projectGraph=function(b,d){g=0;v.objects.length=0;v.sprites.length=0;v.lights.length=0;var e=function(b){if(!1!==b.visible){(b instanceof THREE.Mesh||b instanceof THREE.Line)&&(!1===b.frustumCulled||H.contains(b))?(B.multiplyVector3(A.copy(b.position)),f=a(),f.object=
+b,f.z=A.z,v.objects.push(f)):b instanceof THREE.Sprite||b instanceof THREE.Particle?(B.multiplyVector3(A.copy(b.position)),f=a(),f.object=b,f.z=A.z,v.sprites.push(f)):b instanceof THREE.Light&&v.lights.push(b);for(var c=0,d=b.children.length;c<d;c++)e(b.children[c])}};e(b);d&&v.objects.sort(c);return v};this.projectScene=function(a,f,g){var e=f.near,y=f.far,l=!1,A,C,E,S,R,ca,ka,ia,N,aa,U,ba,ea,Ta,Ja;w=r=o=q=0;v.elements.length=0;void 0===f.parent&&(console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it..."),
+a.add(f));a.updateMatrixWorld();f.matrixWorldInverse.getInverse(f.matrixWorld);B.multiply(f.projectionMatrix,f.matrixWorldInverse);H.setFromMatrix(B);v=this.projectGraph(a,!1);for(a=0,A=v.objects.length;a<A;a++)if(N=v.objects[a].object,aa=N.matrixWorld,i=0,N instanceof THREE.Mesh){U=N.geometry;ba=N.geometry.materials;S=U.vertices;ea=U.faces;Ta=U.faceVertexUvs;U=N.matrixRotationWorld.extractRotation(aa);for(C=0,E=S.length;C<E;C++)h=b(),h.positionWorld.copy(S[C].position),aa.multiplyVector3(h.positionWorld),
+h.positionScreen.copy(h.positionWorld),B.multiplyVector4(h.positionScreen),h.positionScreen.x/=h.positionScreen.w,h.positionScreen.y/=h.positionScreen.w,h.visible=h.positionScreen.z>e&&h.positionScreen.z<y;for(S=0,C=ea.length;S<C;S++){E=ea[S];if(E instanceof THREE.Face3)if(R=j[E.a],ca=j[E.b],ka=j[E.c],R.visible&&ca.visible&&ka.visible)if(l=0>(ka.positionScreen.x-R.positionScreen.x)*(ca.positionScreen.y-R.positionScreen.y)-(ka.positionScreen.y-R.positionScreen.y)*(ca.positionScreen.x-R.positionScreen.x),
+N.doubleSided||l!=N.flipSided)ia=m[q]=m[q]||new THREE.RenderableFace3,q++,k=ia,k.v1.copy(R),k.v2.copy(ca),k.v3.copy(ka);else continue;else continue;else if(E instanceof THREE.Face4)if(R=j[E.a],ca=j[E.b],ka=j[E.c],ia=j[E.d],R.visible&&ca.visible&&ka.visible&&ia.visible)if(l=0>(ia.positionScreen.x-R.positionScreen.x)*(ca.positionScreen.y-R.positionScreen.y)-(ia.positionScreen.y-R.positionScreen.y)*(ca.positionScreen.x-R.positionScreen.x)||0>(ca.positionScreen.x-ka.positionScreen.x)*(ia.positionScreen.y-
+ka.positionScreen.y)-(ca.positionScreen.y-ka.positionScreen.y)*(ia.positionScreen.x-ka.positionScreen.x),N.doubleSided||l!=N.flipSided)Ja=p[o]=p[o]||new THREE.RenderableFace4,o++,k=Ja,k.v1.copy(R),k.v2.copy(ca),k.v3.copy(ka),k.v4.copy(ia);else continue;else continue;k.normalWorld.copy(E.normal);!l&&(N.flipSided||N.doubleSided)&&k.normalWorld.negate();U.multiplyVector3(k.normalWorld);k.centroidWorld.copy(E.centroid);aa.multiplyVector3(k.centroidWorld);k.centroidScreen.copy(k.centroidWorld);B.multiplyVector3(k.centroidScreen);
+ka=E.vertexNormals;for(R=0,ca=ka.length;R<ca;R++)ia=k.vertexNormalsWorld[R],ia.copy(ka[R]),!l&&(N.flipSided||N.doubleSided)&&ia.negate(),U.multiplyVector3(ia);for(R=0,ca=Ta.length;R<ca;R++)if(Ja=Ta[R][S])for(ka=0,ia=Ja.length;ka<ia;ka++)k.uvs[R][ka]=Ja[ka];k.material=N.material;k.faceMaterial=null!==E.materialIndex?ba[E.materialIndex]:null;k.z=k.centroidScreen.z;v.elements.push(k)}}else if(N instanceof THREE.Line){D.multiply(B,aa);S=N.geometry.vertices;R=b();R.positionScreen.copy(S[0].position);D.multiplyVector4(R.positionScreen);
+for(C=1,E=S.length;C<E;C++)if(R=b(),R.positionScreen.copy(S[C].position),D.multiplyVector4(R.positionScreen),ca=j[i-2],I.copy(R.positionScreen),Q.copy(ca.positionScreen),d(I,Q))I.multiplyScalar(1/I.w),Q.multiplyScalar(1/Q.w),aa=s[r]=s[r]||new THREE.RenderableLine,r++,n=aa,n.v1.positionScreen.copy(I),n.v2.positionScreen.copy(Q),n.z=Math.max(I.z,Q.z),n.material=N.material,v.elements.push(n)}for(a=0,A=v.sprites.length;a<A;a++)if(N=v.sprites[a].object,aa=N.matrixWorld,N instanceof THREE.Particle&&(F.set(aa.n14,
+aa.n24,aa.n34,1),B.multiplyVector4(F),F.z/=F.w,0<F.z&&1>F.z))e=u[w]=u[w]||new THREE.RenderableParticle,w++,t=e,t.x=F.x/F.w,t.y=F.y/F.w,t.z=F.z,t.rotation=N.rotation.z,t.scale.x=N.scale.x*Math.abs(t.x-(F.x+f.projectionMatrix.n11)/(F.w+f.projectionMatrix.n14)),t.scale.y=N.scale.y*Math.abs(t.y-(F.y+f.projectionMatrix.n22)/(F.w+f.projectionMatrix.n24)),t.material=N.material,v.elements.push(t);g&&v.elements.sort(c);return v}};
+THREE.Quaternion=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1};
+THREE.Quaternion.prototype={constructor:THREE.Quaternion,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w;return this},clone:function(){return new THREE.Quaternion(this.x,this.y,this.z,this.w)},setFromEuler:function(a){var b=Math.PI/360,c=a.x*b,d=a.y*b,f=a.z*b,a=Math.cos(d),d=Math.sin(d),b=Math.cos(-f),f=Math.sin(-f),g=Math.cos(c),c=Math.sin(c),e=a*b,h=d*f;this.w=e*g-h*c;this.x=e*c+h*g;this.y=d*b*g+a*f*c;this.z=a*f*
+g-d*b*c;return this},setFromAxisAngle:function(a,b){var c=b/2,d=Math.sin(c);this.x=a.x*d;this.y=a.y*d;this.z=a.z*d;this.w=Math.cos(c);return this},setFromRotationMatrix:function(a){var b=Math.pow(a.determinant(),1/3);this.w=Math.sqrt(Math.max(0,b+a.n11+a.n22+a.n33))/2;this.x=Math.sqrt(Math.max(0,b+a.n11-a.n22-a.n33))/2;this.y=Math.sqrt(Math.max(0,b-a.n11+a.n22-a.n33))/2;this.z=Math.sqrt(Math.max(0,b-a.n11-a.n22+a.n33))/2;this.x=0>a.n32-a.n23?-Math.abs(this.x):Math.abs(this.x);this.y=0>a.n13-a.n31?
+-Math.abs(this.y):Math.abs(this.y);this.z=0>a.n21-a.n12?-Math.abs(this.z):Math.abs(this.z);this.normalize();return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x*=-1;this.y*=-1;this.z*=-1;return this},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);0===a?this.w=this.z=
+this.y=this.x=0:(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a);return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,f=this.w,g=a.x,e=a.y,h=a.z,a=a.w;this.x=b*a+f*g+c*h-d*e;this.y=c*a+f*e+d*g-b*h;this.z=d*a+f*h+b*e-c*g;this.w=f*a-b*g-c*e-d*h;return this},multiply:function(a,b){this.x=a.x*b.w+a.y*b.z-a.z*b.y+a.w*b.x;this.y=-a.x*b.z+a.y*b.w+a.z*b.x+a.w*b.y;this.z=a.x*b.y-a.y*b.x+a.z*b.w+a.w*b.z;this.w=-a.x*b.x-a.y*b.y-a.z*b.z+a.w*b.w;return this},multiplyVector3:function(a,b){b||(b=
+a);var c=a.x,d=a.y,f=a.z,g=this.x,e=this.y,h=this.z,i=this.w,j=i*c+e*f-h*d,k=i*d+h*c-g*f,q=i*f+g*d-e*c,c=-g*c-e*d-h*f;b.x=j*i+c*-g+k*-h-q*-e;b.y=k*i+c*-e+q*-g-j*-h;b.z=q*i+c*-h+j*-e-k*-g;return b}};
+THREE.Quaternion.slerp=function(a,b,c,d){var f=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;0>f?(c.w=-b.w,c.x=-b.x,c.y=-b.y,c.z=-b.z,f=-f):c.copy(b);if(1<=Math.abs(f))return c.w=a.w,c.x=a.x,c.y=a.y,c.z=a.z,c;var g=Math.acos(f),f=Math.sqrt(1-f*f);if(0.001>Math.abs(f))return c.w=0.5*(a.w+b.w),c.x=0.5*(a.x+b.x),c.y=0.5*(a.y+b.y),c.z=0.5*(a.z+b.z),c;b=Math.sin((1-d)*g)/f;d=Math.sin(d*g)/f;c.w=a.w*b+c.w*d;c.x=a.x*b+c.x*d;c.y=a.y*b+c.y*d;c.z=a.z*b+c.z*d;return c};THREE.Vertex=function(a){this.position=a||new THREE.Vector3};
+THREE.Vertex.prototype={constructor:THREE.Vertex,clone:function(){return new THREE.Vertex(this.position.clone())}};THREE.Face3=function(a,b,c,d,f,g){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=f instanceof THREE.Color?f:new THREE.Color;this.vertexColors=f instanceof Array?f:[];this.vertexTangents=[];this.materialIndex=g;this.centroid=new THREE.Vector3};
+THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;for(b=0,c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();for(b=0,c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();for(b=0,c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone();
+return a}};THREE.Face4=function(a,b,c,d,f,g,e){this.a=a;this.b=b;this.c=c;this.d=d;this.normal=f instanceof THREE.Vector3?f:new THREE.Vector3;this.vertexNormals=f instanceof Array?f:[];this.color=g instanceof THREE.Color?g:new THREE.Color;this.vertexColors=g instanceof Array?g:[];this.vertexTangents=[];this.materialIndex=e;this.centroid=new THREE.Vector3};
+THREE.Face4.prototype={constructor:THREE.Face4,clone:function(){var a=new THREE.Face4(this.a,this.b,this.c,this.d);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;for(b=0,c=this.vertexNormals.length;b<c;b++)a.vertexNormals[b]=this.vertexNormals[b].clone();for(b=0,c=this.vertexColors.length;b<c;b++)a.vertexColors[b]=this.vertexColors[b].clone();for(b=0,c=this.vertexTangents.length;b<c;b++)a.vertexTangents[b]=this.vertexTangents[b].clone();
+return a}};THREE.UV=function(a,b){this.u=a||0;this.v=b||0};THREE.UV.prototype={constructor:THREE.UV,set:function(a,b){this.u=a;this.v=b;return this},copy:function(a){this.u=a.u;this.v=a.v;return this},lerpSelf:function(a,b){this.u+=(a.u-this.u)*b;this.v+=(a.v-this.v)*b;return this},clone:function(){return new THREE.UV(this.u,this.v)}};
+THREE.Geometry=function(){this.id=THREE.GeometryCount++;this.vertices=[];this.colors=[];this.materials=[];this.faces=[];this.faceUvs=[[]];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.dynamic=this.hasTangents=!1};
+THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){var b=new THREE.Matrix4;b.extractRotation(a);for(var c=0,d=this.vertices.length;c<d;c++)a.multiplyVector3(this.vertices[c].position);c=0;for(d=this.faces.length;c<d;c++){var f=this.faces[c];b.multiplyVector3(f.normal);for(var g=0,e=f.vertexNormals.length;g<e;g++)b.multiplyVector3(f.vertexNormals[g]);a.multiplyVector3(f.centroid)}},computeCentroids:function(){var a,b,c;for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],c.centroid.set(0,
+0,0),c instanceof THREE.Face3?(c.centroid.addSelf(this.vertices[c.a].position),c.centroid.addSelf(this.vertices[c.b].position),c.centroid.addSelf(this.vertices[c.c].position),c.centroid.divideScalar(3)):c instanceof THREE.Face4&&(c.centroid.addSelf(this.vertices[c.a].position),c.centroid.addSelf(this.vertices[c.b].position),c.centroid.addSelf(this.vertices[c.c].position),c.centroid.addSelf(this.vertices[c.d].position),c.centroid.divideScalar(4))},computeFaceNormals:function(){var a,b,c,d,f,g,e=new THREE.Vector3,
+h=new THREE.Vector3;for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],d=this.vertices[c.a],f=this.vertices[c.b],g=this.vertices[c.c],e.sub(g.position,f.position),h.sub(d.position,f.position),e.crossSelf(h),e.isZero()||e.normalize(),c.normal.copy(e)},computeVertexNormals:function(){var a,b,c,d;if(void 0===this.__tmpVertices){d=this.__tmpVertices=Array(this.vertices.length);for(a=0,b=this.vertices.length;a<b;a++)d[a]=new THREE.Vector3;for(a=0,b=this.faces.length;a<b;a++)if(c=this.faces[a],c instanceof
+THREE.Face3)c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];else if(c instanceof THREE.Face4)c.vertexNormals=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3]}else{d=this.__tmpVertices;for(a=0,b=this.vertices.length;a<b;a++)d[a].set(0,0,0)}for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],c instanceof THREE.Face3?(d[c.a].addSelf(c.normal),d[c.b].addSelf(c.normal),d[c.c].addSelf(c.normal)):c instanceof THREE.Face4&&(d[c.a].addSelf(c.normal),d[c.b].addSelf(c.normal),
+d[c.c].addSelf(c.normal),d[c.d].addSelf(c.normal));for(a=0,b=this.vertices.length;a<b;a++)d[a].normalize();for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],c instanceof THREE.Face3?(c.vertexNormals[0].copy(d[c.a]),c.vertexNormals[1].copy(d[c.b]),c.vertexNormals[2].copy(d[c.c])):c instanceof THREE.Face4&&(c.vertexNormals[0].copy(d[c.a]),c.vertexNormals[1].copy(d[c.b]),c.vertexNormals[2].copy(d[c.c]),c.vertexNormals[3].copy(d[c.d]))},computeMorphNormals:function(){var a,b,c,d,f;for(c=0,d=this.faces.length;c<
+d;c++){f=this.faces[c];f.__originalFaceNormal?f.__originalFaceNormal.copy(f.normal):f.__originalFaceNormal=f.normal.clone();if(!f.__originalVertexNormals)f.__originalVertexNormals=[];for(a=0,b=f.vertexNormals.length;a<b;a++)f.__originalVertexNormals[a]?f.__originalVertexNormals[a].copy(f.vertexNormals[a]):f.__originalVertexNormals[a]=f.vertexNormals[a].clone()}var g=new THREE.Geometry;g.faces=this.faces;for(a=0,b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};
+this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];var e=this.morphNormals[a].faceNormals,h=this.morphNormals[a].vertexNormals,i,j;for(c=0,d=this.faces.length;c<d;c++)f=this.faces[c],i=new THREE.Vector3,j=f instanceof THREE.Face3?{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3}:{a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3,d:new THREE.Vector3},e.push(i),h.push(j)}e=this.morphNormals[a];g.vertices=this.morphTargets[a].vertices;g.computeFaceNormals();
+g.computeVertexNormals();for(c=0,d=this.faces.length;c<d;c++)f=this.faces[c],i=e.faceNormals[c],j=e.vertexNormals[c],i.copy(f.normal),f instanceof THREE.Face3?(j.a.copy(f.vertexNormals[0]),j.b.copy(f.vertexNormals[1]),j.c.copy(f.vertexNormals[2])):(j.a.copy(f.vertexNormals[0]),j.b.copy(f.vertexNormals[1]),j.c.copy(f.vertexNormals[2]),j.d.copy(f.vertexNormals[3]))}for(c=0,d=this.faces.length;c<d;c++)f=this.faces[c],f.normal=f.__originalFaceNormal,f.vertexNormals=f.__originalVertexNormals},computeTangents:function(){function a(a,
+b,c,d,f,g,R){h=a.vertices[b].position;i=a.vertices[c].position;j=a.vertices[d].position;k=e[f];q=e[g];m=e[R];o=i.x-h.x;p=j.x-h.x;n=i.y-h.y;r=j.y-h.y;s=i.z-h.z;t=j.z-h.z;w=q.u-k.u;u=m.u-k.u;v=q.v-k.v;A=m.v-k.v;F=1/(w*A-u*v);I.set((A*o-v*p)*F,(A*n-v*r)*F,(A*s-v*t)*F);Q.set((w*p-u*o)*F,(w*r-u*n)*F,(w*t-u*s)*F);D[b].addSelf(I);D[c].addSelf(I);D[d].addSelf(I);H[b].addSelf(Q);H[c].addSelf(Q);H[d].addSelf(Q)}var b,c,d,f,g,e,h,i,j,k,q,m,o,p,n,r,s,t,w,u,v,A,F,B,D=[],H=[],I=new THREE.Vector3,Q=new THREE.Vector3,
+P=new THREE.Vector3,L=new THREE.Vector3,K=new THREE.Vector3;for(b=0,c=this.vertices.length;b<c;b++)D[b]=new THREE.Vector3,H[b]=new THREE.Vector3;for(b=0,c=this.faces.length;b<c;b++)g=this.faces[b],e=this.faceVertexUvs[0][b],g instanceof THREE.Face3?a(this,g.a,g.b,g.c,0,1,2):g instanceof THREE.Face4&&(a(this,g.a,g.b,g.c,0,1,2),a(this,g.a,g.b,g.d,0,1,3));var O=["a","b","c","d"];for(b=0,c=this.faces.length;b<c;b++){g=this.faces[b];for(d=0;d<g.vertexNormals.length;d++)K.copy(g.vertexNormals[d]),f=g[O[d]],
+B=D[f],P.copy(B),P.subSelf(K.multiplyScalar(K.dot(B))).normalize(),L.cross(g.vertexNormals[d],B),f=L.dot(H[f]),f=0>f?-1:1,g.vertexTangents[d]=new THREE.Vector4(P.x,P.y,P.z,f)}this.hasTangents=!0},computeBoundingBox:function(){if(!this.boundingBox)this.boundingBox={min:new THREE.Vector3,max:new THREE.Vector3};if(0<this.vertices.length){var a;a=this.vertices[0].position;this.boundingBox.min.copy(a);this.boundingBox.max.copy(a);for(var b=this.boundingBox.min,c=this.boundingBox.max,d=1,f=this.vertices.length;d<
+f;d++){a=this.vertices[d].position;if(a.x<b.x)b.x=a.x;else if(a.x>c.x)c.x=a.x;if(a.y<b.y)b.y=a.y;else if(a.y>c.y)c.y=a.y;if(a.z<b.z)b.z=a.z;else if(a.z>c.z)c.z=a.z}}else this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){if(!this.boundingSphere)this.boundingSphere={radius:0};for(var a,b=0,c=0,d=this.vertices.length;c<d;c++)a=this.vertices[c].position.length(),a>b&&(b=a);this.boundingSphere.radius=b},mergeVertices:function(){var a={},b=[],c=[],d,f=Math.pow(10,
+4),g,e;for(g=0,e=this.vertices.length;g<e;g++)d=this.vertices[g].position,d=[Math.round(d.x*f),Math.round(d.y*f),Math.round(d.z*f)].join("_"),void 0===a[d]?(a[d]=g,b.push(this.vertices[g]),c[g]=b.length-1):c[g]=c[a[d]];for(g=0,e=this.faces.length;g<e;g++)if(a=this.faces[g],a instanceof THREE.Face3)a.a=c[a.a],a.b=c[a.b],a.c=c[a.c];else if(a instanceof THREE.Face4)a.a=c[a.a],a.b=c[a.b],a.c=c[a.c],a.d=c[a.d];this.vertices=b}};THREE.GeometryCount=0;
+THREE.Spline=function(a){function b(a,b,c,d,f,g,e){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*e+(-3*(b-c)-2*a-d)*g+a*f+b}this.points=a;var c=[],d={x:0,y:0,z:0},f,g,e,h,i,j,k,q,m;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){f=(this.points.length-1)*a;g=Math.floor(f);e=f-g;c[0]=0===g?g:g-1;c[1]=g;c[2]=g>this.points.length-2?g:g+1;c[3]=g>this.points.length-3?g:g+2;j=this.points[c[0]];k=this.points[c[1]];
+q=this.points[c[2]];m=this.points[c[3]];h=e*e;i=e*h;d.x=b(j.x,k.x,q.x,m.x,e,h,i);d.y=b(j.y,k.y,q.y,m.y,e,h,i);d.z=b(j.z,k.z,q.z,m.z,e,h,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,f=b=b=0,g=new THREE.Vector3,e=new THREE.Vector3,h=[],i=0;h[0]=0;a||(a=100);c=this.points.length*a;g.copy(this.points[0]);for(a=1;a<c;a++)b=a/c,d=this.getPoint(b),e.copy(d),i+=e.distanceTo(g),
+g.copy(d),b*=this.points.length-1,b=Math.floor(b),b!=f&&(h[b]=i,f=b);h[h.length]=i;return{chunks:h,total:i}};this.reparametrizeByArcLength=function(a){var b,c,d,f,g,e,h=[],i=new THREE.Vector3,j=this.getLength();h.push(i.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=j.chunks[b]-j.chunks[b-1];e=Math.ceil(a*c/j.total);f=(b-1)/(this.points.length-1);g=b/(this.points.length-1);for(c=1;c<e-1;c++)d=f+c*(1/e)*(g-f),d=this.getPoint(d),h.push(i.copy(d).clone());h.push(i.copy(this.points[b]).clone())}this.points=
+h}};THREE.Camera=function(){THREE.Object3D.call(this);this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4;this.projectionMatrixInverse=new THREE.Matrix4};THREE.Camera.prototype=new THREE.Object3D;THREE.Camera.prototype.constructor=THREE.Camera;THREE.Camera.prototype.lookAt=function(a){this.matrix.lookAt(this.position,a,this.up);this.rotationAutoUpdate&&this.rotation.getRotationFromMatrix(this.matrix)};
+THREE.OrthographicCamera=function(a,b,c,d,f,g){THREE.Camera.call(this);this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==f?f:0.1;this.far=void 0!==g?g:2E3;this.updateProjectionMatrix()};THREE.OrthographicCamera.prototype=new THREE.Camera;THREE.OrthographicCamera.prototype.constructor=THREE.OrthographicCamera;THREE.OrthographicCamera.prototype.updateProjectionMatrix=function(){this.projectionMatrix=THREE.Matrix4.makeOrtho(this.left,this.right,this.top,this.bottom,this.near,this.far)};
+THREE.PerspectiveCamera=function(a,b,c,d){THREE.Camera.call(this);this.fov=void 0!==a?a:50;this.aspect=void 0!==b?b:1;this.near=void 0!==c?c:0.1;this.far=void 0!==d?d:2E3;this.updateProjectionMatrix()};THREE.PerspectiveCamera.prototype=new THREE.Camera;THREE.PerspectiveCamera.prototype.constructor=THREE.PerspectiveCamera;THREE.PerspectiveCamera.prototype.setLens=function(a,b){this.fov=2*Math.atan((void 0!==b?b:24)/(2*a))*(180/Math.PI);this.updateProjectionMatrix()};
+THREE.PerspectiveCamera.prototype.setViewOffset=function(a,b,c,d,f,g){this.fullWidth=a;this.fullHeight=b;this.x=c;this.y=d;this.width=f;this.height=g;this.updateProjectionMatrix()};
+THREE.PerspectiveCamera.prototype.updateProjectionMatrix=function(){if(this.fullWidth){var a=this.fullWidth/this.fullHeight,b=Math.tan(this.fov*Math.PI/360)*this.near,c=-b,d=a*c,a=Math.abs(a*b-d),c=Math.abs(b-c);this.projectionMatrix=THREE.Matrix4.makeFrustum(d+this.x*a/this.fullWidth,d+(this.x+this.width)*a/this.fullWidth,b-(this.y+this.height)*c/this.fullHeight,b-this.y*c/this.fullHeight,this.near,this.far)}else this.projectionMatrix=THREE.Matrix4.makePerspective(this.fov,this.aspect,this.near,
+this.far)};THREE.Light=function(a){THREE.Object3D.call(this);this.color=new THREE.Color(a)};THREE.Light.prototype=new THREE.Object3D;THREE.Light.prototype.constructor=THREE.Light;THREE.Light.prototype.supr=THREE.Object3D.prototype;THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=new THREE.Light;THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;
+THREE.DirectionalLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.onlyShadow=this.castShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraLeft=-500;this.shadowCameraTop=this.shadowCameraRight=500;this.shadowCameraBottom=-500;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowCascade=
+!1;this.shadowCascadeOffset=new THREE.Vector3(0,0,-1E3);this.shadowCascadeCount=2;this.shadowCascadeBias=[0,0,0];this.shadowCascadeWidth=[512,512,512];this.shadowCascadeHeight=[512,512,512];this.shadowCascadeNearZ=[-1,0.99,0.998];this.shadowCascadeFarZ=[0.99,0.998,1];this.shadowCascadeArray=[];this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};THREE.DirectionalLight.prototype=new THREE.Light;THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;
+THREE.PointLight=function(a,b,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,0,0);this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0};THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight;
+THREE.SpotLight=function(a,b,c,d){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.target=new THREE.Object3D;this.intensity=void 0!==b?b:1;this.distance=void 0!==c?c:0;this.castShadow=void 0!==d?d:!1;this.onlyShadow=!1;this.shadowCameraNear=50;this.shadowCameraFar=5E3;this.shadowCameraFov=50;this.shadowCameraVisible=!1;this.shadowBias=0;this.shadowDarkness=0.5;this.shadowMapHeight=this.shadowMapWidth=512;this.shadowMatrix=this.shadowCamera=this.shadowMapSize=this.shadowMap=null};
+THREE.SpotLight.prototype=new THREE.Light;THREE.SpotLight.prototype.constructor=THREE.SpotLight;
+THREE.Material=function(a){a=a||{};this.id=THREE.MaterialCount++;this.name="";this.opacity=void 0!==a.opacity?a.opacity:1;this.transparent=void 0!==a.transparent?a.transparent:!1;this.blending=void 0!==a.blending?a.blending:THREE.NormalBlending;this.depthTest=void 0!==a.depthTest?a.depthTest:!0;this.depthWrite=void 0!==a.depthWrite?a.depthWrite:!0;this.polygonOffset=void 0!==a.polygonOffset?a.polygonOffset:!1;this.polygonOffsetFactor=void 0!==a.polygonOffsetFactor?a.polygonOffsetFactor:0;this.polygonOffsetUnits=
+void 0!==a.polygonOffsetUnits?a.polygonOffsetUnits:0;this.alphaTest=void 0!==a.alphaTest?a.alphaTest:0;this.overdraw=void 0!==a.overdraw?a.overdraw:!1};THREE.MaterialCount=0;THREE.NoShading=0;THREE.FlatShading=1;THREE.SmoothShading=2;THREE.NoColors=0;THREE.FaceColors=1;THREE.VertexColors=2;THREE.NoBlending=0;THREE.NormalBlending=1;THREE.AdditiveBlending=2;THREE.SubtractiveBlending=3;THREE.MultiplyBlending=4;THREE.AdditiveAlphaBlending=5;
+THREE.LineBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.linewidth=void 0!==a.linewidth?a.linewidth:1;this.linecap=void 0!==a.linecap?a.linecap:"round";this.linejoin=void 0!==a.linejoin?a.linejoin:"round";this.vertexColors=a.vertexColors?a.vertexColors:!1;this.fog=void 0!==a.fog?a.fog:!0};THREE.LineBasicMaterial.prototype=new THREE.Material;THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial;
+THREE.MeshBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.map=void 0!==a.map?a.map:null;this.lightMap=void 0!==a.lightMap?a.lightMap:null;this.envMap=void 0!==a.envMap?a.envMap:null;this.combine=void 0!==a.combine?a.combine:THREE.MultiplyOperation;this.reflectivity=void 0!==a.reflectivity?a.reflectivity:1;this.refractionRatio=void 0!==a.refractionRatio?a.refractionRatio:0.98;this.fog=void 0!==a.fog?a.fog:
+!0;this.shading=void 0!==a.shading?a.shading:THREE.SmoothShading;this.wireframe=void 0!==a.wireframe?a.wireframe:!1;this.wireframeLinewidth=void 0!==a.wireframeLinewidth?a.wireframeLinewidth:1;this.wireframeLinecap=void 0!==a.wireframeLinecap?a.wireframeLinecap:"round";this.wireframeLinejoin=void 0!==a.wireframeLinejoin?a.wireframeLinejoin:"round";this.vertexColors=void 0!==a.vertexColors?a.vertexColors:!1;this.skinning=void 0!==a.skinning?a.skinning:!1;this.morphTargets=void 0!==a.morphTargets?a.morphTargets:
+!1};THREE.MeshBasicMaterial.prototype=new THREE.Material;THREE.MeshBasicMaterial.prototype.constructor=THREE.MeshBasicMaterial;
+THREE.MeshLambertMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.ambient=void 0!==a.ambient?new THREE.Color(a.ambient):new THREE.Color(16777215);this.wrapAround=void 0!==a.wrapAround?a.wrapAround:!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.map=void 0!==a.map?a.map:null;this.lightMap=void 0!==a.lightMap?a.lightMap:null;this.envMap=void 0!==a.envMap?a.envMap:null;this.combine=void 0!==a.combine?a.combine:
+THREE.MultiplyOperation;this.reflectivity=void 0!==a.reflectivity?a.reflectivity:1;this.refractionRatio=void 0!==a.refractionRatio?a.refractionRatio:0.98;this.fog=void 0!==a.fog?a.fog:!0;this.shading=void 0!==a.shading?a.shading:THREE.SmoothShading;this.wireframe=void 0!==a.wireframe?a.wireframe:!1;this.wireframeLinewidth=void 0!==a.wireframeLinewidth?a.wireframeLinewidth:1;this.wireframeLinecap=void 0!==a.wireframeLinecap?a.wireframeLinecap:"round";this.wireframeLinejoin=void 0!==a.wireframeLinejoin?
+a.wireframeLinejoin:"round";this.vertexColors=void 0!==a.vertexColors?a.vertexColors:!1;this.skinning=void 0!==a.skinning?a.skinning:!1;this.morphTargets=void 0!==a.morphTargets?a.morphTargets:!1;this.morphNormals=void 0!==a.morphNormals?a.morphNormals:!1};THREE.MeshLambertMaterial.prototype=new THREE.Material;THREE.MeshLambertMaterial.prototype.constructor=THREE.MeshLambertMaterial;
+THREE.MeshPhongMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.ambient=void 0!==a.ambient?new THREE.Color(a.ambient):new THREE.Color(16777215);this.specular=void 0!==a.specular?new THREE.Color(a.specular):new THREE.Color(1118481);this.shininess=void 0!==a.shininess?a.shininess:30;this.metal=void 0!==a.metal?a.metal:!1;this.perPixel=void 0!==a.perPixel?a.perPixel:!1;this.wrapAround=void 0!==a.wrapAround?a.wrapAround:
+!1;this.wrapRGB=new THREE.Vector3(1,1,1);this.map=void 0!==a.map?a.map:null;this.lightMap=void 0!==a.lightMap?a.lightMap:null;this.envMap=void 0!==a.envMap?a.envMap:null;this.combine=void 0!==a.combine?a.combine:THREE.MultiplyOperation;this.reflectivity=void 0!==a.reflectivity?a.reflectivity:1;this.refractionRatio=void 0!==a.refractionRatio?a.refractionRatio:0.98;this.fog=void 0!==a.fog?a.fog:!0;this.shading=void 0!==a.shading?a.shading:THREE.SmoothShading;this.wireframe=void 0!==a.wireframe?a.wireframe:
+!1;this.wireframeLinewidth=void 0!==a.wireframeLinewidth?a.wireframeLinewidth:1;this.wireframeLinecap=void 0!==a.wireframeLinecap?a.wireframeLinecap:"round";this.wireframeLinejoin=void 0!==a.wireframeLinejoin?a.wireframeLinejoin:"round";this.vertexColors=void 0!==a.vertexColors?a.vertexColors:!1;this.skinning=void 0!==a.skinning?a.skinning:!1;this.morphTargets=void 0!==a.morphTargets?a.morphTargets:!1;this.morphNormals=void 0!==a.morphNormals?a.morphNormals:!1};THREE.MeshPhongMaterial.prototype=new THREE.Material;
+THREE.MeshPhongMaterial.prototype.constructor=THREE.MeshPhongMaterial;THREE.MeshDepthMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.shading=void 0!==a.shading?a.shading:THREE.SmoothShading;this.wireframe=void 0!==a.wireframe?a.wireframe:!1;this.wireframeLinewidth=void 0!==a.wireframeLinewidth?a.wireframeLinewidth:1};THREE.MeshDepthMaterial.prototype=new THREE.Material;THREE.MeshDepthMaterial.prototype.constructor=THREE.MeshDepthMaterial;
+THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.shading=a.shading?a.shading:THREE.FlatShading;this.wireframe=a.wireframe?a.wireframe:!1;this.wireframeLinewidth=a.wireframeLinewidth?a.wireframeLinewidth:1};THREE.MeshNormalMaterial.prototype=new THREE.Material;THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshNormalMaterial;THREE.MeshFaceMaterial=function(){};
+THREE.ParticleBasicMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.map=void 0!==a.map?a.map:null;this.size=void 0!==a.size?a.size:1;this.sizeAttenuation=void 0!==a.sizeAttenuation?a.sizeAttenuation:!0;this.vertexColors=void 0!==a.vertexColors?a.vertexColors:!1;this.fog=void 0!==a.fog?a.fog:!0};THREE.ParticleBasicMaterial.prototype=new THREE.Material;THREE.ParticleBasicMaterial.prototype.constructor=THREE.ParticleBasicMaterial;
+THREE.ParticleCanvasMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.program=void 0!==a.program?a.program:function(){}};THREE.ParticleCanvasMaterial.prototype=new THREE.Material;THREE.ParticleCanvasMaterial.prototype.constructor=THREE.ParticleCanvasMaterial;THREE.ParticleDOMMaterial=function(a){THREE.Material.call(this);this.domElement=a};
+THREE.ShaderMaterial=function(a){THREE.Material.call(this,a);a=a||{};this.fragmentShader=void 0!==a.fragmentShader?a.fragmentShader:"void main() {}";this.vertexShader=void 0!==a.vertexShader?a.vertexShader:"void main() {}";this.uniforms=void 0!==a.uniforms?a.uniforms:{};this.attributes=a.attributes;this.shading=void 0!==a.shading?a.shading:THREE.SmoothShading;this.wireframe=void 0!==a.wireframe?a.wireframe:!1;this.wireframeLinewidth=void 0!==a.wireframeLinewidth?a.wireframeLinewidth:1;this.fog=void 0!==
+a.fog?a.fog:!1;this.lights=void 0!==a.lights?a.lights:!1;this.vertexColors=void 0!==a.vertexColors?a.vertexColors:!1;this.skinning=void 0!==a.skinning?a.skinning:!1;this.morphTargets=void 0!==a.morphTargets?a.morphTargets:!1};THREE.ShaderMaterial.prototype=new THREE.Material;THREE.ShaderMaterial.prototype.constructor=THREE.ShaderMaterial;
+THREE.Texture=function(a,b,c,d,f,g,e,h){this.id=THREE.TextureCount++;this.image=a;this.mapping=void 0!==b?b:new THREE.UVMapping;this.wrapS=void 0!==c?c:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==d?d:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==f?f:THREE.LinearFilter;this.minFilter=void 0!==g?g:THREE.LinearMipMapLinearFilter;this.format=void 0!==e?e:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=
+!0;this.needsUpdate=!1;this.onUpdate=null};THREE.Texture.prototype={constructor:THREE.Texture,clone:function(){var a=new THREE.Texture(this.image,this.mapping,this.wrapS,this.wrapT,this.magFilter,this.minFilter,this.format,this.type);a.offset.copy(this.offset);a.repeat.copy(this.repeat);return a}};THREE.TextureCount=0;THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.CubeReflectionMapping=function(){};THREE.CubeRefractionMapping=function(){};THREE.LatitudeReflectionMapping=function(){};
+THREE.LatitudeRefractionMapping=function(){};THREE.SphericalReflectionMapping=function(){};THREE.SphericalRefractionMapping=function(){};THREE.UVMapping=function(){};THREE.RepeatWrapping=0;THREE.ClampToEdgeWrapping=1;THREE.MirroredRepeatWrapping=2;THREE.NearestFilter=3;THREE.NearestMipMapNearestFilter=4;THREE.NearestMipMapLinearFilter=5;THREE.LinearFilter=6;THREE.LinearMipMapNearestFilter=7;THREE.LinearMipMapLinearFilter=8;THREE.ByteType=9;THREE.UnsignedByteType=10;THREE.ShortType=11;
+THREE.UnsignedShortType=12;THREE.IntType=13;THREE.UnsignedIntType=14;THREE.FloatType=15;THREE.AlphaFormat=16;THREE.RGBFormat=17;THREE.RGBAFormat=18;THREE.LuminanceFormat=19;THREE.LuminanceAlphaFormat=20;THREE.DataTexture=function(a,b,c,d,f,g,e,h,i,j){THREE.Texture.call(this,null,g,e,h,i,j,d,f);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=new THREE.Texture;THREE.DataTexture.prototype.constructor=THREE.DataTexture;
+THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture(this.image.data,this.image.width,this.image.height,this.format,this.type,this.mapping,this.wrapS,this.wrapT,this.magFilter,this.minFilter);a.offset.copy(this.offset);a.repeat.copy(this.repeat);return a};THREE.Particle=function(a){THREE.Object3D.call(this);this.material=a};THREE.Particle.prototype=new THREE.Object3D;THREE.Particle.prototype.constructor=THREE.Particle;
+THREE.ParticleSystem=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.ParticleBasicMaterial({color:16777215*Math.random()});this.sortParticles=!1;if(this.geometry)this.geometry.boundingSphere||this.geometry.computeBoundingSphere(),this.boundRadius=a.boundingSphere.radius;this.frustumCulled=!1};THREE.ParticleSystem.prototype=new THREE.Object3D;THREE.ParticleSystem.prototype.constructor=THREE.ParticleSystem;
+THREE.Line=function(a,b,c){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()});this.type=void 0!==c?c:THREE.LineStrip;this.geometry&&(this.geometry.boundingSphere||this.geometry.computeBoundingSphere())};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=new THREE.Object3D;THREE.Line.prototype.constructor=THREE.Line;
+THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random(),wireframe:!0});if(this.geometry&&(this.geometry.boundingSphere||this.geometry.computeBoundingSphere(),this.boundRadius=a.boundingSphere.radius,this.geometry.morphTargets.length)){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var c=0;c<this.geometry.morphTargets.length;c++)this.morphTargetInfluences.push(0),
+this.morphTargetDictionary[this.geometry.morphTargets[c].name]=c}};THREE.Mesh.prototype=new THREE.Object3D;THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.Mesh.prototype.supr=THREE.Object3D.prototype;THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.log("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};
+THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a;this.skinMatrix=new THREE.Matrix4};THREE.Bone.prototype=new THREE.Object3D;THREE.Bone.prototype.constructor=THREE.Bone;THREE.Bone.prototype.supr=THREE.Object3D.prototype;
+THREE.Bone.prototype.update=function(a,b){this.matrixAutoUpdate&&(b|=this.updateMatrix());if(b||this.matrixWorldNeedsUpdate)a?this.skinMatrix.multiply(a,this.matrix):this.skinMatrix.copy(this.matrix),this.matrixWorldNeedsUpdate=!1,b=!0;var c,d=this.children.length;for(c=0;c<d;c++)this.children[c].update(this.skinMatrix,b)};
+THREE.SkinnedMesh=function(a,b){THREE.Mesh.call(this,a,b);this.identityMatrix=new THREE.Matrix4;this.bones=[];this.boneMatrices=[];var c,d,f,g,e,h;if(void 0!==this.geometry.bones){for(c=0;c<this.geometry.bones.length;c++)f=this.geometry.bones[c],g=f.pos,e=f.rotq,h=f.scl,d=this.addBone(),d.name=f.name,d.position.set(g[0],g[1],g[2]),d.quaternion.set(e[0],e[1],e[2],e[3]),d.useQuaternion=!0,void 0!==h?d.scale.set(h[0],h[1],h[2]):d.scale.set(1,1,1);for(c=0;c<this.bones.length;c++)f=this.geometry.bones[c],
+d=this.bones[c],-1===f.parent?this.add(d):this.bones[f.parent].add(d);this.boneMatrices=new Float32Array(16*this.bones.length);this.pose()}};THREE.SkinnedMesh.prototype=new THREE.Mesh;THREE.SkinnedMesh.prototype.constructor=THREE.SkinnedMesh;THREE.SkinnedMesh.prototype.addBone=function(a){void 0===a&&(a=new THREE.Bone(this));this.bones.push(a);return a};
+THREE.SkinnedMesh.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=!1;for(var a=0,b=this.children.length;a<b;a++){var c=this.children[a];c instanceof THREE.Bone?c.update(this.identityMatrix,!1):c.updateMatrixWorld(!0)}for(var b=this.bones.length,c=this.bones,d=this.boneMatrices,a=0;a<b;a++)c[a].skinMatrix.flattenToArrayOffset(d,
+16*a)};
+THREE.SkinnedMesh.prototype.pose=function(){this.updateMatrixWorld(!0);for(var a,b=[],c=0;c<this.bones.length;c++){a=this.bones[c];var d=new THREE.Matrix4;d.getInverse(a.skinMatrix);b.push(d);a.skinMatrix.flattenToArrayOffset(this.boneMatrices,16*c)}if(void 0===this.geometry.skinVerticesA){this.geometry.skinVerticesA=[];this.geometry.skinVerticesB=[];for(a=0;a<this.geometry.skinIndices.length;a++){var c=this.geometry.vertices[a].position,f=this.geometry.skinIndices[a].x,g=this.geometry.skinIndices[a].y,d=
+new THREE.Vector3(c.x,c.y,c.z);this.geometry.skinVerticesA.push(b[f].multiplyVector3(d));d=new THREE.Vector3(c.x,c.y,c.z);this.geometry.skinVerticesB.push(b[g].multiplyVector3(d));1!==this.geometry.skinWeights[a].x+this.geometry.skinWeights[a].y&&(c=0.5*(1-(this.geometry.skinWeights[a].x+this.geometry.skinWeights[a].y)),this.geometry.skinWeights[a].x+=c,this.geometry.skinWeights[a].y+=c)}}};
+THREE.MorphAnimMesh=function(a,b){THREE.Mesh.call(this,a,b);this.duration=1E3;this.mirroredLoop=!1;this.currentKeyframe=this.lastKeyframe=this.time=0;this.direction=1;this.directionBackwards=!1;this.setFrameRange(0,this.geometry.morphTargets.length-1)};THREE.MorphAnimMesh.prototype=new THREE.Mesh;THREE.MorphAnimMesh.prototype.constructor=THREE.MorphAnimMesh;
+THREE.MorphAnimMesh.prototype.setFrameRange=function(a,b){this.startKeyframe=a;this.endKeyframe=b;this.length=this.endKeyframe-this.startKeyframe+1};THREE.MorphAnimMesh.prototype.setDirectionForward=function(){this.direction=1;this.directionBackwards=!1};THREE.MorphAnimMesh.prototype.setDirectionBackward=function(){this.direction=-1;this.directionBackwards=!0};
+THREE.MorphAnimMesh.prototype.parseAnimations=function(){var a=this.geometry;if(!a.animations)a.animations={};for(var b,c=a.animations,d=/([a-z]+)(\d+)/,f=0,g=a.morphTargets.length;f<g;f++){var e=a.morphTargets[f].name.match(d);if(e&&1<e.length){e=e[1];c[e]||(c[e]={start:Infinity,end:-Infinity});var h=c[e];if(f<h.start)h.start=f;if(f>h.end)h.end=f;b||(b=e)}}a.firstAnimation=b};
+THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){if(!this.geometry.animations)this.geometry.animations={};this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")};
+THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time){this.direction*=-1;if(this.time>this.duration)this.time=this.duration,this.directionBackwards=!0;if(0>this.time)this.time=0,this.directionBackwards=!1}}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);if(a!==this.currentKeyframe)this.morphTargetInfluences[this.lastKeyframe]=
+0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a;b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b};THREE.Ribbon=function(a,b){THREE.Object3D.call(this);this.geometry=a;this.material=b};THREE.Ribbon.prototype=new THREE.Object3D;THREE.Ribbon.prototype.constructor=THREE.Ribbon;
+THREE.LOD=function(){THREE.Object3D.call(this);this.LODs=[]};THREE.LOD.prototype=new THREE.Object3D;THREE.LOD.prototype.constructor=THREE.LOD;THREE.LOD.prototype.supr=THREE.Object3D.prototype;THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c<this.LODs.length&&!(b<this.LODs[c].visibleAtDistance);c++);this.LODs.splice(c,0,{visibleAtDistance:b,object3D:a});this.add(a)};
+THREE.LOD.prototype.update=function(a){if(1<this.LODs.length){a.matrixWorldInverse.getInverse(a.matrixWorld);a=a.matrixWorldInverse;a=-(a.n31*this.matrixWorld.n14+a.n32*this.matrixWorld.n24+a.n33*this.matrixWorld.n34+a.n34);this.LODs[0].object3D.visible=!0;for(var b=1;b<this.LODs.length;b++)if(a>=this.LODs[b].visibleAtDistance)this.LODs[b-1].object3D.visible=!1,this.LODs[b].object3D.visible=!0;else break;for(;b<this.LODs.length;b++)this.LODs[b].object3D.visible=!1}};
+THREE.Sprite=function(a){THREE.Object3D.call(this);this.color=void 0!==a.color?new THREE.Color(a.color):new THREE.Color(16777215);this.map=void 0!==a.map?a.map:new THREE.Texture;this.blending=void 0!==a.blending?a.blending:THREE.NormalBlending;this.useScreenCoordinates=void 0!==a.useScreenCoordinates?a.useScreenCoordinates:!0;this.mergeWith3D=void 0!==a.mergeWith3D?a.mergeWith3D:!this.useScreenCoordinates;this.affectedByDistance=void 0!==a.affectedByDistance?a.affectedByDistance:!this.useScreenCoordinates;
+this.scaleByViewport=void 0!==a.scaleByViewport?a.scaleByViewport:!this.affectedByDistance;this.alignment=a.alignment instanceof THREE.Vector2?a.alignment:THREE.SpriteAlignment.center;this.rotation3d=this.rotation;this.rotation=0;this.opacity=1;this.uvOffset=new THREE.Vector2(0,0);this.uvScale=new THREE.Vector2(1,1)};THREE.Sprite.prototype=new THREE.Object3D;THREE.Sprite.prototype.constructor=THREE.Sprite;
+THREE.Sprite.prototype.updateMatrix=function(){this.matrix.setPosition(this.position);this.rotation3d.set(0,0,this.rotation);this.matrix.setRotationFromEuler(this.rotation3d);if(1!==this.scale.x||1!==this.scale.y)this.matrix.scale(this.scale),this.boundRadiusScale=Math.max(this.scale.x,this.scale.y);this.matrixWorldNeedsUpdate=!0};THREE.SpriteAlignment={};THREE.SpriteAlignment.topLeft=new THREE.Vector2(1,-1);THREE.SpriteAlignment.topCenter=new THREE.Vector2(0,-1);
+THREE.SpriteAlignment.topRight=new THREE.Vector2(-1,-1);THREE.SpriteAlignment.centerLeft=new THREE.Vector2(1,0);THREE.SpriteAlignment.center=new THREE.Vector2(0,0);THREE.SpriteAlignment.centerRight=new THREE.Vector2(-1,0);THREE.SpriteAlignment.bottomLeft=new THREE.Vector2(1,1);THREE.SpriteAlignment.bottomCenter=new THREE.Vector2(0,1);THREE.SpriteAlignment.bottomRight=new THREE.Vector2(-1,1);
+THREE.Scene=function(){THREE.Object3D.call(this);this.overrideMaterial=this.fog=null;this.matrixAutoUpdate=!1;this.__objects=[];this.__lights=[];this.__objectsAdded=[];this.__objectsRemoved=[]};THREE.Scene.prototype=new THREE.Object3D;THREE.Scene.prototype.constructor=THREE.Scene;
+THREE.Scene.prototype.__addObject=function(a){if(a instanceof THREE.Light)-1===this.__lights.indexOf(a)&&this.__lights.push(a);else if(!(a instanceof THREE.Camera||a instanceof THREE.Bone)&&-1===this.__objects.indexOf(a)){this.__objects.push(a);this.__objectsAdded.push(a);var b=this.__objectsRemoved.indexOf(a);-1!==b&&this.__objectsRemoved.splice(b,1)}for(b=0;b<a.children.length;b++)this.__addObject(a.children[b])};
+THREE.Scene.prototype.__removeObject=function(a){if(a instanceof THREE.Light){var b=this.__lights.indexOf(a);-1!==b&&this.__lights.splice(b,1)}else a instanceof THREE.Camera||(b=this.__objects.indexOf(a),-1!==b&&(this.__objects.splice(b,1),this.__objectsRemoved.push(a),b=this.__objectsAdded.indexOf(a),-1!==b&&this.__objectsAdded.splice(b,1)));for(b=0;b<a.children.length;b++)this.__removeObject(a.children[b])};
+THREE.Fog=function(a,b,c){this.color=new THREE.Color(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3};THREE.FogExp2=function(a,b){this.color=new THREE.Color(a);this.density=void 0!==b?b:2.5E-4};
+THREE.DOMRenderer=function(){var a,b,c=new THREE.Projector,d,f,g,e;this.domElement=document.createElement("div");this.setSize=function(a,b){d=a;f=b;g=d/2;e=f/2};this.render=function(d,f){var j,k,q,m,o;a=c.projectScene(d,f);b=a.elements;for(j=0,k=b.length;j<k;j++)if(q=b[j],q instanceof THREE.RenderableParticle&&(m=q.x*g+g,o=q.y*e+e,q=q.material,q instanceof THREE.ParticleDOMMaterial))q=q.domElement,q.style.left=m+"px",q.style.top=o+"px"}};
+THREE.CanvasRenderer=function(a){function b(a){if(t!=a)n.globalAlpha=t=a}function c(a){if(w!=a){switch(a){case THREE.NormalBlending:n.globalCompositeOperation="source-over";break;case THREE.AdditiveBlending:n.globalCompositeOperation="lighter";break;case THREE.SubtractiveBlending:n.globalCompositeOperation="darker"}w=a}}function d(a){if(u!=a)n.strokeStyle=u=a}function f(a){if(v!=a)n.fillStyle=v=a}var a=a||{},g=this,e,h,i,j=new THREE.Projector,k=void 0!==a.canvas?a.canvas:document.createElement("canvas"),
+q,m,o,p,n=k.getContext("2d"),r=new THREE.Color(0),s=0,t=1,w=0,u=null,v=null,A=null,F=null,B=null,D,H,I,Q,P=new THREE.RenderableVertex,L=new THREE.RenderableVertex,K,O,y,l,$,C,E,S,R,ca,ka,ia,N=new THREE.Color,aa=new THREE.Color,U=new THREE.Color,ba=new THREE.Color,ea=new THREE.Color,Ta=[],Ja=[],Ka,Ga,qa,ha,ib,db,lb,cb,Za,Sa,La=new THREE.Rectangle,sa=new THREE.Rectangle,za=new THREE.Rectangle,Ea=!1,Fa=new THREE.Color,Wa=new THREE.Color,mb=new THREE.Color,Z=new THREE.Vector3,T,Fb,Uc,eb,pc,Cc,a=16;T=
+document.createElement("canvas");T.width=T.height=2;Fb=T.getContext("2d");Fb.fillStyle="rgba(0,0,0,1)";Fb.fillRect(0,0,2,2);Uc=Fb.getImageData(0,0,2,2);eb=Uc.data;pc=document.createElement("canvas");pc.width=pc.height=a;Cc=pc.getContext("2d");Cc.translate(-a/2,-a/2);Cc.scale(a,a);a--;this.domElement=k;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,faces:0}};this.setSize=function(a,b){q=a;m=b;o=Math.floor(q/2);p=Math.floor(m/2);k.width=q;k.height=m;La.set(-o,-p,
+o,p);sa.set(-o,-p,o,p);t=1;w=0;B=F=A=v=u=null};this.setClearColor=function(a,b){r.copy(a);s=b;sa.set(-o,-p,o,p)};this.setClearColorHex=function(a,b){r.setHex(a);s=b;sa.set(-o,-p,o,p)};this.clear=function(){n.setTransform(1,0,0,-1,o,p);sa.isEmpty()||(sa.minSelf(La),sa.inflate(2),1>s&&n.clearRect(Math.floor(sa.getX()),Math.floor(sa.getY()),Math.floor(sa.getWidth()),Math.floor(sa.getHeight())),0<s&&(c(THREE.NormalBlending),b(1),f("rgba("+Math.floor(255*r.r)+","+Math.floor(255*r.g)+","+Math.floor(255*
+r.b)+","+s+")"),n.fillRect(Math.floor(sa.getX()),Math.floor(sa.getY()),Math.floor(sa.getWidth()),Math.floor(sa.getHeight()))),sa.empty())};this.render=function(a,k){function m(a){var b,c,d,f;Fa.setRGB(0,0,0);Wa.setRGB(0,0,0);mb.setRGB(0,0,0);for(b=0,c=a.length;b<c;b++)d=a[b],f=d.color,d instanceof THREE.AmbientLight?(Fa.r+=f.r,Fa.g+=f.g,Fa.b+=f.b):d instanceof THREE.DirectionalLight?(Wa.r+=f.r,Wa.g+=f.g,Wa.b+=f.b):d instanceof THREE.PointLight&&(mb.r+=f.r,mb.g+=f.g,mb.b+=f.b)}function q(a,b,c,d){var f,
+g,e,h,l,i;for(f=0,g=a.length;f<g;f++)e=a[f],h=e.color,e instanceof THREE.DirectionalLight?(l=e.matrixWorld.getPosition(),i=c.dot(l),0>=i||(i*=e.intensity,d.r+=h.r*i,d.g+=h.g*i,d.b+=h.b*i)):e instanceof THREE.PointLight&&(l=e.matrixWorld.getPosition(),i=c.dot(Z.sub(l,b).normalize()),0>=i||(i*=0==e.distance?1:1-Math.min(b.distanceTo(l)/e.distance,1),0!=i&&(i*=e.intensity,d.r+=h.r*i,d.g+=h.g*i,d.b+=h.b*i)))}function r(a,g,e){b(e.opacity);c(e.blending);var Z,h,l,i,k,j;if(e instanceof THREE.ParticleBasicMaterial){if(e.map)i=
+e.map.image,k=i.width>>1,j=i.height>>1,e=g.scale.x*o,l=g.scale.y*p,Z=e*k,h=l*j,za.set(a.x-Z,a.y-h,a.x+Z,a.y+h),La.intersects(za)&&(n.save(),n.translate(a.x,a.y),n.rotate(-g.rotation),n.scale(e,-l),n.translate(-k,-j),n.drawImage(i,0,0),n.restore())}else e instanceof THREE.ParticleCanvasMaterial&&(Z=g.scale.x*o,h=g.scale.y*p,za.set(a.x-Z,a.y-h,a.x+Z,a.y+h),La.intersects(za)&&(d(e.color.getContextStyle()),f(e.color.getContextStyle()),n.save(),n.translate(a.x,a.y),n.rotate(-g.rotation),n.scale(Z,h),e.program(n),
+n.restore()))}function s(a,f,g,e){b(e.opacity);c(e.blending);n.beginPath();n.moveTo(a.positionScreen.x,a.positionScreen.y);n.lineTo(f.positionScreen.x,f.positionScreen.y);n.closePath();if(e instanceof THREE.LineBasicMaterial){a=e.linewidth;if(A!=a)n.lineWidth=A=a;a=e.linecap;if(F!=a)n.lineCap=F=a;a=e.linejoin;if(B!=a)n.lineJoin=B=a;d(e.color.getContextStyle());n.stroke();za.inflate(2*e.linewidth)}}function t(a,d,f,e,h,j,n,T){g.info.render.vertices+=3;g.info.render.faces++;b(T.opacity);c(T.blending);
+K=a.positionScreen.x;O=a.positionScreen.y;y=d.positionScreen.x;l=d.positionScreen.y;$=f.positionScreen.x;C=f.positionScreen.y;v(K,O,y,l,$,C);if(T instanceof THREE.MeshBasicMaterial)if(T.map)T.map.mapping instanceof THREE.UVMapping&&(ha=n.uvs[0],Vc(K,O,y,l,$,C,ha[e].u,ha[e].v,ha[h].u,ha[h].v,ha[j].u,ha[j].v,T.map));else if(T.envMap){if(T.envMap.mapping instanceof THREE.SphericalReflectionMapping)a=k.matrixWorldInverse,Z.copy(n.vertexNormalsWorld[e]),ib=0.5*(Z.x*a.n11+Z.y*a.n12+Z.z*a.n13)+0.5,db=0.5*
+-(Z.x*a.n21+Z.y*a.n22+Z.z*a.n23)+0.5,Z.copy(n.vertexNormalsWorld[h]),lb=0.5*(Z.x*a.n11+Z.y*a.n12+Z.z*a.n13)+0.5,cb=0.5*-(Z.x*a.n21+Z.y*a.n22+Z.z*a.n23)+0.5,Z.copy(n.vertexNormalsWorld[j]),Za=0.5*(Z.x*a.n11+Z.y*a.n12+Z.z*a.n13)+0.5,Sa=0.5*-(Z.x*a.n21+Z.y*a.n22+Z.z*a.n23)+0.5,Vc(K,O,y,l,$,C,ib,db,lb,cb,Za,Sa,T.envMap)}else T.wireframe?Mb(T.color,T.wireframeLinewidth,T.wireframeLinecap,T.wireframeLinejoin):Gb(T.color);else if(T instanceof THREE.MeshLambertMaterial)T.map&&!T.wireframe&&(T.map.mapping instanceof
+THREE.UVMapping&&(ha=n.uvs[0],Vc(K,O,y,l,$,C,ha[e].u,ha[e].v,ha[h].u,ha[h].v,ha[j].u,ha[j].v,T.map)),c(THREE.SubtractiveBlending)),Ea?!T.wireframe&&T.shading==THREE.SmoothShading&&3==n.vertexNormalsWorld.length?(aa.r=U.r=ba.r=Fa.r,aa.g=U.g=ba.g=Fa.g,aa.b=U.b=ba.b=Fa.b,q(i,n.v1.positionWorld,n.vertexNormalsWorld[0],aa),q(i,n.v2.positionWorld,n.vertexNormalsWorld[1],U),q(i,n.v3.positionWorld,n.vertexNormalsWorld[2],ba),aa.r=Math.max(0,Math.min(T.color.r*aa.r,1)),aa.g=Math.max(0,Math.min(T.color.g*aa.g,
+1)),aa.b=Math.max(0,Math.min(T.color.b*aa.b,1)),U.r=Math.max(0,Math.min(T.color.r*U.r,1)),U.g=Math.max(0,Math.min(T.color.g*U.g,1)),U.b=Math.max(0,Math.min(T.color.b*U.b,1)),ba.r=Math.max(0,Math.min(T.color.r*ba.r,1)),ba.g=Math.max(0,Math.min(T.color.g*ba.g,1)),ba.b=Math.max(0,Math.min(T.color.b*ba.b,1)),ea.r=0.5*(U.r+ba.r),ea.g=0.5*(U.g+ba.g),ea.b=0.5*(U.b+ba.b),qa=Dc(aa,U,ba,ea),gc(K,O,y,l,$,C,0,0,1,0,0,1,qa)):(N.r=Fa.r,N.g=Fa.g,N.b=Fa.b,q(i,n.centroidWorld,n.normalWorld,N),N.r=Math.max(0,Math.min(T.color.r*
+N.r,1)),N.g=Math.max(0,Math.min(T.color.g*N.g,1)),N.b=Math.max(0,Math.min(T.color.b*N.b,1)),T.wireframe?Mb(N,T.wireframeLinewidth,T.wireframeLinecap,T.wireframeLinejoin):Gb(N)):T.wireframe?Mb(T.color,T.wireframeLinewidth,T.wireframeLinecap,T.wireframeLinejoin):Gb(T.color);else if(T instanceof THREE.MeshDepthMaterial)Ka=k.near,Ga=k.far,aa.r=aa.g=aa.b=1-ac(a.positionScreen.z,Ka,Ga),U.r=U.g=U.b=1-ac(d.positionScreen.z,Ka,Ga),ba.r=ba.g=ba.b=1-ac(f.positionScreen.z,Ka,Ga),ea.r=0.5*(U.r+ba.r),ea.g=0.5*
+(U.g+ba.g),ea.b=0.5*(U.b+ba.b),qa=Dc(aa,U,ba,ea),gc(K,O,y,l,$,C,0,0,1,0,0,1,qa);else if(T instanceof THREE.MeshNormalMaterial)N.r=hc(n.normalWorld.x),N.g=hc(n.normalWorld.y),N.b=hc(n.normalWorld.z),T.wireframe?Mb(N,T.wireframeLinewidth,T.wireframeLinecap,T.wireframeLinejoin):Gb(N)}function u(a,d,f,e,Z,h,T,j,n){g.info.render.vertices+=4;g.info.render.faces++;b(j.opacity);c(j.blending);if(j.map||j.envMap)t(a,d,e,0,1,3,T,j,n),t(Z,f,h,1,2,3,T,j,n);else if(K=a.positionScreen.x,O=a.positionScreen.y,y=d.positionScreen.x,
+l=d.positionScreen.y,$=f.positionScreen.x,C=f.positionScreen.y,E=e.positionScreen.x,S=e.positionScreen.y,R=Z.positionScreen.x,ca=Z.positionScreen.y,ka=h.positionScreen.x,ia=h.positionScreen.y,j instanceof THREE.MeshBasicMaterial)w(K,O,y,l,$,C,E,S),j.wireframe?Mb(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):Gb(j.color);else if(j instanceof THREE.MeshLambertMaterial)Ea?!j.wireframe&&j.shading==THREE.SmoothShading&&4==T.vertexNormalsWorld.length?(aa.r=U.r=ba.r=ea.r=Fa.r,aa.g=
+U.g=ba.g=ea.g=Fa.g,aa.b=U.b=ba.b=ea.b=Fa.b,q(i,T.v1.positionWorld,T.vertexNormalsWorld[0],aa),q(i,T.v2.positionWorld,T.vertexNormalsWorld[1],U),q(i,T.v4.positionWorld,T.vertexNormalsWorld[3],ba),q(i,T.v3.positionWorld,T.vertexNormalsWorld[2],ea),aa.r=Math.max(0,Math.min(j.color.r*aa.r,1)),aa.g=Math.max(0,Math.min(j.color.g*aa.g,1)),aa.b=Math.max(0,Math.min(j.color.b*aa.b,1)),U.r=Math.max(0,Math.min(j.color.r*U.r,1)),U.g=Math.max(0,Math.min(j.color.g*U.g,1)),U.b=Math.max(0,Math.min(j.color.b*U.b,1)),
+ba.r=Math.max(0,Math.min(j.color.r*ba.r,1)),ba.g=Math.max(0,Math.min(j.color.g*ba.g,1)),ba.b=Math.max(0,Math.min(j.color.b*ba.b,1)),ea.r=Math.max(0,Math.min(j.color.r*ea.r,1)),ea.g=Math.max(0,Math.min(j.color.g*ea.g,1)),ea.b=Math.max(0,Math.min(j.color.b*ea.b,1)),qa=Dc(aa,U,ba,ea),v(K,O,y,l,E,S),gc(K,O,y,l,E,S,0,0,1,0,0,1,qa),v(R,ca,$,C,ka,ia),gc(R,ca,$,C,ka,ia,1,0,1,1,0,1,qa)):(N.r=Fa.r,N.g=Fa.g,N.b=Fa.b,q(i,T.centroidWorld,T.normalWorld,N),N.r=Math.max(0,Math.min(j.color.r*N.r,1)),N.g=Math.max(0,
+Math.min(j.color.g*N.g,1)),N.b=Math.max(0,Math.min(j.color.b*N.b,1)),w(K,O,y,l,$,C,E,S),j.wireframe?Mb(N,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):Gb(N)):(w(K,O,y,l,$,C,E,S),j.wireframe?Mb(j.color,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):Gb(j.color));else if(j instanceof THREE.MeshNormalMaterial)N.r=hc(T.normalWorld.x),N.g=hc(T.normalWorld.y),N.b=hc(T.normalWorld.z),w(K,O,y,l,$,C,E,S),j.wireframe?Mb(N,j.wireframeLinewidth,j.wireframeLinecap,j.wireframeLinejoin):
+Gb(N);else if(j instanceof THREE.MeshDepthMaterial)Ka=k.near,Ga=k.far,aa.r=aa.g=aa.b=1-ac(a.positionScreen.z,Ka,Ga),U.r=U.g=U.b=1-ac(d.positionScreen.z,Ka,Ga),ba.r=ba.g=ba.b=1-ac(e.positionScreen.z,Ka,Ga),ea.r=ea.g=ea.b=1-ac(f.positionScreen.z,Ka,Ga),qa=Dc(aa,U,ba,ea),v(K,O,y,l,E,S),gc(K,O,y,l,E,S,0,0,1,0,0,1,qa),v(R,ca,$,C,ka,ia),gc(R,ca,$,C,ka,ia,1,0,1,1,0,1,qa)}function v(a,b,c,d,f,e){n.beginPath();n.moveTo(a,b);n.lineTo(c,d);n.lineTo(f,e);n.lineTo(a,b);n.closePath()}function w(a,b,c,d,f,e,g,Z){n.beginPath();
+n.moveTo(a,b);n.lineTo(c,d);n.lineTo(f,e);n.lineTo(g,Z);n.lineTo(a,b);n.closePath()}function Mb(a,b,c,f){if(A!=b)n.lineWidth=A=b;if(F!=c)n.lineCap=F=c;if(B!=f)n.lineJoin=B=f;d(a.getContextStyle());n.stroke();za.inflate(2*b)}function Gb(a){f(a.getContextStyle());n.fill()}function Vc(a,b,c,d,e,g,Z,h,l,i,j,T,k){if(0!=k.image.width){if(!0==k.needsUpdate||void 0==Ta[k.id]){var m=k.wrapS==THREE.RepeatWrapping,o=k.wrapT==THREE.RepeatWrapping;Ta[k.id]=n.createPattern(k.image,m&&o?"repeat":m&&!o?"repeat-x":
+!m&&o?"repeat-y":"no-repeat");k.needsUpdate=!1}f(Ta[k.id]);var m=k.offset.x/k.repeat.x,o=k.offset.y/k.repeat.y,p=k.image.width*k.repeat.x,Fb=k.image.height*k.repeat.y,Z=(Z+m)*p,h=(h+o)*Fb,c=c-a,d=d-b,e=e-a,g=g-b,l=(l+m)*p-Z,i=(i+o)*Fb-h,j=(j+m)*p-Z,T=(T+o)*Fb-h,m=l*T-j*i;if(0==m){if(void 0===Ja[k.id])b=document.createElement("canvas"),b.width=k.image.width,b.height=k.image.height,b=b.getContext("2d"),b.drawImage(k.image,0,0),Ja[k.id]=b.getImageData(0,0,k.image.width,k.image.height).data;b=Ja[k.id];
+Z=4*(Math.floor(Z)+Math.floor(h)*k.image.width);N.setRGB(b[Z]/255,b[Z+1]/255,b[Z+2]/255);Gb(N)}else m=1/m,k=(T*c-i*e)*m,i=(T*d-i*g)*m,c=(l*e-j*c)*m,d=(l*g-j*d)*m,a=a-k*Z-c*h,Z=b-i*Z-d*h,n.save(),n.transform(k,i,c,d,a,Z),n.fill(),n.restore()}}function gc(a,b,c,d,f,e,g,Z,h,l,i,j,T){var k,m;k=T.width-1;m=T.height-1;g*=k;Z*=m;c-=a;d-=b;f-=a;e-=b;h=h*k-g;l=l*m-Z;i=i*k-g;j=j*m-Z;m=1/(h*j-i*l);k=(j*c-l*f)*m;l=(j*d-l*e)*m;c=(h*f-i*c)*m;d=(h*e-i*d)*m;a=a-k*g-c*Z;b=b-l*g-d*Z;n.save();n.transform(k,l,c,d,a,
+b);n.clip();n.drawImage(T,0,0);n.restore()}function Dc(a,b,c,d){var f=~~(255*a.r),e=~~(255*a.g),a=~~(255*a.b),g=~~(255*b.r),Z=~~(255*b.g),b=~~(255*b.b),h=~~(255*c.r),l=~~(255*c.g),c=~~(255*c.b),i=~~(255*d.r),j=~~(255*d.g),d=~~(255*d.b);eb[0]=0>f?0:255<f?255:f;eb[1]=0>e?0:255<e?255:e;eb[2]=0>a?0:255<a?255:a;eb[4]=0>g?0:255<g?255:g;eb[5]=0>Z?0:255<Z?255:Z;eb[6]=0>b?0:255<b?255:b;eb[8]=0>h?0:255<h?255:h;eb[9]=0>l?0:255<l?255:l;eb[10]=0>c?0:255<c?255:c;eb[12]=0>i?0:255<i?255:i;eb[13]=0>j?0:255<j?255:
+j;eb[14]=0>d?0:255<d?255:d;Fb.putImageData(Uc,0,0);Cc.drawImage(T,0,0);return pc}function ac(a,b,c){a=(a-b)/(c-b);return a*a*(3-2*a)}function hc(a){a=0.5*(a+1);return 0>a?0:1<a?1:a}function Nb(a,b){var c=b.x-a.x,d=b.y-a.y,f=c*c+d*d;0!=f&&(f=1/Math.sqrt(f),c*=f,d*=f,b.x+=c,b.y+=d,a.x-=c,a.y-=d)}var Ec,fd,Pa,jb;this.autoClear?this.clear():n.setTransform(1,0,0,-1,o,p);g.info.render.vertices=0;g.info.render.faces=0;e=j.projectScene(a,k,this.sortElements);h=e.elements;i=e.lights;(Ea=0<i.length)&&m(i);
+for(Ec=0,fd=h.length;Ec<fd;Ec++)if(Pa=h[Ec],jb=Pa.material,jb=jb instanceof THREE.MeshFaceMaterial?Pa.faceMaterial:jb,!(null==jb||0==jb.opacity)){za.empty();if(Pa instanceof THREE.RenderableParticle)D=Pa,D.x*=o,D.y*=p,r(D,Pa,jb,a);else if(Pa instanceof THREE.RenderableLine)D=Pa.v1,H=Pa.v2,D.positionScreen.x*=o,D.positionScreen.y*=p,H.positionScreen.x*=o,H.positionScreen.y*=p,za.addPoint(D.positionScreen.x,D.positionScreen.y),za.addPoint(H.positionScreen.x,H.positionScreen.y),La.intersects(za)&&s(D,
+H,Pa,jb,a);else if(Pa instanceof THREE.RenderableFace3)D=Pa.v1,H=Pa.v2,I=Pa.v3,D.positionScreen.x*=o,D.positionScreen.y*=p,H.positionScreen.x*=o,H.positionScreen.y*=p,I.positionScreen.x*=o,I.positionScreen.y*=p,jb.overdraw&&(Nb(D.positionScreen,H.positionScreen),Nb(H.positionScreen,I.positionScreen),Nb(I.positionScreen,D.positionScreen)),za.add3Points(D.positionScreen.x,D.positionScreen.y,H.positionScreen.x,H.positionScreen.y,I.positionScreen.x,I.positionScreen.y),La.intersects(za)&&t(D,H,I,0,1,2,
+Pa,jb,a);else if(Pa instanceof THREE.RenderableFace4)D=Pa.v1,H=Pa.v2,I=Pa.v3,Q=Pa.v4,D.positionScreen.x*=o,D.positionScreen.y*=p,H.positionScreen.x*=o,H.positionScreen.y*=p,I.positionScreen.x*=o,I.positionScreen.y*=p,Q.positionScreen.x*=o,Q.positionScreen.y*=p,P.positionScreen.copy(H.positionScreen),L.positionScreen.copy(Q.positionScreen),jb.overdraw&&(Nb(D.positionScreen,H.positionScreen),Nb(H.positionScreen,Q.positionScreen),Nb(Q.positionScreen,D.positionScreen),Nb(I.positionScreen,P.positionScreen),
+Nb(I.positionScreen,L.positionScreen)),za.addPoint(D.positionScreen.x,D.positionScreen.y),za.addPoint(H.positionScreen.x,H.positionScreen.y),za.addPoint(I.positionScreen.x,I.positionScreen.y),za.addPoint(Q.positionScreen.x,Q.positionScreen.y),La.intersects(za)&&u(D,H,I,Q,P,L,Pa,jb,a);sa.addRectangle(za)}n.setTransform(1,0,0,1,0,0)}};
+THREE.SVGRenderer=function(){function a(a,b,c,d){var f,e,g,h,i,j;for(f=0,e=a.length;f<e;f++)g=a[f],h=g.color,g instanceof THREE.DirectionalLight?(i=g.matrixWorld.getPosition(),j=c.dot(i),0>=j||(j*=g.intensity,d.r+=h.r*j,d.g+=h.g*j,d.b+=h.b*j)):g instanceof THREE.PointLight&&(i=g.matrixWorld.getPosition(),j=c.dot(D.sub(i,b).normalize()),0>=j||(j*=0==g.distance?1:1-Math.min(b.distanceTo(i)/g.distance,1),0!=j&&(j*=g.intensity,d.r+=h.r*j,d.g+=h.g*j,d.b+=h.b*j)))}function b(a){null==H[a]&&(H[a]=document.createElementNS("http://www.w3.org/2000/svg",
+"path"),0==K&&H[a].setAttribute("shape-rendering","crispEdges"));return H[a]}function c(a){a=0.5*(a+1);return 0>a?0:1<a?1:a}var d=this,f,g,e,h=new THREE.Projector,i=document.createElementNS("http://www.w3.org/2000/svg","svg"),j,k,q,m,o,p,n,r,s=new THREE.Rectangle,t=new THREE.Rectangle,w=!1,u=new THREE.Color,v=new THREE.Color,A=new THREE.Color,F=new THREE.Color,B,D=new THREE.Vector3,H=[],I=[],Q,P,L,K=1;this.domElement=i;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,
+faces:0}};this.setQuality=function(a){switch(a){case "high":K=1;break;case "low":K=0}};this.setSize=function(a,b){j=a;k=b;q=j/2;m=k/2;i.setAttribute("viewBox",-q+" "+-m+" "+j+" "+k);i.setAttribute("width",j);i.setAttribute("height",k);s.set(-q,-m,q,m)};this.clear=function(){for(;0<i.childNodes.length;)i.removeChild(i.childNodes[0])};this.render=function(j,k){var l,D,C,E;this.autoClear&&this.clear();d.info.render.vertices=0;d.info.render.faces=0;f=h.projectScene(j,k,this.sortElements);g=f.elements;
+e=f.lights;L=P=0;if(w=0<e.length){v.setRGB(0,0,0);A.setRGB(0,0,0);F.setRGB(0,0,0);for(l=0,D=e.length;l<D;l++)E=e[l],C=E.color,E instanceof THREE.AmbientLight?(v.r+=C.r,v.g+=C.g,v.b+=C.b):E instanceof THREE.DirectionalLight?(A.r+=C.r,A.g+=C.g,A.b+=C.b):E instanceof THREE.PointLight&&(F.r+=C.r,F.g+=C.g,F.b+=C.b)}for(l=0,D=g.length;l<D;l++)if(C=g[l],E=C.material,E=E instanceof THREE.MeshFaceMaterial?C.faceMaterial:E,!(null==E||0==E.opacity))if(t.empty(),C instanceof THREE.RenderableParticle)o=C,o.x*=
+q,o.y*=-m;else if(C instanceof THREE.RenderableLine){if(o=C.v1,p=C.v2,o.positionScreen.x*=q,o.positionScreen.y*=-m,p.positionScreen.x*=q,p.positionScreen.y*=-m,t.addPoint(o.positionScreen.x,o.positionScreen.y),t.addPoint(p.positionScreen.x,p.positionScreen.y),s.intersects(t)){C=o;var S=p,R=L++;null==I[R]&&(I[R]=document.createElementNS("http://www.w3.org/2000/svg","line"),0==K&&I[R].setAttribute("shape-rendering","crispEdges"));Q=I[R];Q.setAttribute("x1",C.positionScreen.x);Q.setAttribute("y1",C.positionScreen.y);
+Q.setAttribute("x2",S.positionScreen.x);Q.setAttribute("y2",S.positionScreen.y);E instanceof THREE.LineBasicMaterial&&(Q.setAttribute("style","fill: none; stroke: "+E.color.getContextStyle()+"; stroke-width: "+E.linewidth+"; stroke-opacity: "+E.opacity+"; stroke-linecap: "+E.linecap+"; stroke-linejoin: "+E.linejoin),i.appendChild(Q))}}else if(C instanceof THREE.RenderableFace3){if(o=C.v1,p=C.v2,n=C.v3,o.positionScreen.x*=q,o.positionScreen.y*=-m,p.positionScreen.x*=q,p.positionScreen.y*=-m,n.positionScreen.x*=
+q,n.positionScreen.y*=-m,t.addPoint(o.positionScreen.x,o.positionScreen.y),t.addPoint(p.positionScreen.x,p.positionScreen.y),t.addPoint(n.positionScreen.x,n.positionScreen.y),s.intersects(t)){var S=o,R=p,H=n;d.info.render.vertices+=3;d.info.render.faces++;Q=b(P++);Q.setAttribute("d","M "+S.positionScreen.x+" "+S.positionScreen.y+" L "+R.positionScreen.x+" "+R.positionScreen.y+" L "+H.positionScreen.x+","+H.positionScreen.y+"z");E instanceof THREE.MeshBasicMaterial?u.copy(E.color):E instanceof THREE.MeshLambertMaterial?
+w?(u.r=v.r,u.g=v.g,u.b=v.b,a(e,C.centroidWorld,C.normalWorld,u),u.r=Math.max(0,Math.min(E.color.r*u.r,1)),u.g=Math.max(0,Math.min(E.color.g*u.g,1)),u.b=Math.max(0,Math.min(E.color.b*u.b,1))):u.copy(E.color):E instanceof THREE.MeshDepthMaterial?(B=1-E.__2near/(E.__farPlusNear-C.z*E.__farMinusNear),u.setRGB(B,B,B)):E instanceof THREE.MeshNormalMaterial&&u.setRGB(c(C.normalWorld.x),c(C.normalWorld.y),c(C.normalWorld.z));E.wireframe?Q.setAttribute("style","fill: none; stroke: "+u.getContextStyle()+"; stroke-width: "+
+E.wireframeLinewidth+"; stroke-opacity: "+E.opacity+"; stroke-linecap: "+E.wireframeLinecap+"; stroke-linejoin: "+E.wireframeLinejoin):Q.setAttribute("style","fill: "+u.getContextStyle()+"; fill-opacity: "+E.opacity);i.appendChild(Q)}}else if(C instanceof THREE.RenderableFace4&&(o=C.v1,p=C.v2,n=C.v3,r=C.v4,o.positionScreen.x*=q,o.positionScreen.y*=-m,p.positionScreen.x*=q,p.positionScreen.y*=-m,n.positionScreen.x*=q,n.positionScreen.y*=-m,r.positionScreen.x*=q,r.positionScreen.y*=-m,t.addPoint(o.positionScreen.x,
+o.positionScreen.y),t.addPoint(p.positionScreen.x,p.positionScreen.y),t.addPoint(n.positionScreen.x,n.positionScreen.y),t.addPoint(r.positionScreen.x,r.positionScreen.y),s.intersects(t))){var S=o,R=p,H=n,ka=r;d.info.render.vertices+=4;d.info.render.faces++;Q=b(P++);Q.setAttribute("d","M "+S.positionScreen.x+" "+S.positionScreen.y+" L "+R.positionScreen.x+" "+R.positionScreen.y+" L "+H.positionScreen.x+","+H.positionScreen.y+" L "+ka.positionScreen.x+","+ka.positionScreen.y+"z");E instanceof THREE.MeshBasicMaterial?
+u.copy(E.color):E instanceof THREE.MeshLambertMaterial?w?(u.r=v.r,u.g=v.g,u.b=v.b,a(e,C.centroidWorld,C.normalWorld,u),u.r=Math.max(0,Math.min(E.color.r*u.r,1)),u.g=Math.max(0,Math.min(E.color.g*u.g,1)),u.b=Math.max(0,Math.min(E.color.b*u.b,1))):u.copy(E.color):E instanceof THREE.MeshDepthMaterial?(B=1-E.__2near/(E.__farPlusNear-C.z*E.__farMinusNear),u.setRGB(B,B,B)):E instanceof THREE.MeshNormalMaterial&&u.setRGB(c(C.normalWorld.x),c(C.normalWorld.y),c(C.normalWorld.z));E.wireframe?Q.setAttribute("style",
+"fill: none; stroke: "+u.getContextStyle()+"; stroke-width: "+E.wireframeLinewidth+"; stroke-opacity: "+E.opacity+"; stroke-linecap: "+E.wireframeLinecap+"; stroke-linejoin: "+E.wireframeLinejoin):Q.setAttribute("style","fill: "+u.getContextStyle()+"; fill-opacity: "+E.opacity);i.appendChild(Q)}}};
+THREE.ShaderChunk={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float reflectivity;\nuniform samplerCube envMap;\nuniform float flipEnvMap;\nuniform int combine;\n#endif",
+envmap_fragment:"#ifdef USE_ENVMAP\n#ifdef DOUBLE_SIDED\nfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\nvec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * vReflect.x, vReflect.yz ) );\n#else\nvec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * vReflect.x, vReflect.yz ) );\n#endif\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\nif ( combine == 1 ) {\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, reflectivity );\n} else {\ngl_FragColor.xyz = gl_FragColor.xyz * cubeColor.xyz;\n}\n#endif",
+envmap_pars_vertex:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float refractionRatio;\nuniform bool useRefract;\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvec3 nWorld = mat3( objectMatrix[ 0 ].xyz, objectMatrix[ 1 ].xyz, objectMatrix[ 2 ].xyz ) * normal;\nif ( useRefract ) {\nvReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refractionRatio );\n} else {\nvReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );\n}\n#endif",
+map_particle_pars_fragment:"#ifdef USE_MAP\nuniform sampler2D map;\n#endif",map_particle_fragment:"#ifdef USE_MAP\ngl_FragColor = gl_FragColor * texture2D( map, gl_PointCoord );\n#endif",map_pars_vertex:"#ifdef USE_MAP\nvarying vec2 vUv;\nuniform vec4 offsetRepeat;\n#endif",map_pars_fragment:"#ifdef USE_MAP\nvarying vec2 vUv;\nuniform sampler2D map;\n#endif",map_vertex:"#ifdef USE_MAP\nvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n#endif",map_fragment:"#ifdef USE_MAP\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( map, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( map, vUv );\n#endif\n#endif",
+lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\nuniform sampler2D lightMap;\n#endif",lightmap_pars_vertex:"#ifdef USE_LIGHTMAP\nvarying vec2 vUv2;\n#endif",lightmap_fragment:"#ifdef USE_LIGHTMAP\ngl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );\n#endif",lightmap_vertex:"#ifdef USE_LIGHTMAP\nvUv2 = uv2;\n#endif",lights_lambert_pars_vertex:"uniform vec3 ambient;\nuniform vec3 diffuse;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif",
+lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor;\n#endif",
+lights_phong_pars_vertex:"#if MAX_POINT_LIGHTS > 0\n#ifndef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif",lights_phong_vertex:"#if MAX_POINT_LIGHTS > 0\n#ifndef PHONG_PER_PIXEL\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif",
+lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",
+lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse  = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse  += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse  = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse  += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif",
+color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, opacity );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n#endif",skinning_vertex:"#ifdef USE_SKINNING\ngl_Position  = ( boneGlobalMatrices[ int( skinIndex.x ) ] * skinVertexA ) * skinWeight.x;\ngl_Position += ( boneGlobalMatrices[ int( skinIndex.y ) ] * skinVertexB ) * skinWeight.y;\ngl_Position  = projectionMatrix * modelViewMatrix * gl_Position;\n#endif",
+morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( morphed, 1.0 );\n#endif",
+default_vertex:"#ifndef USE_MORPHTARGETS\n#ifndef USE_SKINNING\ngl_Position = projectionMatrix * mvPosition;\n#endif\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal +=  ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal +=  ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal +=  ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal +=  ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\nvec3 transformedNormal = normalMatrix * morphedNormal;\n#else\nvec3 transformedNormal = normalMatrix * normal;\n#endif",
+shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#ifdef SHADOWMAP_SOFT\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif",
+shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n#ifdef USE_MORPHTARGETS\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( morphed, 1.0 );\n#else\nvShadowCoord[ i ] = shadowMatrix[ i ] * objectMatrix * vec4( position, 1.0 );\n#endif\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",
+linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"};
+THREE.UniformsUtils={merge:function(a){var b,c,d,f={};for(b=0;b<a.length;b++)for(c in d=this.clone(a[b]),d)f[c]=d[c];return f},clone:function(a){var b,c,d,f={};for(b in a)for(c in f[b]={},a[b])d=a[b][c],f[b][c]=d instanceof THREE.Color||d instanceof THREE.Vector2||d instanceof THREE.Vector3||d instanceof THREE.Vector4||d instanceof THREE.Matrix4||d instanceof THREE.Texture?d.clone():d instanceof Array?d.slice():d;return f}};
+THREE.UniformsLib={common:{diffuse:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:0,texture:null},offsetRepeat:{type:"v4",value:new THREE.Vector4(0,0,1,1)},lightMap:{type:"t",value:2,texture:null},envMap:{type:"t",value:1,texture:null},flipEnvMap:{type:"f",value:-1},useRefract:{type:"i",value:0},reflectivity:{type:"f",value:1},refractionRatio:{type:"f",value:0.98},combine:{type:"i",value:0},morphTargetInfluences:{type:"f",value:0}},fog:{fogDensity:{type:"f",
+value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{ambientLightColor:{type:"fv",value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightDistance:{type:"fv1",value:[]}},particle:{psColor:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},size:{type:"f",value:1},scale:{type:"f",
+value:1},map:{type:"t",value:0,texture:null},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},shadowmap:{shadowMap:{type:"tv",value:6,texture:[]},shadowMapSize:{type:"v2v",value:[]},shadowBias:{type:"fv1",value:[]},shadowDarkness:{type:"fv1",value:[]},shadowMatrix:{type:"m4v",value:[]}}};
+THREE.ShaderLib={depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",
+value:1}},vertexShader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}",fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.shadowmap]),vertexShader:[THREE.ShaderChunk.map_pars_vertex,
+THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.color_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.morphtarget_vertex,
+THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,
+THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(328965)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["varying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif",
+THREE.ShaderChunk.map_pars_vertex,THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_lambert_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.color_vertex,
+THREE.ShaderChunk.morphnormal_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\nvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,THREE.ShaderChunk.envmap_pars_fragment,
+THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,"#ifdef DOUBLE_SIDED\nif ( gl_FrontFacing )\ngl_FragColor.xyz *= vLightFront;\nelse\ngl_FragColor.xyz *= vLightBack;\n#else\ngl_FragColor.xyz *= vLightFront;\n#endif",THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,
+THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{ambient:{type:"c",value:new THREE.Color(328965)},specular:{type:"c",value:new THREE.Color(1118481)},shininess:{type:"f",value:30},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["varying vec3 vViewPosition;\nvarying vec3 vNormal;",THREE.ShaderChunk.map_pars_vertex,
+THREE.ShaderChunk.lightmap_pars_vertex,THREE.ShaderChunk.envmap_pars_vertex,THREE.ShaderChunk.lights_phong_pars_vertex,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.map_vertex,THREE.ShaderChunk.lightmap_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.color_vertex,"#ifndef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\n#endif\nvViewPosition = -mvPosition.xyz;",
+THREE.ShaderChunk.morphnormal_vertex,"vNormal = transformedNormal;",THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform vec3 ambient;\nuniform vec3 specular;\nuniform float shininess;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.lightmap_pars_fragment,
+THREE.ShaderChunk.envmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.lights_phong_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3 ( 1.0 ), opacity );",THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,
+THREE.ShaderChunk.fog_fragment,"}"].join("\n")},particle_basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.particle,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n#ifdef USE_SIZEATTENUATION\ngl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n#else\ngl_PointSize = size;\n#endif\ngl_Position = projectionMatrix * mvPosition;",
+THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform float opacity;",THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_particle_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.shadowmap_pars_fragment,"void main() {\ngl_FragColor = vec4( psColor, opacity );",THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.fog_fragment,
+"}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask  = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};
+THREE.WebGLRenderer=function(a){function b(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){if(void 0===a.__webglCustomAttributesList)a.__webglCustomAttributesList=[];for(var f in d.attributes){var e=d.attributes[f];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var g=1;"v2"===e.type?g=2:"v3"===e.type?g=3:"v4"===e.type?g=4:"c"===e.type&&(g=3);e.size=g;e.array=new Float32Array(c*g);e.buffer=l.createBuffer();e.buffer.belongsToAttribute=f;e.needsUpdate=!0}a.__webglCustomAttributesList.push(e)}}}
+function c(a,b){if(a.material&&!(a.material instanceof THREE.MeshFaceMaterial))return a.material;if(0<=b.materialIndex)return a.geometry.materials[b.materialIndex]}function d(a){return a instanceof THREE.MeshBasicMaterial&&!a.envMap||a instanceof THREE.MeshDepthMaterial?!1:a&&void 0!==a.shading&&a.shading===THREE.SmoothShading?THREE.SmoothShading:THREE.FlatShading}function f(a){return a.map||a.lightMap||a instanceof THREE.ShaderMaterial?!0:!1}function g(a,b,c){var d,f,e,g,h=a.vertices;g=h.length;
+var i=a.colors,j=i.length,k=a.__vertexArray,n=a.__colorArray,m=a.__sortArray,o=a.__dirtyVertices,p=a.__dirtyColors,q=a.__webglCustomAttributesList;if(c.sortParticles){Za.multiplySelf(c.matrixWorld);for(d=0;d<g;d++)f=h[d].position,Sa.copy(f),Za.multiplyVector3(Sa),m[d]=[Sa.z,d];m.sort(function(a,b){return b[0]-a[0]});for(d=0;d<g;d++)f=h[m[d][1]].position,e=3*d,k[e]=f.x,k[e+1]=f.y,k[e+2]=f.z;for(d=0;d<j;d++)e=3*d,f=i[m[d][1]],n[e]=f.r,n[e+1]=f.g,n[e+2]=f.b;if(q)for(i=0,j=q.length;i<j;i++)if(h=q[i],
+void 0===h.boundTo||"vertices"===h.boundTo)if(e=0,f=h.value.length,1===h.size)for(d=0;d<f;d++)g=m[d][1],h.array[d]=h.value[g];else if(2===h.size)for(d=0;d<f;d++)g=m[d][1],g=h.value[g],h.array[e]=g.x,h.array[e+1]=g.y,e+=2;else if(3===h.size)if("c"===h.type)for(d=0;d<f;d++)g=m[d][1],g=h.value[g],h.array[e]=g.r,h.array[e+1]=g.g,h.array[e+2]=g.b,e+=3;else for(d=0;d<f;d++)g=m[d][1],g=h.value[g],h.array[e]=g.x,h.array[e+1]=g.y,h.array[e+2]=g.z,e+=3;else if(4===h.size)for(d=0;d<f;d++)g=m[d][1],g=h.value[g],
+h.array[e]=g.x,h.array[e+1]=g.y,h.array[e+2]=g.z,h.array[e+3]=g.w,e+=4}else{if(o)for(d=0;d<g;d++)f=h[d].position,e=3*d,k[e]=f.x,k[e+1]=f.y,k[e+2]=f.z;if(p)for(d=0;d<j;d++)f=i[d],e=3*d,n[e]=f.r,n[e+1]=f.g,n[e+2]=f.b;if(q)for(i=0,j=q.length;i<j;i++)if(h=q[i],h.needsUpdate&&(void 0===h.boundTo||"vertices"===h.boundTo))if(f=h.value.length,e=0,1===h.size)for(d=0;d<f;d++)h.array[d]=h.value[d];else if(2===h.size)for(d=0;d<f;d++)g=h.value[d],h.array[e]=g.x,h.array[e+1]=g.y,e+=2;else if(3===h.size)if("c"===
+h.type)for(d=0;d<f;d++)g=h.value[d],h.array[e]=g.r,h.array[e+1]=g.g,h.array[e+2]=g.b,e+=3;else for(d=0;d<f;d++)g=h.value[d],h.array[e]=g.x,h.array[e+1]=g.y,h.array[e+2]=g.z,e+=3;else if(4===h.size)for(d=0;d<f;d++)g=h.value[d],h.array[e]=g.x,h.array[e+1]=g.y,h.array[e+2]=g.z,h.array[e+3]=g.w,e+=4}if(o||c.sortParticles)l.bindBuffer(l.ARRAY_BUFFER,a.__webglVertexBuffer),l.bufferData(l.ARRAY_BUFFER,k,b);if(p||c.sortParticles)l.bindBuffer(l.ARRAY_BUFFER,a.__webglColorBuffer),l.bufferData(l.ARRAY_BUFFER,
+n,b);if(q)for(i=0,j=q.length;i<j;i++)if(h=q[i],h.needsUpdate||c.sortParticles)l.bindBuffer(l.ARRAY_BUFFER,h.buffer),l.bufferData(l.ARRAY_BUFFER,h.array,b)}function e(a,b){return b.z-a.z}function h(a,b,c){if(a.length)for(var d=0,f=a.length;d<f;d++)ca=C=null,S=R=ba=U=aa=-1,a[d].render(b,c,db,lb),ca=C=null,S=R=ba=U=aa=-1}function i(a,b,c,d,f,e,g,h){var i,l,j,k;b?(l=a.length-1,k=b=-1):(l=0,b=a.length,k=1);for(var n=l;n!==b;n+=k)if(i=a[n],i.render){l=i.object;j=i.buffer;if(h)i=h;else{i=i[c];if(!i)continue;
+g&&y.setBlending(i.blending);y.setDepthTest(i.depthTest);y.setDepthWrite(i.depthWrite);s(i.polygonOffset,i.polygonOffsetFactor,i.polygonOffsetUnits)}y.setObjectFaces(l);j instanceof THREE.BufferGeometry?y.renderBufferDirect(d,f,e,i,j,l):y.renderBuffer(d,f,e,i,j,l)}}function j(a,b,c,d,f,e,g){for(var h,i,l=0,j=a.length;l<j;l++)if(h=a[l],i=h.object,i.visible){if(g)h=g;else{h=h[b];if(!h)continue;e&&y.setBlending(h.blending);y.setDepthTest(h.depthTest);y.setDepthWrite(h.depthWrite);s(h.polygonOffset,h.polygonOffsetFactor,
+h.polygonOffsetUnits)}y.renderImmediateObject(c,d,f,h,i)}}function k(a,b,c){a.push({buffer:b,object:c,opaque:null,transparent:null})}function q(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return!0;return!1}function m(a){for(var b in a.attributes)a.attributes[b].needsUpdate=!1}function o(a,b){for(var c=a.length-1;0<=c;c--)a[c].object===b&&a.splice(c,1)}function p(a,b){for(var c=a.length-1;0<=c;c--)a[c]===b&&a.splice(c,1)}function n(a,b,c,d,f){d.program||y.initMaterial(d,b,c,f);if(d.morphTargets&&
+!f.__webglMorphTargetInfluences){f.__webglMorphTargetInfluences=new Float32Array(y.maxMorphTargets);for(var e=0,g=y.maxMorphTargets;e<g;e++)f.__webglMorphTargetInfluences[e]=0}var h=!1,e=d.program,g=e.uniforms,i=d.uniforms;e!==C&&(l.useProgram(e),C=e,h=!0);if(d.id!==S)S=d.id,h=!0;if(h||a!==ca)l.uniformMatrix4fv(g.projectionMatrix,!1,a._projectionMatrixArray),a!==ca&&(ca=a);if(h){if(c&&d.fog)if(i.fogColor.value=c.color,c instanceof THREE.Fog)i.fogNear.value=c.near,i.fogFar.value=c.far;else if(c instanceof
+THREE.FogExp2)i.fogDensity.value=c.density;if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){var j,k=0,n=0,m=0,o,p,q,r=sa,s=r.directional.colors,t=r.directional.positions,E=r.point.colors,u=r.point.positions,v=r.point.distances,B=0,R=0,D=q=0;for(c=0,h=b.length;c<h;c++)if(j=b[c],!j.onlyShadow)if(o=j.color,p=j.intensity,q=j.distance,j instanceof THREE.AmbientLight)y.gammaInput?(k+=o.r*o.r,n+=o.g*o.g,m+=o.b*o.b):(k+=o.r,n+=o.g,m+=o.b);else if(j instanceof THREE.DirectionalLight)q=
+3*B,y.gammaInput?(s[q]=o.r*o.r*p*p,s[q+1]=o.g*o.g*p*p,s[q+2]=o.b*o.b*p*p):(s[q]=o.r*p,s[q+1]=o.g*p,s[q+2]=o.b*p),La.copy(j.matrixWorld.getPosition()),La.subSelf(j.target.matrixWorld.getPosition()),La.normalize(),t[q]=La.x,t[q+1]=La.y,t[q+2]=La.z,B+=1;else if(j instanceof THREE.PointLight||j instanceof THREE.SpotLight)D=3*R,y.gammaInput?(E[D]=o.r*o.r*p*p,E[D+1]=o.g*o.g*p*p,E[D+2]=o.b*o.b*p*p):(E[D]=o.r*p,E[D+1]=o.g*p,E[D+2]=o.b*p),j=j.matrixWorld.getPosition(),u[D]=j.x,u[D+1]=j.y,u[D+2]=j.z,v[R]=q,
+R+=1;for(c=3*B,h=s.length;c<h;c++)s[c]=0;for(c=3*R,h=E.length;c<h;c++)E[c]=0;r.point.length=R;r.directional.length=B;r.ambient[0]=k;r.ambient[1]=n;r.ambient[2]=m;c=sa;i.ambientLightColor.value=c.ambient;i.directionalLightColor.value=c.directional.colors;i.directionalLightDirection.value=c.directional.positions;i.pointLightColor.value=c.point.colors;i.pointLightPosition.value=c.point.positions;i.pointLightDistance.value=c.point.distances}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||
+d instanceof THREE.MeshPhongMaterial)i.opacity.value=d.opacity,y.gammaInput?i.diffuse.value.copyGammaToLinear(d.color):i.diffuse.value=d.color,(i.map.texture=d.map)&&i.offsetRepeat.value.set(d.map.offset.x,d.map.offset.y,d.map.repeat.x,d.map.repeat.y),i.lightMap.texture=d.lightMap,i.envMap.texture=d.envMap,i.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1,i.reflectivity.value=d.reflectivity,i.refractionRatio.value=d.refractionRatio,i.combine.value=d.combine,i.useRefract.value=
+d.envMap&&d.envMap.mapping instanceof THREE.CubeRefractionMapping;if(d instanceof THREE.LineBasicMaterial)i.diffuse.value=d.color,i.opacity.value=d.opacity;else if(d instanceof THREE.ParticleBasicMaterial)i.psColor.value=d.color,i.opacity.value=d.opacity,i.size.value=d.size,i.scale.value=F.height/2,i.map.texture=d.map;else if(d instanceof THREE.MeshPhongMaterial)i.shininess.value=d.shininess,y.gammaInput?(i.ambient.value.copyGammaToLinear(d.ambient),i.specular.value.copyGammaToLinear(d.specular)):
+(i.ambient.value=d.ambient,i.specular.value=d.specular),d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB);else if(d instanceof THREE.MeshLambertMaterial)y.gammaInput?i.ambient.value.copyGammaToLinear(d.ambient):i.ambient.value=d.ambient,d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB);else if(d instanceof THREE.MeshDepthMaterial)i.mNear.value=a.near,i.mFar.value=a.far,i.opacity.value=d.opacity;else if(d instanceof THREE.MeshNormalMaterial)i.opacity.value=d.opacity;if(f.receiveShadow&&!d._shadowPass&&i.shadowMatrix){h=
+c=0;for(k=b.length;h<k;h++)if(n=b[h],n.castShadow&&(n instanceof THREE.SpotLight||n instanceof THREE.DirectionalLight&&!n.shadowCascade))i.shadowMap.texture[c]=n.shadowMap,i.shadowMapSize.value[c]=n.shadowMapSize,i.shadowMatrix.value[c]=n.shadowMatrix,i.shadowDarkness.value[c]=n.shadowDarkness,i.shadowBias.value[c]=n.shadowBias,c++}b=d.uniformsList;for(i=0,c=b.length;i<c;i++)if(n=e.uniforms[b[i][1]])if(h=b[i][0],m=h.type,k=h.value,"i"===m)l.uniform1i(n,k);else if("f"===m)l.uniform1f(n,k);else if("v2"===
+m)l.uniform2f(n,k.x,k.y);else if("v3"===m)l.uniform3f(n,k.x,k.y,k.z);else if("v4"===m)l.uniform4f(n,k.x,k.y,k.z,k.w);else if("c"===m)l.uniform3f(n,k.r,k.g,k.b);else if("fv1"===m)l.uniform1fv(n,k);else if("fv"===m)l.uniform3fv(n,k);else if("v2v"===m){if(!h._array)h._array=new Float32Array(2*k.length);for(m=0,r=k.length;m<r;m++)s=2*m,h._array[s]=k[m].x,h._array[s+1]=k[m].y;l.uniform2fv(n,h._array)}else if("v3v"===m){if(!h._array)h._array=new Float32Array(3*k.length);for(m=0,r=k.length;m<r;m++)s=3*m,
+h._array[s]=k[m].x,h._array[s+1]=k[m].y,h._array[s+2]=k[m].z;l.uniform3fv(n,h._array)}else if("v4v"==m){if(!h._array)h._array=new Float32Array(4*k.length);for(m=0,r=k.length;m<r;m++)s=4*m,h._array[s]=k[m].x,h._array[s+1]=k[m].y,h._array[s+2]=k[m].z,h._array[s+3]=k[m].w;l.uniform4fv(n,h._array)}else if("m4"===m){if(!h._array)h._array=new Float32Array(16);k.flattenToArray(h._array);l.uniformMatrix4fv(n,!1,h._array)}else if("m4v"===m){if(!h._array)h._array=new Float32Array(16*k.length);for(m=0,r=k.length;m<
+r;m++)k[m].flattenToArrayOffset(h._array,16*m);l.uniformMatrix4fv(n,!1,h._array)}else if("t"===m){if(l.uniform1i(n,k),n=h.texture)if(n.image instanceof Array&&6===n.image.length){if(h=n,6===h.image.length)if(h.needsUpdate){if(!h.image.__webglTextureCube)h.image.__webglTextureCube=l.createTexture();l.activeTexture(l.TEXTURE0+k);l.bindTexture(l.TEXTURE_CUBE_MAP,h.image.__webglTextureCube);k=[];for(n=0;6>n;n++){m=k;r=n;if(y.autoScaleCubemaps){if(s=h.image[n],E=Ea,!(s.width<=E&&s.height<=E))u=Math.max(s.width,
+s.height),t=Math.floor(s.width*E/u),E=Math.floor(s.height*E/u),u=document.createElement("canvas"),u.width=t,u.height=E,u.getContext("2d").drawImage(s,0,0,s.width,s.height,0,0,t,E),s=u}else s=h.image[n];m[r]=s}n=k[0];m=0===(n.width&n.width-1)&&0===(n.height&n.height-1);r=A(h.format);s=A(h.type);w(l.TEXTURE_CUBE_MAP,h,m);for(n=0;6>n;n++)l.texImage2D(l.TEXTURE_CUBE_MAP_POSITIVE_X+n,0,r,r,s,k[n]);h.generateMipmaps&&m&&l.generateMipmap(l.TEXTURE_CUBE_MAP);h.needsUpdate=!1;if(h.onUpdate)h.onUpdate()}else l.activeTexture(l.TEXTURE0+
+k),l.bindTexture(l.TEXTURE_CUBE_MAP,h.image.__webglTextureCube)}else n instanceof THREE.WebGLRenderTargetCube?(h=n,l.activeTexture(l.TEXTURE0+k),l.bindTexture(l.TEXTURE_CUBE_MAP,h.__webglTexture)):y.setTexture(n,k)}else if("tv"===m){if(!h._array){h._array=[];for(m=0,r=h.texture.length;m<r;m++)h._array[m]=k+m}l.uniform1iv(n,h._array);for(m=0,r=h.texture.length;m<r;m++)(n=h.texture[m])&&y.setTexture(n,h._array[m])}if((d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&
+null!==g.cameraPosition)b=a.matrixWorld.getPosition(),l.uniform3f(g.cameraPosition,b.x,b.y,b.z);(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==g.viewMatrix&&l.uniformMatrix4fv(g.viewMatrix,!1,a._viewMatrixArray);d.skinning&&l.uniformMatrix4fv(g.boneGlobalMatrices,!1,f.boneMatrices)}l.uniformMatrix4fv(g.modelViewMatrix,!1,f._modelViewMatrixArray);g.normalMatrix&&l.uniformMatrix3fv(g.normalMatrix,!1,f._normalMatrixArray);
+(d instanceof THREE.ShaderMaterial||d.envMap||d.skinning||f.receiveShadow)&&null!==g.objectMatrix&&l.uniformMatrix4fv(g.objectMatrix,!1,f._objectMatrixArray);return e}function r(a,b){a._modelViewMatrix.multiplyToArray(b.matrixWorldInverse,a.matrixWorld,a._modelViewMatrixArray);var c=THREE.Matrix4.makeInvert3x3(a._modelViewMatrix);c&&c.transposeIntoArray(a._normalMatrixArray)}function s(a,b,c){ea!==a&&(a?l.enable(l.POLYGON_OFFSET_FILL):l.disable(l.POLYGON_OFFSET_FILL),ea=a);if(a&&(Ta!==b||Ja!==c))l.polygonOffset(b,
+c),Ta=b,Ja=c}function t(a,b){var c;"fragment"===a?c=l.createShader(l.FRAGMENT_SHADER):"vertex"===a&&(c=l.createShader(l.VERTEX_SHADER));l.shaderSource(c,b);l.compileShader(c);return!l.getShaderParameter(c,l.COMPILE_STATUS)?(console.error(l.getShaderInfoLog(c)),console.error(b),null):c}function w(a,b,c){c?(l.texParameteri(a,l.TEXTURE_WRAP_S,A(b.wrapS)),l.texParameteri(a,l.TEXTURE_WRAP_T,A(b.wrapT)),l.texParameteri(a,l.TEXTURE_MAG_FILTER,A(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,A(b.minFilter))):
+(l.texParameteri(a,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_MAG_FILTER,v(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,v(b.minFilter)))}function u(a,b){l.bindRenderbuffer(l.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_COMPONENT16,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT,l.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,
+l.DEPTH_STENCIL,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a)):l.renderbufferStorage(l.RENDERBUFFER,l.RGBA4,b.width,b.height)}function v(a){switch(a){case THREE.NearestFilter:case THREE.NearestMipMapNearestFilter:case THREE.NearestMipMapLinearFilter:return l.NEAREST;default:return l.LINEAR}}function A(a){switch(a){case THREE.RepeatWrapping:return l.REPEAT;case THREE.ClampToEdgeWrapping:return l.CLAMP_TO_EDGE;case THREE.MirroredRepeatWrapping:return l.MIRRORED_REPEAT;
+case THREE.NearestFilter:return l.NEAREST;case THREE.NearestMipMapNearestFilter:return l.NEAREST_MIPMAP_NEAREST;case THREE.NearestMipMapLinearFilter:return l.NEAREST_MIPMAP_LINEAR;case THREE.LinearFilter:return l.LINEAR;case THREE.LinearMipMapNearestFilter:return l.LINEAR_MIPMAP_NEAREST;case THREE.LinearMipMapLinearFilter:return l.LINEAR_MIPMAP_LINEAR;case THREE.ByteType:return l.BYTE;case THREE.UnsignedByteType:return l.UNSIGNED_BYTE;case THREE.ShortType:return l.SHORT;case THREE.UnsignedShortType:return l.UNSIGNED_SHORT;
+case THREE.IntType:return l.INT;case THREE.UnsignedIntType:return l.UNSIGNED_INT;case THREE.FloatType:return l.FLOAT;case THREE.AlphaFormat:return l.ALPHA;case THREE.RGBFormat:return l.RGB;case THREE.RGBAFormat:return l.RGBA;case THREE.LuminanceFormat:return l.LUMINANCE;case THREE.LuminanceAlphaFormat:return l.LUMINANCE_ALPHA}return 0}var a=a||{},F=void 0!==a.canvas?a.canvas:document.createElement("canvas"),B=void 0!==a.precision?a.precision:"mediump",D=void 0!==a.alpha?a.alpha:!0,H=void 0!==a.premultipliedAlpha?
+a.premultipliedAlpha:!0,I=void 0!==a.antialias?a.antialias:!1,Q=void 0!==a.stencil?a.stencil:!0,P=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,L=void 0!==a.clearColor?new THREE.Color(a.clearColor):new THREE.Color(0),K=void 0!==a.clearAlpha?a.clearAlpha:0,O=void 0!==a.maxLights?a.maxLights:4;this.domElement=F;this.context=null;this.autoUpdateScene=this.autoUpdateObjects=this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=
+this.physicallyBasedShading=this.gammaOutput=this.gammaInput=!1;this.shadowMapCullFrontFaces=this.shadowMapSoft=this.shadowMapAutoUpdate=!0;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.renderPluginsPre=[];this.renderPluginsPost=[];this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var y=this,l,$=[],C=null,E=null,S=-1,R=null,ca=null,ka=0,ia=null,N=null,aa=null,U=null,ba=null,
+ea=null,Ta=null,Ja=null,Ka=null,Ga=0,qa=0,ha=0,ib=0,db=0,lb=0,cb=new THREE.Frustum,Za=new THREE.Matrix4,Sa=new THREE.Vector4,La=new THREE.Vector3,sa={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]}};l=function(){var a;try{if(!(a=F.getContext("experimental-webgl",{alpha:D,premultipliedAlpha:H,antialias:I,stencil:Q,preserveDrawingBuffer:P})))throw"Error creating WebGL context.";console.log(navigator.userAgent+" | "+a.getParameter(a.VERSION)+
+" | "+a.getParameter(a.VENDOR)+" | "+a.getParameter(a.RENDERER)+" | "+a.getParameter(a.SHADING_LANGUAGE_VERSION))}catch(b){console.error(b)}return a}();l.clearColor(0,0,0,1);l.clearDepth(1);l.clearStencil(0);l.enable(l.DEPTH_TEST);l.depthFunc(l.LEQUAL);l.frontFace(l.CCW);l.cullFace(l.BACK);l.enable(l.CULL_FACE);l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.SRC_ALPHA,l.ONE_MINUS_SRC_ALPHA);l.clearColor(L.r,L.g,L.b,K);this.context=l;var za=l.getParameter(l.MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+l.getParameter(l.MAX_TEXTURE_SIZE);var Ea=l.getParameter(l.MAX_CUBE_MAP_TEXTURE_SIZE);this.getContext=function(){return l};this.supportsVertexTextures=function(){return 0<za};this.setSize=function(a,b){F.width=a;F.height=b;this.setViewport(0,0,F.width,F.height)};this.setViewport=function(a,b,c,d){Ga=a;qa=b;ha=c;ib=d;l.viewport(Ga,qa,ha,ib)};this.setScissor=function(a,b,c,d){l.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?l.enable(l.SCISSOR_TEST):l.disable(l.SCISSOR_TEST)};this.setClearColorHex=
+function(a,b){L.setHex(a);K=b;l.clearColor(L.r,L.g,L.b,K)};this.setClearColor=function(a,b){L.copy(a);K=b;l.clearColor(L.r,L.g,L.b,K)};this.getClearColor=function(){return L};this.getClearAlpha=function(){return K};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=l.COLOR_BUFFER_BIT;if(void 0===b||b)d|=l.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=l.STENCIL_BUFFER_BIT;l.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);
+this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};this.deallocateObject=function(a){if(a.__webglInit)if(a.__webglInit=!1,delete a._modelViewMatrix,delete a._normalMatrixArray,delete a._modelViewMatrixArray,delete a._objectMatrixArray,a instanceof THREE.Mesh)for(var b in a.geometry.geometryGroups){var c=a.geometry.geometryGroups[b];l.deleteBuffer(c.__webglVertexBuffer);l.deleteBuffer(c.__webglNormalBuffer);l.deleteBuffer(c.__webglTangentBuffer);
+l.deleteBuffer(c.__webglColorBuffer);l.deleteBuffer(c.__webglUVBuffer);l.deleteBuffer(c.__webglUV2Buffer);l.deleteBuffer(c.__webglSkinVertexABuffer);l.deleteBuffer(c.__webglSkinVertexBBuffer);l.deleteBuffer(c.__webglSkinIndicesBuffer);l.deleteBuffer(c.__webglSkinWeightsBuffer);l.deleteBuffer(c.__webglFaceBuffer);l.deleteBuffer(c.__webglLineBuffer);var d=void 0,f=void 0;if(c.numMorphTargets)for(d=0,f=c.numMorphTargets;d<f;d++)l.deleteBuffer(c.__webglMorphTargetsBuffers[d]);if(c.numMorphNormals)for(d=
+0,f=c.numMorphNormals;d<f;d++)l.deleteBuffer(c.__webglMorphNormalsBuffers[d]);if(c.__webglCustomAttributesList)for(d in d=void 0,c.__webglCustomAttributesList)l.deleteBuffer(c.__webglCustomAttributesList[d].buffer);y.info.memory.geometries--}else if(a instanceof THREE.Ribbon)a=a.geometry,l.deleteBuffer(a.__webglVertexBuffer),l.deleteBuffer(a.__webglColorBuffer),y.info.memory.geometries--;else if(a instanceof THREE.Line)a=a.geometry,l.deleteBuffer(a.__webglVertexBuffer),l.deleteBuffer(a.__webglColorBuffer),
+y.info.memory.geometries--;else if(a instanceof THREE.ParticleSystem)a=a.geometry,l.deleteBuffer(a.__webglVertexBuffer),l.deleteBuffer(a.__webglColorBuffer),y.info.memory.geometries--};this.deallocateTexture=function(a){if(a.__webglInit)a.__webglInit=!1,l.deleteTexture(a.__webglTexture),y.info.memory.textures--};this.updateShadowMap=function(a,b){C=null;S=R=ba=U=aa=-1;this.shadowMapPlugin.update(a,b)};this.renderBufferImmediate=function(a,b,c){if(!a.__webglVertexBuffer)a.__webglVertexBuffer=l.createBuffer();
+if(!a.__webglNormalBuffer)a.__webglNormalBuffer=l.createBuffer();a.hasPos&&(l.bindBuffer(l.ARRAY_BUFFER,a.__webglVertexBuffer),l.bufferData(l.ARRAY_BUFFER,a.positionArray,l.DYNAMIC_DRAW),l.enableVertexAttribArray(b.attributes.position),l.vertexAttribPointer(b.attributes.position,3,l.FLOAT,!1,0,0));if(a.hasNormal){l.bindBuffer(l.ARRAY_BUFFER,a.__webglNormalBuffer);if(c===THREE.FlatShading){var d,f,e,g,h,i,j,k,n,m,o=3*a.count;for(m=0;m<o;m+=9)c=a.normalArray,d=c[m],f=c[m+1],e=c[m+2],g=c[m+3],i=c[m+
+4],k=c[m+5],h=c[m+6],j=c[m+7],n=c[m+8],d=(d+g+h)/3,f=(f+i+j)/3,e=(e+k+n)/3,c[m]=d,c[m+1]=f,c[m+2]=e,c[m+3]=d,c[m+4]=f,c[m+5]=e,c[m+6]=d,c[m+7]=f,c[m+8]=e}l.bufferData(l.ARRAY_BUFFER,a.normalArray,l.DYNAMIC_DRAW);l.enableVertexAttribArray(b.attributes.normal);l.vertexAttribPointer(b.attributes.normal,3,l.FLOAT,!1,0,0)}l.drawArrays(l.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,f,e){if(0!==d.opacity&&(c=n(a,b,c,d,e),a=c.attributes,b=!1,d=16777215*f.id+2*c.id+(d.wireframe?
+1:0),d!==R&&(R=d,b=!0),e instanceof THREE.Mesh)){e=f.offsets;d=0;for(c=e.length;d<c;++d)b&&(l.bindBuffer(l.ARRAY_BUFFER,f.vertexPositionBuffer),l.vertexAttribPointer(a.position,f.vertexPositionBuffer.itemSize,l.FLOAT,!1,0,12*e[d].index),0<=a.normal&&f.vertexNormalBuffer&&(l.bindBuffer(l.ARRAY_BUFFER,f.vertexNormalBuffer),l.vertexAttribPointer(a.normal,f.vertexNormalBuffer.itemSize,l.FLOAT,!1,0,12*e[d].index)),0<=a.uv&&f.vertexUvBuffer&&(f.vertexUvBuffer?(l.bindBuffer(l.ARRAY_BUFFER,f.vertexUvBuffer),
+l.vertexAttribPointer(a.uv,f.vertexUvBuffer.itemSize,l.FLOAT,!1,0,8*e[d].index),l.enableVertexAttribArray(a.uv)):l.disableVertexAttribArray(a.uv)),0<=a.color&&f.vertexColorBuffer&&(l.bindBuffer(l.ARRAY_BUFFER,f.vertexColorBuffer),l.vertexAttribPointer(a.color,f.vertexColorBuffer.itemSize,l.FLOAT,!1,0,16*e[d].index)),l.bindBuffer(l.ELEMENT_ARRAY_BUFFER,f.vertexIndexBuffer)),l.drawElements(l.TRIANGLES,e[d].count,l.UNSIGNED_SHORT,2*e[d].start),y.info.render.calls++,y.info.render.vertices+=e[d].count,
+y.info.render.faces+=e[d].count/3}};this.renderBuffer=function(a,b,c,d,f,e){if(0!==d.opacity){var g,h,c=n(a,b,c,d,e),b=c.attributes,a=!1,c=16777215*f.id+2*c.id+(d.wireframe?1:0);c!==R&&(R=c,a=!0);if(!d.morphTargets&&0<=b.position)a&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglVertexBuffer),l.vertexAttribPointer(b.position,3,l.FLOAT,!1,0,0));else if(e.morphTargetBase){c=d.program.attributes;-1!==e.morphTargetBase?(l.bindBuffer(l.ARRAY_BUFFER,f.__webglMorphTargetsBuffers[e.morphTargetBase]),l.vertexAttribPointer(c.position,
+3,l.FLOAT,!1,0,0)):0<=c.position&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglVertexBuffer),l.vertexAttribPointer(c.position,3,l.FLOAT,!1,0,0));if(e.morphTargetForcedOrder.length){g=0;var i=e.morphTargetForcedOrder;for(h=e.morphTargetInfluences;g<d.numSupportedMorphTargets&&g<i.length;)l.bindBuffer(l.ARRAY_BUFFER,f.__webglMorphTargetsBuffers[i[g]]),l.vertexAttribPointer(c["morphTarget"+g],3,l.FLOAT,!1,0,0),d.morphNormals&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglMorphNormalsBuffers[i[g]]),l.vertexAttribPointer(c["morphNormal"+
+g],3,l.FLOAT,!1,0,0)),e.__webglMorphTargetInfluences[g]=h[i[g]],g++}else{var i=[],j=-1,k=0;h=e.morphTargetInfluences;var m,o=h.length;g=0;for(-1!==e.morphTargetBase&&(i[e.morphTargetBase]=!0);g<d.numSupportedMorphTargets;){for(m=0;m<o;m++)!i[m]&&h[m]>j&&(k=m,j=h[k]);l.bindBuffer(l.ARRAY_BUFFER,f.__webglMorphTargetsBuffers[k]);l.vertexAttribPointer(c["morphTarget"+g],3,l.FLOAT,!1,0,0);d.morphNormals&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglMorphNormalsBuffers[k]),l.vertexAttribPointer(c["morphNormal"+
+g],3,l.FLOAT,!1,0,0));e.__webglMorphTargetInfluences[g]=j;i[k]=1;j=-1;g++}}null!==d.program.uniforms.morphTargetInfluences&&l.uniform1fv(d.program.uniforms.morphTargetInfluences,e.__webglMorphTargetInfluences)}if(a){if(f.__webglCustomAttributesList)for(g=0,h=f.__webglCustomAttributesList.length;g<h;g++)c=f.__webglCustomAttributesList[g],0<=b[c.buffer.belongsToAttribute]&&(l.bindBuffer(l.ARRAY_BUFFER,c.buffer),l.vertexAttribPointer(b[c.buffer.belongsToAttribute],c.size,l.FLOAT,!1,0,0));0<=b.color&&
+(l.bindBuffer(l.ARRAY_BUFFER,f.__webglColorBuffer),l.vertexAttribPointer(b.color,3,l.FLOAT,!1,0,0));0<=b.normal&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglNormalBuffer),l.vertexAttribPointer(b.normal,3,l.FLOAT,!1,0,0));0<=b.tangent&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglTangentBuffer),l.vertexAttribPointer(b.tangent,4,l.FLOAT,!1,0,0));0<=b.uv&&(f.__webglUVBuffer?(l.bindBuffer(l.ARRAY_BUFFER,f.__webglUVBuffer),l.vertexAttribPointer(b.uv,2,l.FLOAT,!1,0,0),l.enableVertexAttribArray(b.uv)):l.disableVertexAttribArray(b.uv));
+0<=b.uv2&&(f.__webglUV2Buffer?(l.bindBuffer(l.ARRAY_BUFFER,f.__webglUV2Buffer),l.vertexAttribPointer(b.uv2,2,l.FLOAT,!1,0,0),l.enableVertexAttribArray(b.uv2)):l.disableVertexAttribArray(b.uv2));d.skinning&&0<=b.skinVertexA&&0<=b.skinVertexB&&0<=b.skinIndex&&0<=b.skinWeight&&(l.bindBuffer(l.ARRAY_BUFFER,f.__webglSkinVertexABuffer),l.vertexAttribPointer(b.skinVertexA,4,l.FLOAT,!1,0,0),l.bindBuffer(l.ARRAY_BUFFER,f.__webglSkinVertexBBuffer),l.vertexAttribPointer(b.skinVertexB,4,l.FLOAT,!1,0,0),l.bindBuffer(l.ARRAY_BUFFER,
+f.__webglSkinIndicesBuffer),l.vertexAttribPointer(b.skinIndex,4,l.FLOAT,!1,0,0),l.bindBuffer(l.ARRAY_BUFFER,f.__webglSkinWeightsBuffer),l.vertexAttribPointer(b.skinWeight,4,l.FLOAT,!1,0,0))}e instanceof THREE.Mesh?(d.wireframe?(d=d.wireframeLinewidth,d!==Ka&&(l.lineWidth(d),Ka=d),a&&l.bindBuffer(l.ELEMENT_ARRAY_BUFFER,f.__webglLineBuffer),l.drawElements(l.LINES,f.__webglLineCount,l.UNSIGNED_SHORT,0)):(a&&l.bindBuffer(l.ELEMENT_ARRAY_BUFFER,f.__webglFaceBuffer),l.drawElements(l.TRIANGLES,f.__webglFaceCount,
+l.UNSIGNED_SHORT,0)),y.info.render.calls++,y.info.render.vertices+=f.__webglFaceCount,y.info.render.faces+=f.__webglFaceCount/3):e instanceof THREE.Line?(e=e.type===THREE.LineStrip?l.LINE_STRIP:l.LINES,d=d.linewidth,d!==Ka&&(l.lineWidth(d),Ka=d),l.drawArrays(e,0,f.__webglLineCount),y.info.render.calls++):e instanceof THREE.ParticleSystem?(l.drawArrays(l.POINTS,0,f.__webglParticleCount),y.info.render.calls++,y.info.render.points+=f.__webglParticleCount):e instanceof THREE.Ribbon&&(l.drawArrays(l.TRIANGLE_STRIP,
+0,f.__webglVertexCount),y.info.render.calls++)}};this.render=function(a,b,c,d){var f,g,k,m,n=a.__lights,o=a.fog;S=-1;this.autoUpdateObjects&&this.initWebGLObjects(a);void 0===b.parent&&(console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it..."),a.add(b));this.autoUpdateScene&&a.updateMatrixWorld();h(this.renderPluginsPre,a,b);y.info.render.calls=0;y.info.render.vertices=0;y.info.render.faces=0;y.info.render.points=0;b.matrixWorldInverse.getInverse(b.matrixWorld);if(!b._viewMatrixArray)b._viewMatrixArray=
+new Float32Array(16);b.matrixWorldInverse.flattenToArray(b._viewMatrixArray);if(!b._projectionMatrixArray)b._projectionMatrixArray=new Float32Array(16);b.projectionMatrix.flattenToArray(b._projectionMatrixArray);Za.multiply(b.projectionMatrix,b.matrixWorldInverse);cb.setFromMatrix(Za);this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);m=a.__webglObjects;for(d=0,f=m.length;d<f;d++)if(g=m[d],k=g.object,g.render=!1,k.visible&&(!(k instanceof
+THREE.Mesh||k instanceof THREE.ParticleSystem)||!k.frustumCulled||cb.contains(k))){k.matrixWorld.flattenToArray(k._objectMatrixArray);r(k,b);var p=g,q=p.object,t=p.buffer,E=void 0,E=E=void 0,E=q.material;if(E instanceof THREE.MeshFaceMaterial){if(E=t.materialIndex,0<=E)E=q.geometry.materials[E],E.transparent?(p.transparent=E,p.opaque=null):(p.opaque=E,p.transparent=null)}else if(E)E.transparent?(p.transparent=E,p.opaque=null):(p.opaque=E,p.transparent=null);g.render=!0;if(this.sortObjects)k.renderDepth?
+g.z=k.renderDepth:(Sa.copy(k.position),Za.multiplyVector3(Sa),g.z=Sa.z)}this.sortObjects&&m.sort(e);m=a.__webglObjectsImmediate;for(d=0,f=m.length;d<f;d++)if(g=m[d],k=g.object,k.visible)k.matrixAutoUpdate&&k.matrixWorld.flattenToArray(k._objectMatrixArray),r(k,b),k=g.object.material,k.transparent?(g.transparent=k,g.opaque=null):(g.opaque=k,g.transparent=null);a.overrideMaterial?(this.setBlending(a.overrideMaterial.blending),this.setDepthTest(a.overrideMaterial.depthTest),this.setDepthWrite(a.overrideMaterial.depthWrite),
+s(a.overrideMaterial.polygonOffset,a.overrideMaterial.polygonOffsetFactor,a.overrideMaterial.polygonOffsetUnits),i(a.__webglObjects,!1,"",b,n,o,!0,a.overrideMaterial),j(a.__webglObjectsImmediate,"",b,n,o,!1,a.overrideMaterial)):(this.setBlending(THREE.NormalBlending),i(a.__webglObjects,!0,"opaque",b,n,o,!1),j(a.__webglObjectsImmediate,"opaque",b,n,o,!1),i(a.__webglObjects,!1,"transparent",b,n,o,!0),j(a.__webglObjectsImmediate,"transparent",b,n,o,!0));h(this.renderPluginsPost,a,b);c&&c.generateMipmaps&&
+c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter&&(c instanceof THREE.WebGLRenderTargetCube?(l.bindTexture(l.TEXTURE_CUBE_MAP,c.__webglTexture),l.generateMipmap(l.TEXTURE_CUBE_MAP),l.bindTexture(l.TEXTURE_CUBE_MAP,null)):(l.bindTexture(l.TEXTURE_2D,c.__webglTexture),l.generateMipmap(l.TEXTURE_2D),l.bindTexture(l.TEXTURE_2D,null)));this.setDepthTest(!0);this.setDepthWrite(!0)};this.renderImmediateObject=function(a,b,c,d,f){var e=n(a,b,c,d,f);R=-1;y.setObjectFaces(f);f.immediateRenderCallback?
+f.immediateRenderCallback(e,l,cb):f.render(function(a){y.renderBufferImmediate(a,e,d.shading)})};this.initWebGLObjects=function(a){if(!a.__webglObjects)a.__webglObjects=[],a.__webglObjectsImmediate=[],a.__webglSprites=[],a.__webglFlares=[];for(;a.__objectsAdded.length;){var e=a.__objectsAdded[0],h=a,i=void 0,j=void 0,n=void 0;if(!e.__webglInit)if(e.__webglInit=!0,e._modelViewMatrix=new THREE.Matrix4,e._normalMatrixArray=new Float32Array(9),e._modelViewMatrixArray=new Float32Array(16),e._objectMatrixArray=
+new Float32Array(16),e.matrixWorld.flattenToArray(e._objectMatrixArray),e instanceof THREE.Mesh){if(j=e.geometry,j instanceof THREE.Geometry){if(void 0===j.geometryGroups){var r=j,s=void 0,t=void 0,E=void 0,u=void 0,v=void 0,w=void 0,C=void 0,B={},D=r.morphTargets.length,R=r.morphNormals.length;r.geometryGroups={};for(s=0,t=r.faces.length;s<t;s++)E=r.faces[s],u=E.materialIndex,w=void 0!==u?u:-1,void 0===B[w]&&(B[w]={hash:w,counter:0}),C=B[w].hash+"_"+B[w].counter,void 0===r.geometryGroups[C]&&(r.geometryGroups[C]=
+{faces3:[],faces4:[],materialIndex:u,vertices:0,numMorphTargets:D,numMorphNormals:R}),v=E instanceof THREE.Face3?3:4,65535<r.geometryGroups[C].vertices+v&&(B[w].counter+=1,C=B[w].hash+"_"+B[w].counter,void 0===r.geometryGroups[C]&&(r.geometryGroups[C]={faces3:[],faces4:[],materialIndex:u,vertices:0,numMorphTargets:D,numMorphNormals:R})),E instanceof THREE.Face3?r.geometryGroups[C].faces3.push(s):r.geometryGroups[C].faces4.push(s),r.geometryGroups[C].vertices+=v;r.geometryGroupsList=[];var A=void 0;
+for(A in r.geometryGroups)r.geometryGroups[A].id=ka++,r.geometryGroupsList.push(r.geometryGroups[A])}for(i in j.geometryGroups)if(n=j.geometryGroups[i],!n.__webglVertexBuffer){var S=n;S.__webglVertexBuffer=l.createBuffer();S.__webglNormalBuffer=l.createBuffer();S.__webglTangentBuffer=l.createBuffer();S.__webglColorBuffer=l.createBuffer();S.__webglUVBuffer=l.createBuffer();S.__webglUV2Buffer=l.createBuffer();S.__webglSkinVertexABuffer=l.createBuffer();S.__webglSkinVertexBBuffer=l.createBuffer();S.__webglSkinIndicesBuffer=
+l.createBuffer();S.__webglSkinWeightsBuffer=l.createBuffer();S.__webglFaceBuffer=l.createBuffer();S.__webglLineBuffer=l.createBuffer();var F=void 0,H=void 0;if(S.numMorphTargets){S.__webglMorphTargetsBuffers=[];for(F=0,H=S.numMorphTargets;F<H;F++)S.__webglMorphTargetsBuffers.push(l.createBuffer())}if(S.numMorphNormals){S.__webglMorphNormalsBuffers=[];for(F=0,H=S.numMorphNormals;F<H;F++)S.__webglMorphNormalsBuffers.push(l.createBuffer())}y.info.memory.geometries++;var N=n,I=e,K=I.geometry,ca=N.faces3,
+O=N.faces4,L=3*ca.length+4*O.length,P=1*ca.length+2*O.length,ia=3*ca.length+4*O.length,U=c(I,N),Q=f(U),aa=d(U),ba=U.vertexColors?U.vertexColors:!1;N.__vertexArray=new Float32Array(3*L);if(aa)N.__normalArray=new Float32Array(3*L);if(K.hasTangents)N.__tangentArray=new Float32Array(4*L);if(ba)N.__colorArray=new Float32Array(3*L);if(Q){if(0<K.faceUvs.length||0<K.faceVertexUvs.length)N.__uvArray=new Float32Array(2*L);if(1<K.faceUvs.length||1<K.faceVertexUvs.length)N.__uv2Array=new Float32Array(2*L)}if(I.geometry.skinWeights.length&&
+I.geometry.skinIndices.length)N.__skinVertexAArray=new Float32Array(4*L),N.__skinVertexBArray=new Float32Array(4*L),N.__skinIndexArray=new Float32Array(4*L),N.__skinWeightArray=new Float32Array(4*L);N.__faceArray=new Uint16Array(3*P);N.__lineArray=new Uint16Array(2*ia);var ea=void 0,$=void 0;if(N.numMorphTargets){N.__morphTargetsArrays=[];for(ea=0,$=N.numMorphTargets;ea<$;ea++)N.__morphTargetsArrays.push(new Float32Array(3*L))}if(N.numMorphNormals){N.__morphNormalsArrays=[];for(ea=0,$=N.numMorphNormals;ea<
+$;ea++)N.__morphNormalsArrays.push(new Float32Array(3*L))}N.__webglFaceCount=3*P;N.__webglLineCount=2*ia;if(U.attributes){if(void 0===N.__webglCustomAttributesList)N.__webglCustomAttributesList=[];var Ja=void 0;for(Ja in U.attributes){var Ta=U.attributes[Ja],ha={},Ka;for(Ka in Ta)ha[Ka]=Ta[Ka];if(!ha.__webglInitialized||ha.createUniqueBuffers){ha.__webglInitialized=!0;var qa=1;"v2"===ha.type?qa=2:"v3"===ha.type?qa=3:"v4"===ha.type?qa=4:"c"===ha.type&&(qa=3);ha.size=qa;ha.array=new Float32Array(L*
+qa);ha.buffer=l.createBuffer();ha.buffer.belongsToAttribute=Ja;Ta.needsUpdate=!0;ha.__original=Ta}N.__webglCustomAttributesList.push(ha)}}N.__inittedArrays=!0;j.__dirtyVertices=!0;j.__dirtyMorphTargets=!0;j.__dirtyElements=!0;j.__dirtyUvs=!0;j.__dirtyNormals=!0;j.__dirtyTangents=!0;j.__dirtyColors=!0}}}else if(e instanceof THREE.Ribbon){if(j=e.geometry,!j.__webglVertexBuffer){var Ga=j;Ga.__webglVertexBuffer=l.createBuffer();Ga.__webglColorBuffer=l.createBuffer();y.info.memory.geometries++;var sa=
+j,za=sa.vertices.length;sa.__vertexArray=new Float32Array(3*za);sa.__colorArray=new Float32Array(3*za);sa.__webglVertexCount=za;j.__dirtyVertices=!0;j.__dirtyColors=!0}}else if(e instanceof THREE.Line){if(j=e.geometry,!j.__webglVertexBuffer){var La=j;La.__webglVertexBuffer=l.createBuffer();La.__webglColorBuffer=l.createBuffer();y.info.memory.geometries++;var Ea=j,ib=e,db=Ea.vertices.length;Ea.__vertexArray=new Float32Array(3*db);Ea.__colorArray=new Float32Array(3*db);Ea.__webglLineCount=db;b(Ea,ib);
+j.__dirtyVertices=!0;j.__dirtyColors=!0}}else if(e instanceof THREE.ParticleSystem&&(j=e.geometry,!j.__webglVertexBuffer)){var Za=j;Za.__webglVertexBuffer=l.createBuffer();Za.__webglColorBuffer=l.createBuffer();y.info.geometries++;var Sa=j,lb=e,cb=Sa.vertices.length;Sa.__vertexArray=new Float32Array(3*cb);Sa.__colorArray=new Float32Array(3*cb);Sa.__sortArray=[];Sa.__webglParticleCount=cb;b(Sa,lb);j.__dirtyVertices=!0;j.__dirtyColors=!0}if(!e.__webglActive){if(e instanceof THREE.Mesh)if(j=e.geometry,
+j instanceof THREE.BufferGeometry)k(h.__webglObjects,j,e);else for(i in j.geometryGroups)n=j.geometryGroups[i],k(h.__webglObjects,n,e);else e instanceof THREE.Ribbon||e instanceof THREE.Line||e instanceof THREE.ParticleSystem?(j=e.geometry,k(h.__webglObjects,j,e)):void 0!==THREE.MarchingCubes&&e instanceof THREE.MarchingCubes||e.immediateRenderCallback?h.__webglObjectsImmediate.push({object:e,opaque:null,transparent:null}):e instanceof THREE.Sprite?h.__webglSprites.push(e):e instanceof THREE.LensFlare&&
+h.__webglFlares.push(e);e.__webglActive=!0}a.__objectsAdded.splice(0,1)}for(;a.__objectsRemoved.length;){var fb=a.__objectsRemoved[0],Fc=a;fb instanceof THREE.Mesh||fb instanceof THREE.ParticleSystem||fb instanceof THREE.Ribbon||fb instanceof THREE.Line?o(Fc.__webglObjects,fb):fb instanceof THREE.Sprite?p(Fc.__webglSprites,fb):fb instanceof THREE.LensFlare?p(Fc.__webglFlares,fb):(fb instanceof THREE.MarchingCubes||fb.immediateRenderCallback)&&o(Fc.__webglObjectsImmediate,fb);fb.__webglActive=!1;a.__objectsRemoved.splice(0,
+1)}for(var Wc=0,rd=a.__webglObjects.length;Wc<rd;Wc++){var nb=a.__webglObjects[Wc].object,ja=nb.geometry,qc=void 0,ic=void 0,Xa=void 0;if(nb instanceof THREE.Mesh)if(ja instanceof THREE.BufferGeometry)ja.__dirtyVertices=!1,ja.__dirtyElements=!1,ja.__dirtyUvs=!1,ja.__dirtyNormals=!1,ja.__dirtyColors=!1;else{for(var Xc=0,sd=ja.geometryGroupsList.length;Xc<sd;Xc++)if(qc=ja.geometryGroupsList[Xc],Xa=c(nb,qc),ic=Xa.attributes&&q(Xa),ja.__dirtyVertices||ja.__dirtyMorphTargets||ja.__dirtyElements||ja.__dirtyUvs||
+ja.__dirtyNormals||ja.__dirtyColors||ja.__dirtyTangents||ic){var fa=qc,td=nb,$a=l.DYNAMIC_DRAW,ud=!ja.dynamic,bc=Xa;if(fa.__inittedArrays){var gd=d(bc),Yc=bc.vertexColors?bc.vertexColors:!1,hd=f(bc),Gc=gd===THREE.SmoothShading,G=void 0,V=void 0,kb=void 0,M=void 0,jc=void 0,Ob=void 0,ob=void 0,Hc=void 0,Hb=void 0,kc=void 0,lc=void 0,W=void 0,X=void 0,Y=void 0,oa=void 0,pb=void 0,qb=void 0,rb=void 0,rc=void 0,sb=void 0,tb=void 0,ub=void 0,sc=void 0,vb=void 0,wb=void 0,xb=void 0,tc=void 0,yb=void 0,
+zb=void 0,Ab=void 0,uc=void 0,Bb=void 0,Cb=void 0,Db=void 0,vc=void 0,Pb=void 0,Qb=void 0,Rb=void 0,Ic=void 0,Sb=void 0,Tb=void 0,Ub=void 0,Jc=void 0,la=void 0,id=void 0,Vb=void 0,mc=void 0,nc=void 0,Ma=void 0,jd=void 0,Ha=void 0,Ia=void 0,Wb=void 0,Ib=void 0,Aa=0,Da=0,Jb=0,Kb=0,gb=0,Ra=0,pa=0,Ua=0,Ba=0,J=0,da=0,z=0,ab=void 0,Na=fa.__vertexArray,wc=fa.__uvArray,xc=fa.__uv2Array,hb=fa.__normalArray,ta=fa.__tangentArray,Oa=fa.__colorArray,ua=fa.__skinVertexAArray,va=fa.__skinVertexBArray,wa=fa.__skinIndexArray,
+xa=fa.__skinWeightArray,Zc=fa.__morphTargetsArrays,$c=fa.__morphNormalsArrays,ad=fa.__webglCustomAttributesList,x=void 0,Eb=fa.__faceArray,bb=fa.__lineArray,Va=td.geometry,vd=Va.__dirtyElements,kd=Va.__dirtyUvs,wd=Va.__dirtyNormals,xd=Va.__dirtyTangents,yd=Va.__dirtyColors,zd=Va.__dirtyMorphTargets,cc=Va.vertices,ma=fa.faces3,na=fa.faces4,Ca=Va.faces,bd=Va.faceVertexUvs[0],cd=Va.faceVertexUvs[1],dc=Va.skinVerticesA,ec=Va.skinVerticesB,fc=Va.skinIndices,Xb=Va.skinWeights,Yb=Va.morphTargets,Kc=Va.morphNormals;
+if(Va.__dirtyVertices){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],W=cc[M.a].position,X=cc[M.b].position,Y=cc[M.c].position,Na[Da]=W.x,Na[Da+1]=W.y,Na[Da+2]=W.z,Na[Da+3]=X.x,Na[Da+4]=X.y,Na[Da+5]=X.z,Na[Da+6]=Y.x,Na[Da+7]=Y.y,Na[Da+8]=Y.z,Da+=9;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],W=cc[M.a].position,X=cc[M.b].position,Y=cc[M.c].position,oa=cc[M.d].position,Na[Da]=W.x,Na[Da+1]=W.y,Na[Da+2]=W.z,Na[Da+3]=X.x,Na[Da+4]=X.y,Na[Da+5]=X.z,Na[Da+6]=Y.x,Na[Da+7]=Y.y,Na[Da+8]=Y.z,Na[Da+9]=oa.x,Na[Da+10]=oa.y,
+Na[Da+11]=oa.z,Da+=12;l.bindBuffer(l.ARRAY_BUFFER,fa.__webglVertexBuffer);l.bufferData(l.ARRAY_BUFFER,Na,$a)}if(zd)for(Ma=0,jd=Yb.length;Ma<jd;Ma++){da=0;for(G=0,V=ma.length;G<V;G++){Wb=ma[G];M=Ca[Wb];W=Yb[Ma].vertices[M.a].position;X=Yb[Ma].vertices[M.b].position;Y=Yb[Ma].vertices[M.c].position;Ha=Zc[Ma];Ha[da]=W.x;Ha[da+1]=W.y;Ha[da+2]=W.z;Ha[da+3]=X.x;Ha[da+4]=X.y;Ha[da+5]=X.z;Ha[da+6]=Y.x;Ha[da+7]=Y.y;Ha[da+8]=Y.z;if(bc.morphNormals)Gc?(Ib=Kc[Ma].vertexNormals[Wb],sb=Ib.a,tb=Ib.b,ub=Ib.c):ub=
+tb=sb=Kc[Ma].faceNormals[Wb],Ia=$c[Ma],Ia[da]=sb.x,Ia[da+1]=sb.y,Ia[da+2]=sb.z,Ia[da+3]=tb.x,Ia[da+4]=tb.y,Ia[da+5]=tb.z,Ia[da+6]=ub.x,Ia[da+7]=ub.y,Ia[da+8]=ub.z;da+=9}for(G=0,V=na.length;G<V;G++){Wb=na[G];M=Ca[Wb];W=Yb[Ma].vertices[M.a].position;X=Yb[Ma].vertices[M.b].position;Y=Yb[Ma].vertices[M.c].position;oa=Yb[Ma].vertices[M.d].position;Ha=Zc[Ma];Ha[da]=W.x;Ha[da+1]=W.y;Ha[da+2]=W.z;Ha[da+3]=X.x;Ha[da+4]=X.y;Ha[da+5]=X.z;Ha[da+6]=Y.x;Ha[da+7]=Y.y;Ha[da+8]=Y.z;Ha[da+9]=oa.x;Ha[da+10]=oa.y;Ha[da+
+11]=oa.z;if(bc.morphNormals)Gc?(Ib=Kc[Ma].vertexNormals[Wb],sb=Ib.a,tb=Ib.b,ub=Ib.c,sc=Ib.d):sc=ub=tb=sb=Kc[Ma].faceNormals[Wb],Ia=$c[Ma],Ia[da]=sb.x,Ia[da+1]=sb.y,Ia[da+2]=sb.z,Ia[da+3]=tb.x,Ia[da+4]=tb.y,Ia[da+5]=tb.z,Ia[da+6]=ub.x,Ia[da+7]=ub.y,Ia[da+8]=ub.z,Ia[da+9]=sc.x,Ia[da+10]=sc.y,Ia[da+11]=sc.z;da+=12}l.bindBuffer(l.ARRAY_BUFFER,fa.__webglMorphTargetsBuffers[Ma]);l.bufferData(l.ARRAY_BUFFER,Zc[Ma],$a);bc.morphNormals&&(l.bindBuffer(l.ARRAY_BUFFER,fa.__webglMorphNormalsBuffers[Ma]),l.bufferData(l.ARRAY_BUFFER,
+$c[Ma],$a))}if(Xb.length){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],yb=Xb[M.a],zb=Xb[M.b],Ab=Xb[M.c],xa[J]=yb.x,xa[J+1]=yb.y,xa[J+2]=yb.z,xa[J+3]=yb.w,xa[J+4]=zb.x,xa[J+5]=zb.y,xa[J+6]=zb.z,xa[J+7]=zb.w,xa[J+8]=Ab.x,xa[J+9]=Ab.y,xa[J+10]=Ab.z,xa[J+11]=Ab.w,Bb=fc[M.a],Cb=fc[M.b],Db=fc[M.c],wa[J]=Bb.x,wa[J+1]=Bb.y,wa[J+2]=Bb.z,wa[J+3]=Bb.w,wa[J+4]=Cb.x,wa[J+5]=Cb.y,wa[J+6]=Cb.z,wa[J+7]=Cb.w,wa[J+8]=Db.x,wa[J+9]=Db.y,wa[J+10]=Db.z,wa[J+11]=Db.w,Pb=dc[M.a],Qb=dc[M.b],Rb=dc[M.c],ua[J]=Pb.x,ua[J+1]=Pb.y,
+ua[J+2]=Pb.z,ua[J+3]=1,ua[J+4]=Qb.x,ua[J+5]=Qb.y,ua[J+6]=Qb.z,ua[J+7]=1,ua[J+8]=Rb.x,ua[J+9]=Rb.y,ua[J+10]=Rb.z,ua[J+11]=1,Sb=ec[M.a],Tb=ec[M.b],Ub=ec[M.c],va[J]=Sb.x,va[J+1]=Sb.y,va[J+2]=Sb.z,va[J+3]=1,va[J+4]=Tb.x,va[J+5]=Tb.y,va[J+6]=Tb.z,va[J+7]=1,va[J+8]=Ub.x,va[J+9]=Ub.y,va[J+10]=Ub.z,va[J+11]=1,J+=12;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],yb=Xb[M.a],zb=Xb[M.b],Ab=Xb[M.c],uc=Xb[M.d],xa[J]=yb.x,xa[J+1]=yb.y,xa[J+2]=yb.z,xa[J+3]=yb.w,xa[J+4]=zb.x,xa[J+5]=zb.y,xa[J+6]=zb.z,xa[J+7]=zb.w,xa[J+8]=
+Ab.x,xa[J+9]=Ab.y,xa[J+10]=Ab.z,xa[J+11]=Ab.w,xa[J+12]=uc.x,xa[J+13]=uc.y,xa[J+14]=uc.z,xa[J+15]=uc.w,Bb=fc[M.a],Cb=fc[M.b],Db=fc[M.c],vc=fc[M.d],wa[J]=Bb.x,wa[J+1]=Bb.y,wa[J+2]=Bb.z,wa[J+3]=Bb.w,wa[J+4]=Cb.x,wa[J+5]=Cb.y,wa[J+6]=Cb.z,wa[J+7]=Cb.w,wa[J+8]=Db.x,wa[J+9]=Db.y,wa[J+10]=Db.z,wa[J+11]=Db.w,wa[J+12]=vc.x,wa[J+13]=vc.y,wa[J+14]=vc.z,wa[J+15]=vc.w,Pb=dc[M.a],Qb=dc[M.b],Rb=dc[M.c],Ic=dc[M.d],ua[J]=Pb.x,ua[J+1]=Pb.y,ua[J+2]=Pb.z,ua[J+3]=1,ua[J+4]=Qb.x,ua[J+5]=Qb.y,ua[J+6]=Qb.z,ua[J+7]=1,ua[J+
+8]=Rb.x,ua[J+9]=Rb.y,ua[J+10]=Rb.z,ua[J+11]=1,ua[J+12]=Ic.x,ua[J+13]=Ic.y,ua[J+14]=Ic.z,ua[J+15]=1,Sb=ec[M.a],Tb=ec[M.b],Ub=ec[M.c],Jc=ec[M.d],va[J]=Sb.x,va[J+1]=Sb.y,va[J+2]=Sb.z,va[J+3]=1,va[J+4]=Tb.x,va[J+5]=Tb.y,va[J+6]=Tb.z,va[J+7]=1,va[J+8]=Ub.x,va[J+9]=Ub.y,va[J+10]=Ub.z,va[J+11]=1,va[J+12]=Jc.x,va[J+13]=Jc.y,va[J+14]=Jc.z,va[J+15]=1,J+=16;0<J&&(l.bindBuffer(l.ARRAY_BUFFER,fa.__webglSkinVertexABuffer),l.bufferData(l.ARRAY_BUFFER,ua,$a),l.bindBuffer(l.ARRAY_BUFFER,fa.__webglSkinVertexBBuffer),
+l.bufferData(l.ARRAY_BUFFER,va,$a),l.bindBuffer(l.ARRAY_BUFFER,fa.__webglSkinIndicesBuffer),l.bufferData(l.ARRAY_BUFFER,wa,$a),l.bindBuffer(l.ARRAY_BUFFER,fa.__webglSkinWeightsBuffer),l.bufferData(l.ARRAY_BUFFER,xa,$a))}if(yd&&Yc){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],ob=M.vertexColors,Hc=M.color,3===ob.length&&Yc===THREE.VertexColors?(vb=ob[0],wb=ob[1],xb=ob[2]):xb=wb=vb=Hc,Oa[Ba]=vb.r,Oa[Ba+1]=vb.g,Oa[Ba+2]=vb.b,Oa[Ba+3]=wb.r,Oa[Ba+4]=wb.g,Oa[Ba+5]=wb.b,Oa[Ba+6]=xb.r,Oa[Ba+7]=xb.g,Oa[Ba+8]=xb.b,
+Ba+=9;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],ob=M.vertexColors,Hc=M.color,4===ob.length&&Yc===THREE.VertexColors?(vb=ob[0],wb=ob[1],xb=ob[2],tc=ob[3]):tc=xb=wb=vb=Hc,Oa[Ba]=vb.r,Oa[Ba+1]=vb.g,Oa[Ba+2]=vb.b,Oa[Ba+3]=wb.r,Oa[Ba+4]=wb.g,Oa[Ba+5]=wb.b,Oa[Ba+6]=xb.r,Oa[Ba+7]=xb.g,Oa[Ba+8]=xb.b,Oa[Ba+9]=tc.r,Oa[Ba+10]=tc.g,Oa[Ba+11]=tc.b,Ba+=12;0<Ba&&(l.bindBuffer(l.ARRAY_BUFFER,fa.__webglColorBuffer),l.bufferData(l.ARRAY_BUFFER,Oa,$a))}if(xd&&Va.hasTangents){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],Hb=
+M.vertexTangents,pb=Hb[0],qb=Hb[1],rb=Hb[2],ta[pa]=pb.x,ta[pa+1]=pb.y,ta[pa+2]=pb.z,ta[pa+3]=pb.w,ta[pa+4]=qb.x,ta[pa+5]=qb.y,ta[pa+6]=qb.z,ta[pa+7]=qb.w,ta[pa+8]=rb.x,ta[pa+9]=rb.y,ta[pa+10]=rb.z,ta[pa+11]=rb.w,pa+=12;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],Hb=M.vertexTangents,pb=Hb[0],qb=Hb[1],rb=Hb[2],rc=Hb[3],ta[pa]=pb.x,ta[pa+1]=pb.y,ta[pa+2]=pb.z,ta[pa+3]=pb.w,ta[pa+4]=qb.x,ta[pa+5]=qb.y,ta[pa+6]=qb.z,ta[pa+7]=qb.w,ta[pa+8]=rb.x,ta[pa+9]=rb.y,ta[pa+10]=rb.z,ta[pa+11]=rb.w,ta[pa+12]=rc.x,ta[pa+
+13]=rc.y,ta[pa+14]=rc.z,ta[pa+15]=rc.w,pa+=16;l.bindBuffer(l.ARRAY_BUFFER,fa.__webglTangentBuffer);l.bufferData(l.ARRAY_BUFFER,ta,$a)}if(wd&&gd){for(G=0,V=ma.length;G<V;G++)if(M=Ca[ma[G]],jc=M.vertexNormals,Ob=M.normal,3===jc.length&&Gc)for(la=0;3>la;la++)Vb=jc[la],hb[Ra]=Vb.x,hb[Ra+1]=Vb.y,hb[Ra+2]=Vb.z,Ra+=3;else for(la=0;3>la;la++)hb[Ra]=Ob.x,hb[Ra+1]=Ob.y,hb[Ra+2]=Ob.z,Ra+=3;for(G=0,V=na.length;G<V;G++)if(M=Ca[na[G]],jc=M.vertexNormals,Ob=M.normal,4===jc.length&&Gc)for(la=0;4>la;la++)Vb=jc[la],
+hb[Ra]=Vb.x,hb[Ra+1]=Vb.y,hb[Ra+2]=Vb.z,Ra+=3;else for(la=0;4>la;la++)hb[Ra]=Ob.x,hb[Ra+1]=Ob.y,hb[Ra+2]=Ob.z,Ra+=3;l.bindBuffer(l.ARRAY_BUFFER,fa.__webglNormalBuffer);l.bufferData(l.ARRAY_BUFFER,hb,$a)}if(kd&&bd&&hd){for(G=0,V=ma.length;G<V;G++)if(kb=ma[G],M=Ca[kb],kc=bd[kb],void 0!==kc)for(la=0;3>la;la++)mc=kc[la],wc[Jb]=mc.u,wc[Jb+1]=mc.v,Jb+=2;for(G=0,V=na.length;G<V;G++)if(kb=na[G],M=Ca[kb],kc=bd[kb],void 0!==kc)for(la=0;4>la;la++)mc=kc[la],wc[Jb]=mc.u,wc[Jb+1]=mc.v,Jb+=2;0<Jb&&(l.bindBuffer(l.ARRAY_BUFFER,
+fa.__webglUVBuffer),l.bufferData(l.ARRAY_BUFFER,wc,$a))}if(kd&&cd&&hd){for(G=0,V=ma.length;G<V;G++)if(kb=ma[G],M=Ca[kb],lc=cd[kb],void 0!==lc)for(la=0;3>la;la++)nc=lc[la],xc[Kb]=nc.u,xc[Kb+1]=nc.v,Kb+=2;for(G=0,V=na.length;G<V;G++)if(kb=na[G],M=Ca[kb],lc=cd[kb],void 0!==lc)for(la=0;4>la;la++)nc=lc[la],xc[Kb]=nc.u,xc[Kb+1]=nc.v,Kb+=2;0<Kb&&(l.bindBuffer(l.ARRAY_BUFFER,fa.__webglUV2Buffer),l.bufferData(l.ARRAY_BUFFER,xc,$a))}if(vd){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],Eb[gb]=Aa,Eb[gb+1]=Aa+1,Eb[gb+
+2]=Aa+2,gb+=3,bb[Ua]=Aa,bb[Ua+1]=Aa+1,bb[Ua+2]=Aa,bb[Ua+3]=Aa+2,bb[Ua+4]=Aa+1,bb[Ua+5]=Aa+2,Ua+=6,Aa+=3;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],Eb[gb]=Aa,Eb[gb+1]=Aa+1,Eb[gb+2]=Aa+3,Eb[gb+3]=Aa+1,Eb[gb+4]=Aa+2,Eb[gb+5]=Aa+3,gb+=6,bb[Ua]=Aa,bb[Ua+1]=Aa+1,bb[Ua+2]=Aa,bb[Ua+3]=Aa+3,bb[Ua+4]=Aa+1,bb[Ua+5]=Aa+2,bb[Ua+6]=Aa+2,bb[Ua+7]=Aa+3,Ua+=8,Aa+=4;l.bindBuffer(l.ELEMENT_ARRAY_BUFFER,fa.__webglFaceBuffer);l.bufferData(l.ELEMENT_ARRAY_BUFFER,Eb,$a);l.bindBuffer(l.ELEMENT_ARRAY_BUFFER,fa.__webglLineBuffer);
+l.bufferData(l.ELEMENT_ARRAY_BUFFER,bb,$a)}if(ad)for(la=0,id=ad.length;la<id;la++)if(x=ad[la],x.__original.needsUpdate){z=0;if(1===x.size)if(void 0===x.boundTo||"vertices"===x.boundTo){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],x.array[z]=x.value[M.a],x.array[z+1]=x.value[M.b],x.array[z+2]=x.value[M.c],z+=3;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],x.array[z]=x.value[M.a],x.array[z+1]=x.value[M.b],x.array[z+2]=x.value[M.c],x.array[z+3]=x.value[M.d],z+=4}else{if("faces"===x.boundTo){for(G=0,V=ma.length;G<
+V;G++)ab=x.value[ma[G]],x.array[z]=ab,x.array[z+1]=ab,x.array[z+2]=ab,z+=3;for(G=0,V=na.length;G<V;G++)ab=x.value[na[G]],x.array[z]=ab,x.array[z+1]=ab,x.array[z+2]=ab,x.array[z+3]=ab,z+=4}}else if(2===x.size)if(void 0===x.boundTo||"vertices"===x.boundTo){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],W=x.value[M.a],X=x.value[M.b],Y=x.value[M.c],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=X.x,x.array[z+3]=X.y,x.array[z+4]=Y.x,x.array[z+5]=Y.y,z+=6;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],W=x.value[M.a],X=
+x.value[M.b],Y=x.value[M.c],oa=x.value[M.d],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=X.x,x.array[z+3]=X.y,x.array[z+4]=Y.x,x.array[z+5]=Y.y,x.array[z+6]=oa.x,x.array[z+7]=oa.y,z+=8}else{if("faces"===x.boundTo){for(G=0,V=ma.length;G<V;G++)Y=X=W=ab=x.value[ma[G]],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=X.x,x.array[z+3]=X.y,x.array[z+4]=Y.x,x.array[z+5]=Y.y,z+=6;for(G=0,V=na.length;G<V;G++)oa=Y=X=W=ab=x.value[na[G]],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=X.x,x.array[z+3]=X.y,x.array[z+
+4]=Y.x,x.array[z+5]=Y.y,x.array[z+6]=oa.x,x.array[z+7]=oa.y,z+=8}}else if(3===x.size){var ga;ga="c"===x.type?["r","g","b"]:["x","y","z"];if(void 0===x.boundTo||"vertices"===x.boundTo){for(G=0,V=ma.length;G<V;G++)M=Ca[ma[G]],W=x.value[M.a],X=x.value[M.b],Y=x.value[M.c],x.array[z]=W[ga[0]],x.array[z+1]=W[ga[1]],x.array[z+2]=W[ga[2]],x.array[z+3]=X[ga[0]],x.array[z+4]=X[ga[1]],x.array[z+5]=X[ga[2]],x.array[z+6]=Y[ga[0]],x.array[z+7]=Y[ga[1]],x.array[z+8]=Y[ga[2]],z+=9;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],
+W=x.value[M.a],X=x.value[M.b],Y=x.value[M.c],oa=x.value[M.d],x.array[z]=W[ga[0]],x.array[z+1]=W[ga[1]],x.array[z+2]=W[ga[2]],x.array[z+3]=X[ga[0]],x.array[z+4]=X[ga[1]],x.array[z+5]=X[ga[2]],x.array[z+6]=Y[ga[0]],x.array[z+7]=Y[ga[1]],x.array[z+8]=Y[ga[2]],x.array[z+9]=oa[ga[0]],x.array[z+10]=oa[ga[1]],x.array[z+11]=oa[ga[2]],z+=12}else if("faces"===x.boundTo){for(G=0,V=ma.length;G<V;G++)Y=X=W=ab=x.value[ma[G]],x.array[z]=W[ga[0]],x.array[z+1]=W[ga[1]],x.array[z+2]=W[ga[2]],x.array[z+3]=X[ga[0]],
+x.array[z+4]=X[ga[1]],x.array[z+5]=X[ga[2]],x.array[z+6]=Y[ga[0]],x.array[z+7]=Y[ga[1]],x.array[z+8]=Y[ga[2]],z+=9;for(G=0,V=na.length;G<V;G++)oa=Y=X=W=ab=x.value[na[G]],x.array[z]=W[ga[0]],x.array[z+1]=W[ga[1]],x.array[z+2]=W[ga[2]],x.array[z+3]=X[ga[0]],x.array[z+4]=X[ga[1]],x.array[z+5]=X[ga[2]],x.array[z+6]=Y[ga[0]],x.array[z+7]=Y[ga[1]],x.array[z+8]=Y[ga[2]],x.array[z+9]=oa[ga[0]],x.array[z+10]=oa[ga[1]],x.array[z+11]=oa[ga[2]],z+=12}}else if(4===x.size)if(void 0===x.boundTo||"vertices"===x.boundTo){for(G=
+0,V=ma.length;G<V;G++)M=Ca[ma[G]],W=x.value[M.a],X=x.value[M.b],Y=x.value[M.c],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=W.z,x.array[z+3]=W.w,x.array[z+4]=X.x,x.array[z+5]=X.y,x.array[z+6]=X.z,x.array[z+7]=X.w,x.array[z+8]=Y.x,x.array[z+9]=Y.y,x.array[z+10]=Y.z,x.array[z+11]=Y.w,z+=12;for(G=0,V=na.length;G<V;G++)M=Ca[na[G]],W=x.value[M.a],X=x.value[M.b],Y=x.value[M.c],oa=x.value[M.d],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=W.z,x.array[z+3]=W.w,x.array[z+4]=X.x,x.array[z+5]=X.y,x.array[z+6]=
+X.z,x.array[z+7]=X.w,x.array[z+8]=Y.x,x.array[z+9]=Y.y,x.array[z+10]=Y.z,x.array[z+11]=Y.w,x.array[z+12]=oa.x,x.array[z+13]=oa.y,x.array[z+14]=oa.z,x.array[z+15]=oa.w,z+=16}else if("faces"===x.boundTo){for(G=0,V=ma.length;G<V;G++)Y=X=W=ab=x.value[ma[G]],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=W.z,x.array[z+3]=W.w,x.array[z+4]=X.x,x.array[z+5]=X.y,x.array[z+6]=X.z,x.array[z+7]=X.w,x.array[z+8]=Y.x,x.array[z+9]=Y.y,x.array[z+10]=Y.z,x.array[z+11]=Y.w,z+=12;for(G=0,V=na.length;G<V;G++)oa=Y=X=W=
+ab=x.value[na[G]],x.array[z]=W.x,x.array[z+1]=W.y,x.array[z+2]=W.z,x.array[z+3]=W.w,x.array[z+4]=X.x,x.array[z+5]=X.y,x.array[z+6]=X.z,x.array[z+7]=X.w,x.array[z+8]=Y.x,x.array[z+9]=Y.y,x.array[z+10]=Y.z,x.array[z+11]=Y.w,x.array[z+12]=oa.x,x.array[z+13]=oa.y,x.array[z+14]=oa.z,x.array[z+15]=oa.w,z+=16}l.bindBuffer(l.ARRAY_BUFFER,x.buffer);l.bufferData(l.ARRAY_BUFFER,x.array,$a)}ud&&(delete fa.__inittedArrays,delete fa.__colorArray,delete fa.__normalArray,delete fa.__tangentArray,delete fa.__uvArray,
+delete fa.__uv2Array,delete fa.__faceArray,delete fa.__vertexArray,delete fa.__lineArray,delete fa.__skinVertexAArray,delete fa.__skinVertexBArray,delete fa.__skinIndexArray,delete fa.__skinWeightArray)}}ja.__dirtyVertices=!1;ja.__dirtyMorphTargets=!1;ja.__dirtyElements=!1;ja.__dirtyUvs=!1;ja.__dirtyNormals=!1;ja.__dirtyColors=!1;ja.__dirtyTangents=!1;Xa.attributes&&m(Xa)}else if(nb instanceof THREE.Ribbon){if(ja.__dirtyVertices||ja.__dirtyColors){var Zb=ja,ld=l.DYNAMIC_DRAW,yc=void 0,zc=void 0,Lc=
+void 0,$b=void 0,Mc=void 0,md=Zb.vertices,nd=Zb.colors,Ad=md.length,Bd=nd.length,Nc=Zb.__vertexArray,Oc=Zb.__colorArray,Cd=Zb.__dirtyColors;if(Zb.__dirtyVertices){for(yc=0;yc<Ad;yc++)Lc=md[yc].position,$b=3*yc,Nc[$b]=Lc.x,Nc[$b+1]=Lc.y,Nc[$b+2]=Lc.z;l.bindBuffer(l.ARRAY_BUFFER,Zb.__webglVertexBuffer);l.bufferData(l.ARRAY_BUFFER,Nc,ld)}if(Cd){for(zc=0;zc<Bd;zc++)Mc=nd[zc],$b=3*zc,Oc[$b]=Mc.r,Oc[$b+1]=Mc.g,Oc[$b+2]=Mc.b;l.bindBuffer(l.ARRAY_BUFFER,Zb.__webglColorBuffer);l.bufferData(l.ARRAY_BUFFER,
+Oc,ld)}}ja.__dirtyVertices=!1;ja.__dirtyColors=!1}else if(nb instanceof THREE.Line){Xa=c(nb,qc);ic=Xa.attributes&&q(Xa);if(ja.__dirtyVertices||ja.__dirtyColors||ic){var Lb=ja,dd=l.DYNAMIC_DRAW,Ac=void 0,Bc=void 0,Pc=void 0,ya=void 0,Qc=void 0,od=Lb.vertices,pd=Lb.colors,Dd=od.length,Ed=pd.length,Rc=Lb.__vertexArray,Sc=Lb.__colorArray,Fd=Lb.__dirtyColors,ed=Lb.__webglCustomAttributesList,Tc=void 0,qd=void 0,Qa=void 0,oc=void 0,Ya=void 0,ra=void 0;if(Lb.__dirtyVertices){for(Ac=0;Ac<Dd;Ac++)Pc=od[Ac].position,
+ya=3*Ac,Rc[ya]=Pc.x,Rc[ya+1]=Pc.y,Rc[ya+2]=Pc.z;l.bindBuffer(l.ARRAY_BUFFER,Lb.__webglVertexBuffer);l.bufferData(l.ARRAY_BUFFER,Rc,dd)}if(Fd){for(Bc=0;Bc<Ed;Bc++)Qc=pd[Bc],ya=3*Bc,Sc[ya]=Qc.r,Sc[ya+1]=Qc.g,Sc[ya+2]=Qc.b;l.bindBuffer(l.ARRAY_BUFFER,Lb.__webglColorBuffer);l.bufferData(l.ARRAY_BUFFER,Sc,dd)}if(ed)for(Tc=0,qd=ed.length;Tc<qd;Tc++)if(ra=ed[Tc],ra.needsUpdate&&(void 0===ra.boundTo||"vertices"===ra.boundTo)){ya=0;oc=ra.value.length;if(1===ra.size)for(Qa=0;Qa<oc;Qa++)ra.array[Qa]=ra.value[Qa];
+else if(2===ra.size)for(Qa=0;Qa<oc;Qa++)Ya=ra.value[Qa],ra.array[ya]=Ya.x,ra.array[ya+1]=Ya.y,ya+=2;else if(3===ra.size)if("c"===ra.type)for(Qa=0;Qa<oc;Qa++)Ya=ra.value[Qa],ra.array[ya]=Ya.r,ra.array[ya+1]=Ya.g,ra.array[ya+2]=Ya.b,ya+=3;else for(Qa=0;Qa<oc;Qa++)Ya=ra.value[Qa],ra.array[ya]=Ya.x,ra.array[ya+1]=Ya.y,ra.array[ya+2]=Ya.z,ya+=3;else if(4===ra.size)for(Qa=0;Qa<oc;Qa++)Ya=ra.value[Qa],ra.array[ya]=Ya.x,ra.array[ya+1]=Ya.y,ra.array[ya+2]=Ya.z,ra.array[ya+3]=Ya.w,ya+=4;l.bindBuffer(l.ARRAY_BUFFER,
+ra.buffer);l.bufferData(l.ARRAY_BUFFER,ra.array,dd)}}ja.__dirtyVertices=!1;ja.__dirtyColors=!1;Xa.attributes&&m(Xa)}else if(nb instanceof THREE.ParticleSystem)Xa=c(nb,qc),ic=Xa.attributes&&q(Xa),(ja.__dirtyVertices||ja.__dirtyColors||nb.sortParticles||ic)&&g(ja,l.DYNAMIC_DRAW,nb),ja.__dirtyVertices=!1,ja.__dirtyColors=!1,Xa.attributes&&m(Xa)}};this.initMaterial=function(a,b,c,d){var f,e,g,h,i;a instanceof THREE.MeshDepthMaterial?i="depth":a instanceof THREE.MeshNormalMaterial?i="normal":a instanceof
+THREE.MeshBasicMaterial?i="basic":a instanceof THREE.MeshLambertMaterial?i="lambert":a instanceof THREE.MeshPhongMaterial?i="phong":a instanceof THREE.LineBasicMaterial?i="basic":a instanceof THREE.ParticleBasicMaterial&&(i="particle_basic");if(i){var j=THREE.ShaderLib[i];a.uniforms=THREE.UniformsUtils.clone(j.uniforms);a.vertexShader=j.vertexShader;a.fragmentShader=j.fragmentShader}var k,m;e=j=0;for(k=0,m=b.length;k<m;k++)f=b[k],f.onlyShadow||(f instanceof THREE.DirectionalLight&&e++,f instanceof
+THREE.PointLight&&j++,f instanceof THREE.SpotLight&&j++);j+e<=O?k=e:(k=Math.ceil(O*e/(j+e)),j=O-k);f=k;e=j;var n=0;for(j=0,k=b.length;j<k;j++)m=b[j],m.castShadow&&(m instanceof THREE.SpotLight&&n++,m instanceof THREE.DirectionalLight&&!m.shadowCascade&&n++);var o=50;if(void 0!==d&&d instanceof THREE.SkinnedMesh)o=d.bones.length;var p;a:{k=a.fragmentShader;m=a.vertexShader;var j=a.uniforms,b=a.attributes,c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,
+sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:f,maxPointLights:e,maxBones:o,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,maxShadows:n,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:d&&d.doubleSided},
+q,d=[];i?d.push(i):(d.push(k),d.push(m));for(q in c)d.push(q),d.push(c[q]);i=d.join();for(q=0,d=$.length;q<d;q++)if($[q].code===i){p=$[q].program;break a}q=l.createProgram();d=[0<za?"#define VERTEX_TEXTURES":"",y.gammaInput?"#define GAMMA_INPUT":"",y.gammaOutput?"#define GAMMA_OUTPUT":"",y.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,
+c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":
+"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
+f=["precision "+B+" float;","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",y.gammaInput?"#define GAMMA_INPUT":"",y.gammaOutput?"#define GAMMA_OUTPUT":"",y.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?
+"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");l.attachShader(q,t("fragment",f+k));
+l.attachShader(q,t("vertex",d+m));l.linkProgram(q);l.getProgramParameter(q,l.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+l.getProgramParameter(q,l.VALIDATE_STATUS)+", gl error ["+l.getError()+"]");q.uniforms={};q.attributes={};var r,d="viewMatrix,modelViewMatrix,projectionMatrix,normalMatrix,objectMatrix,cameraPosition,boneGlobalMatrices,morphTargetInfluences".split(",");for(r in j)d.push(r);r=d;for(d=0,j=r.length;d<j;d++)k=r[d],q.uniforms[k]=l.getUniformLocation(q,
+k);d="position,normal,uv,uv2,tangent,color,skinVertexA,skinVertexB,skinIndex,skinWeight".split(",");for(r=0;r<c.maxMorphTargets;r++)d.push("morphTarget"+r);for(r=0;r<c.maxMorphNormals;r++)d.push("morphNormal"+r);for(p in b)d.push(p);p=d;for(r=0,b=p.length;r<b;r++)c=p[r],q.attributes[c]=l.getAttribLocation(q,c);q.id=$.length;$.push({program:q,code:i});y.info.memory.programs=$.length;p=q}a.program=p;p=a.program.attributes;0<=p.position&&l.enableVertexAttribArray(p.position);0<=p.color&&l.enableVertexAttribArray(p.color);
+0<=p.normal&&l.enableVertexAttribArray(p.normal);0<=p.tangent&&l.enableVertexAttribArray(p.tangent);a.skinning&&0<=p.skinVertexA&&0<=p.skinVertexB&&0<=p.skinIndex&&0<=p.skinWeight&&(l.enableVertexAttribArray(p.skinVertexA),l.enableVertexAttribArray(p.skinVertexB),l.enableVertexAttribArray(p.skinIndex),l.enableVertexAttribArray(p.skinWeight));if(a.attributes)for(h in a.attributes)void 0!==p[h]&&0<=p[h]&&l.enableVertexAttribArray(p[h]);if(a.morphTargets){a.numSupportedMorphTargets=0;q="morphTarget";
+for(h=0;h<this.maxMorphTargets;h++)r=q+h,0<=p[r]&&(l.enableVertexAttribArray(p[r]),a.numSupportedMorphTargets++)}if(a.morphNormals){a.numSupportedMorphNormals=0;q="morphNormal";for(h=0;h<this.maxMorphNormals;h++)r=q+h,0<=p[r]&&(l.enableVertexAttribArray(p[r]),a.numSupportedMorphNormals++)}a.uniformsList=[];for(g in a.uniforms)a.uniformsList.push([a.uniforms[g],g])};this.setFaceCulling=function(a,b){a?(!b||"ccw"===b?l.frontFace(l.CCW):l.frontFace(l.CW),"back"===a?l.cullFace(l.BACK):"front"===a?l.cullFace(l.FRONT):
+l.cullFace(l.FRONT_AND_BACK),l.enable(l.CULL_FACE)):l.disable(l.CULL_FACE)};this.setObjectFaces=function(a){if(ia!==a.doubleSided)a.doubleSided?l.disable(l.CULL_FACE):l.enable(l.CULL_FACE),ia=a.doubleSided;if(N!==a.flipSided)a.flipSided?l.frontFace(l.CW):l.frontFace(l.CCW),N=a.flipSided};this.setDepthTest=function(a){U!==a&&(a?l.enable(l.DEPTH_TEST):l.disable(l.DEPTH_TEST),U=a)};this.setDepthWrite=function(a){ba!==a&&(l.depthMask(a),ba=a)};this.setBlending=function(a){if(a!==aa){switch(a){case THREE.NoBlending:l.disable(l.BLEND);
+break;case THREE.AdditiveBlending:l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.SRC_ALPHA,l.ONE);break;case THREE.SubtractiveBlending:l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.ZERO,l.ONE_MINUS_SRC_COLOR);break;case THREE.MultiplyBlending:l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.ZERO,l.SRC_COLOR);break;default:l.enable(l.BLEND),l.blendEquationSeparate(l.FUNC_ADD,l.FUNC_ADD),l.blendFuncSeparate(l.SRC_ALPHA,l.ONE_MINUS_SRC_ALPHA,l.ONE,l.ONE_MINUS_SRC_ALPHA)}aa=
+a}};this.setTexture=function(a,b){if(a.needsUpdate){if(!a.__webglInit)a.__webglInit=!0,a.__webglTexture=l.createTexture(),y.info.memory.textures++;l.activeTexture(l.TEXTURE0+b);l.bindTexture(l.TEXTURE_2D,a.__webglTexture);var c=a.image,d=0===(c.width&c.width-1)&&0===(c.height&c.height-1),f=A(a.format),e=A(a.type);w(l.TEXTURE_2D,a,d);a instanceof THREE.DataTexture?l.texImage2D(l.TEXTURE_2D,0,f,c.width,c.height,0,f,e,c.data):l.texImage2D(l.TEXTURE_2D,0,f,f,e,a.image);a.generateMipmaps&&d&&l.generateMipmap(l.TEXTURE_2D);
+a.needsUpdate=!1;if(a.onUpdate)a.onUpdate()}else l.activeTexture(l.TEXTURE0+b),l.bindTexture(l.TEXTURE_2D,a.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&!a.__webglFramebuffer){if(void 0===a.depthBuffer)a.depthBuffer=!0;if(void 0===a.stencilBuffer)a.stencilBuffer=!0;a.__webglTexture=l.createTexture();var c=0===(a.width&a.width-1)&&0===(a.height&a.height-1),d=A(a.format),f=A(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];l.bindTexture(l.TEXTURE_CUBE_MAP,
+a.__webglTexture);w(l.TEXTURE_CUBE_MAP,a,c);for(c=0;6>c;c++){a.__webglFramebuffer[c]=l.createFramebuffer();a.__webglRenderbuffer[c]=l.createRenderbuffer();l.texImage2D(l.TEXTURE_CUBE_MAP_POSITIVE_X+c,0,d,a.width,a.height,0,d,f,null);var e=a,g=l.TEXTURE_CUBE_MAP_POSITIVE_X+c;l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer[c]);l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,g,e.__webglTexture,0);u(a.__webglRenderbuffer[c],a)}}else a.__webglFramebuffer=l.createFramebuffer(),a.__webglRenderbuffer=
+l.createRenderbuffer(),l.bindTexture(l.TEXTURE_2D,a.__webglTexture),w(l.TEXTURE_2D,a,c),l.texImage2D(l.TEXTURE_2D,0,d,a.width,a.height,0,d,f,null),d=l.TEXTURE_2D,l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer),l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,d,a.__webglTexture,0),u(a.__webglRenderbuffer,a);b?l.bindTexture(l.TEXTURE_CUBE_MAP,null):l.bindTexture(l.TEXTURE_2D,null);l.bindRenderbuffer(l.RENDERBUFFER,null);l.bindFramebuffer(l.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:
+a.__webglFramebuffer,d=a.width,a=a.height,c=f=0):(b=null,d=ha,a=ib,f=Ga,c=qa);b!==E&&(l.bindFramebuffer(l.FRAMEBUFFER,b),l.viewport(f,c,d,a),E=b);db=d;lb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};
+THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format:THREE.RGBAFormat;this.type=void 0!==c.type?c.type:
+THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0};
+THREE.WebGLRenderTarget.prototype.clone=function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;return a};THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};
+THREE.WebGLRenderTargetCube.prototype=new THREE.WebGLRenderTarget;THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube;THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};
+THREE.RenderableFace3=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null};
+THREE.RenderableFace4=function(){this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.v4=new THREE.RenderableVertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.faceMaterial=this.material=null;this.uvs=[[]];this.z=null};THREE.RenderableObject=function(){this.z=this.object=null};
+THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.material=null};
+THREE.ColorUtils={adjustHSV:function(a,b,c,d){var f=THREE.ColorUtils.__hsv;THREE.ColorUtils.rgbToHsv(a,f);f.h=THREE.Math.clamp(f.h+b,0,1);f.s=THREE.Math.clamp(f.s+c,0,1);f.v=THREE.Math.clamp(f.v+d,0,1);a.setHSV(f.h,f.s,f.v)},rgbToHsv:function(a,b){var c=a.r,d=a.g,f=a.b,g=Math.max(Math.max(c,d),f),e=Math.min(Math.min(c,d),f);if(e===g)e=c=0;else{var h=g-e,e=h/g,c=(c===g?(d-f)/h:d===g?2+(f-c)/h:4+(c-d)/h)/6;0>c&&(c+=1);1<c&&(c-=1)}void 0===b&&(b={h:0,s:0,v:0});b.h=c;b.s=e;b.v=g;return b}};
+THREE.ColorUtils.__hsv={h:0,s:0,v:0};
+THREE.GeometryUtils={merge:function(a,b){for(var c,d,f=a.vertices.length,g=b instanceof THREE.Mesh?b.geometry:b,e=a.vertices,h=g.vertices,i=a.faces,j=g.faces,k=a.faceVertexUvs[0],q=g.faceVertexUvs[0],m={},o=0;o<a.materials.length;o++)m[a.materials[o].id]=o;if(b instanceof THREE.Mesh)b.matrixAutoUpdate&&b.updateMatrix(),c=b.matrix,d=new THREE.Matrix4,d.extractRotation(c,b.scale);for(var o=0,p=h.length;o<p;o++){var n=h[o].clone();c&&c.multiplyVector3(n.position);e.push(n)}for(o=0,p=j.length;o<p;o++){var e=
+j[o],r,s,t=e.vertexNormals,w=e.vertexColors;e instanceof THREE.Face3?r=new THREE.Face3(e.a+f,e.b+f,e.c+f):e instanceof THREE.Face4&&(r=new THREE.Face4(e.a+f,e.b+f,e.c+f,e.d+f));r.normal.copy(e.normal);d&&d.multiplyVector3(r.normal);h=0;for(n=t.length;h<n;h++)s=t[h].clone(),d&&d.multiplyVector3(s),r.vertexNormals.push(s);r.color.copy(e.color);h=0;for(n=w.length;h<n;h++)s=w[h],r.vertexColors.push(s.clone());if(void 0!==e.materialIndex){h=g.materials[e.materialIndex];n=h.id;w=m[n];if(void 0===w)w=a.materials.length,
+m[n]=w,a.materials.push(h);r.materialIndex=w}r.centroid.copy(e.centroid);c&&c.multiplyVector3(r.centroid);i.push(r)}for(o=0,p=q.length;o<p;o++){c=q[o];d=[];h=0;for(n=c.length;h<n;h++)d.push(new THREE.UV(c[h].u,c[h].v));k.push(d)}},clone:function(a){var b=new THREE.Geometry,c,d=a.vertices,f=a.faces,g=a.faceVertexUvs[0];if(a.materials)b.materials=a.materials.slice();for(a=0,c=d.length;a<c;a++)b.vertices.push(d[a].clone());for(a=0,c=f.length;a<c;a++)b.faces.push(f[a].clone());for(a=0,c=g.length;a<c;a++){for(var d=
+g[a],f=[],e=0,h=d.length;e<h;e++)f.push(new THREE.UV(d[e].u,d[e].v));b.faceVertexUvs[0].push(f)}return b},randomPointInTriangle:function(a,b,c){var d,f,g,e=new THREE.Vector3,h=THREE.GeometryUtils.__v1;d=THREE.GeometryUtils.random();f=THREE.GeometryUtils.random();1<d+f&&(d=1-d,f=1-f);g=1-d-f;e.copy(a);e.multiplyScalar(d);h.copy(b);h.multiplyScalar(f);e.addSelf(h);h.copy(c);h.multiplyScalar(g);e.addSelf(h);return e},randomPointInFace:function(a,b,c){var d,f,g;if(a instanceof THREE.Face3)return d=b.vertices[a.a].position,
+f=b.vertices[a.b].position,g=b.vertices[a.c].position,THREE.GeometryUtils.randomPointInTriangle(d,f,g);if(a instanceof THREE.Face4){d=b.vertices[a.a].position;f=b.vertices[a.b].position;g=b.vertices[a.c].position;var b=b.vertices[a.d].position,e;c?a._area1&&a._area2?(c=a._area1,e=a._area2):(c=THREE.GeometryUtils.triangleArea(d,f,b),e=THREE.GeometryUtils.triangleArea(f,g,b),a._area1=c,a._area2=e):(c=THREE.GeometryUtils.triangleArea(d,f,b),e=THREE.GeometryUtils.triangleArea(f,g,b));return THREE.GeometryUtils.random()*
+(c+e)<c?THREE.GeometryUtils.randomPointInTriangle(d,f,b):THREE.GeometryUtils.randomPointInTriangle(f,g,b)}},randomPointsInGeometry:function(a,b){function c(a){function b(c,d){if(d<c)return c;var f=c+Math.floor((d-c)/2);return j[f]>a?b(c,f-1):j[f]<a?b(f+1,d):f}return b(0,j.length-1)}var d,f,g=a.faces,e=a.vertices,h=g.length,i=0,j=[],k,q,m,o;for(f=0;f<h;f++){d=g[f];if(d instanceof THREE.Face3)k=e[d.a].position,q=e[d.b].position,m=e[d.c].position,d._area=THREE.GeometryUtils.triangleArea(k,q,m);else if(d instanceof
+THREE.Face4)k=e[d.a].position,q=e[d.b].position,m=e[d.c].position,o=e[d.d].position,d._area1=THREE.GeometryUtils.triangleArea(k,q,o),d._area2=THREE.GeometryUtils.triangleArea(q,m,o),d._area=d._area1+d._area2;i+=d._area;j[f]=i}d=[];for(f=0;f<b;f++)e=THREE.GeometryUtils.random()*i,e=c(e),d[f]=THREE.GeometryUtils.randomPointInFace(g[e],a,!0);return d},triangleArea:function(a,b,c){var d,f=THREE.GeometryUtils.__v1;f.sub(a,b);d=f.length();f.sub(a,c);a=f.length();f.sub(b,c);c=f.length();b=0.5*(d+a+c);return Math.sqrt(b*
+(b-d)*(b-a)*(b-c))},center:function(a){a.computeBoundingBox();var b=a.boundingBox,c=new THREE.Vector3;c.add(b.min,b.max);c.multiplyScalar(-0.5);a.applyMatrix((new THREE.Matrix4).setTranslation(c.x,c.y,c.z));a.computeBoundingBox();return c},normalizeUVs:function(a){for(var a=a.faceVertexUvs[0],b=0,c=a.length;b<c;b++)for(var d=a[b],f=0,g=d.length;f<g;f++)1!==d[f].u&&(d[f].u-=Math.floor(d[f].u)),1!==d[f].v&&(d[f].v-=Math.floor(d[f].v))},triangulateQuads:function(a){for(var b=a.faces.length-1;0<=b;b--){var c=
+a.faces[b];if(c instanceof THREE.Face4){var d=c.a,f=c.b,g=c.c,e=c.d,h=c.clone(),c=c.clone();h.a=d;h.b=f;h.c=e;c.a=f;c.b=g;c.c=e;a.faces.splice(b,1,h,c);for(d=0;d<a.faceVertexUvs.length;d++)a.faceVertexUvs[d].length&&(h=a.faceVertexUvs[d][b],f=h[1],g=h[2],e=h[3],h=[h[0].clone(),f.clone(),e.clone()],f=[f.clone(),g.clone(),e.clone()],a.faceVertexUvs[d].splice(b,1,h,f));for(d=0;d<a.faceUvs.length;d++)a.faceUvs[d].length&&(f=a.faceUvs[d][b],a.faceUvs[d].splice(b,1,f,f))}}a.computeCentroids();a.computeFaceNormals();
+a.computeVertexNormals();a.hasTangents&&a.computeTangents()},explode:function(a){for(var b=[],c=0,d=a.faces.length;c<d;c++){var f=b.length,g=a.faces[c];if(g instanceof THREE.Face4){var e=g.a,h=g.b,i=g.c,e=a.vertices[e],h=a.vertices[h],i=a.vertices[i],j=a.vertices[g.d];b.push(e.clone());b.push(h.clone());b.push(i.clone());b.push(j.clone());g.a=f;g.b=f+1;g.c=f+2;g.d=f+3}else e=g.a,h=g.b,i=g.c,e=a.vertices[e],h=a.vertices[h],i=a.vertices[i],b.push(e.clone()),b.push(h.clone()),b.push(i.clone()),g.a=f,
+g.b=f+1,g.c=f+2}a.vertices=b},tessellate:function(a,b){var c,d,f,g,e,h,i,j,k,q,m,o,p,n,r,s,t;for(c=a.faces.length-1;0<=c;c--)if(d=a.faces[c],d instanceof THREE.Face3){if(f=d.a,g=d.b,e=d.c,i=a.vertices[f],j=a.vertices[g],k=a.vertices[e],m=i.position.distanceTo(j.position),o=j.position.distanceTo(k.position),q=i.position.distanceTo(k.position),m>b||o>b||q>b){h=a.vertices.length;t=d.clone();d=d.clone();m>=o&&m>=q?(i=i.clone(),i.position.lerpSelf(j.position,0.5),t.a=f,t.b=h,t.c=e,d.a=h,d.b=g,d.c=e,f=
+0):o>=m&&o>=q?(i=j.clone(),i.position.lerpSelf(k.position,0.5),t.a=f,t.b=g,t.c=h,d.a=h,d.b=e,d.c=f,f=1):(i=i.clone(),i.position.lerpSelf(k.position,0.5),t.a=f,t.b=g,t.c=h,d.a=h,d.b=g,d.c=e,f=2);a.faces.splice(c,1,t,d);a.vertices.push(i);for(g=0;g<a.faceVertexUvs.length;g++)a.faceVertexUvs[g].length&&(k=a.faceVertexUvs[g][c],j=k[0],e=k[1],i=k[2],0===f?(m=j.clone(),m.lerpSelf(e,0.5),k=[j.clone(),m.clone(),i.clone()],e=[m.clone(),e.clone(),i.clone()]):1===f?(m=e.clone(),m.lerpSelf(i,0.5),k=[j.clone(),
+e.clone(),m.clone()],e=[m.clone(),i.clone(),j.clone()]):(m=j.clone(),m.lerpSelf(i,0.5),k=[j.clone(),e.clone(),m.clone()],e=[m.clone(),e.clone(),i.clone()]),a.faceVertexUvs[g].splice(c,1,k,e))}}else if(f=d.a,g=d.b,e=d.c,h=d.d,i=a.vertices[f],j=a.vertices[g],k=a.vertices[e],q=a.vertices[h],m=i.position.distanceTo(j.position),o=j.position.distanceTo(k.position),p=k.position.distanceTo(q.position),n=i.position.distanceTo(q.position),m>b||o>b||p>b||n>b){r=a.vertices.length;s=a.vertices.length+1;t=d.clone();
+d=d.clone();m>=o&&m>=p&&m>=n||p>=o&&p>=m&&p>=n?(m=i.clone(),m.position.lerpSelf(j.position,0.5),j=k.clone(),j.position.lerpSelf(q.position,0.5),t.a=f,t.b=r,t.c=s,t.d=h,d.a=r,d.b=g,d.c=e,d.d=s,f=0):(m=j.clone(),m.position.lerpSelf(k.position,0.5),j=q.clone(),j.position.lerpSelf(i.position,0.5),t.a=f,t.b=g,t.c=r,t.d=s,d.a=s,d.b=r,d.c=e,d.d=h,f=1);a.faces.splice(c,1,t,d);a.vertices.push(m);a.vertices.push(j);for(g=0;g<a.faceVertexUvs.length;g++)a.faceVertexUvs[g].length&&(k=a.faceVertexUvs[g][c],j=k[0],
+e=k[1],i=k[2],k=k[3],0===f?(m=j.clone(),m.lerpSelf(e,0.5),o=i.clone(),o.lerpSelf(k,0.5),j=[j.clone(),m.clone(),o.clone(),k.clone()],e=[m.clone(),e.clone(),i.clone(),o.clone()]):(m=e.clone(),m.lerpSelf(i,0.5),o=k.clone(),o.lerpSelf(j,0.5),j=[j.clone(),e.clone(),m.clone(),o.clone()],e=[o.clone(),m.clone(),i.clone(),k.clone()]),a.faceVertexUvs[g].splice(c,1,j,e))}}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.GeometryUtils.__v1=new THREE.Vector3;
+THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(a,b,c){var d=new Image,f=new THREE.Texture(d,b);d.onload=function(){f.needsUpdate=!0;c&&c(this)};d.crossOrigin=this.crossOrigin;d.src=a;return f},loadTextureCube:function(a,b,c){var d,f=[],g=new THREE.Texture(f,b);f.loadCount=0;for(b=0,d=a.length;b<d;++b)f[b]=new Image,f[b].onload=function(){f.loadCount+=1;if(6===f.loadCount)g.needsUpdate=!0;c&&c(this)},f[b].crossOrigin=this.crossOrigin,f[b].src=a[b];return g},getNormalMap:function(a,
+b){var c=function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]},b=b|1,d=a.width,f=a.height,g=document.createElement("canvas");g.width=d;g.height=f;var e=g.getContext("2d");e.drawImage(a,0,0);for(var h=e.getImageData(0,0,d,f).data,i=e.createImageData(d,f),j=i.data,k=0;k<d;k++)for(var q=1;q<f;q++){var m=0>q-1?f-1:q-1,o=(q+1)%f,p=0>k-1?d-1:k-1,n=(k+1)%d,r=[],s=[0,0,h[4*(q*d+k)]/255*b];r.push([-1,0,h[4*(q*d+p)]/255*b]);r.push([-1,-1,h[4*(m*d+p)]/255*b]);r.push([0,-1,
+h[4*(m*d+k)]/255*b]);r.push([1,-1,h[4*(m*d+n)]/255*b]);r.push([1,0,h[4*(q*d+n)]/255*b]);r.push([1,1,h[4*(o*d+n)]/255*b]);r.push([0,1,h[4*(o*d+k)]/255*b]);r.push([-1,1,h[4*(o*d+p)]/255*b]);m=[];p=r.length;for(o=0;o<p;o++){var n=r[o],t=r[(o+1)%p],n=[n[0]-s[0],n[1]-s[1],n[2]-s[2]],t=[t[0]-s[0],t[1]-s[1],t[2]-s[2]];m.push(c([n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]))}r=[0,0,0];for(o=0;o<m.length;o++)r[0]+=m[o][0],r[1]+=m[o][1],r[2]+=m[o][2];r[0]/=m.length;r[1]/=m.length;r[2]/=m.length;
+s=4*(q*d+k);j[s]=255*((r[0]+1)/2)|0;j[s+1]=255*(r[1]+0.5)|0;j[s+2]=255*r[2]|0;j[s+3]=255}e.putImageData(i,0,0);return g},generateDataTexture:function(a,b,c){for(var d=a*b,f=new Uint8Array(3*d),g=Math.floor(255*c.r),e=Math.floor(255*c.g),c=Math.floor(255*c.b),h=0;h<d;h++)f[3*h]=g,f[3*h+1]=e,f[3*h+2]=c;a=new THREE.DataTexture(f,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}};
+THREE.SceneUtils={showHierarchy:function(a,b){THREE.SceneUtils.traverseHierarchy(a,function(a){a.visible=b})},traverseHierarchy:function(a,b){var c,d,f=a.children.length;for(d=0;d<f;d++)c=a.children[d],b(c),THREE.SceneUtils.traverseHierarchy(c,b)},createMultiMaterialObject:function(a,b){var c,d=b.length,f=new THREE.Object3D;for(c=0;c<d;c++){var g=new THREE.Mesh(a,b[c]);f.add(g)}return f},cloneObject:function(a){var b;a instanceof THREE.MorphAnimMesh?(b=new THREE.MorphAnimMesh(a.geometry,a.material),
+b.duration=a.duration,b.mirroredLoop=a.mirroredLoop,b.time=a.time,b.lastKeyframe=a.lastKeyframe,b.currentKeyframe=a.currentKeyframe,b.direction=a.direction,b.directionBackwards=a.directionBackwards):a instanceof THREE.SkinnedMesh?b=new THREE.SkinnedMesh(a.geometry,a.material):a instanceof THREE.Mesh?b=new THREE.Mesh(a.geometry,a.material):a instanceof THREE.Line?b=new THREE.Line(a.geometry,a.material,a.type):a instanceof THREE.Ribbon?b=new THREE.Ribbon(a.geometry,a.material):a instanceof THREE.ParticleSystem?
+(b=new THREE.ParticleSystem(a.geometry,a.material),b.sortParticles=a.sortParticles):a instanceof THREE.Particle?b=new THREE.Particle(a.material):a instanceof THREE.Sprite?(b=new THREE.Sprite({}),b.color.copy(a.color),b.map=a.map,b.blending=a.blending,b.useScreenCoordinates=a.useScreenCoordinates,b.mergeWith3D=a.mergeWith3D,b.affectedByDistance=a.affectedByDistance,b.scaleByViewport=a.scaleByViewport,b.alignment=a.alignment,b.rotation3d.copy(a.rotation3d),b.rotation=a.rotation,b.opacity=a.opacity,
+b.uvOffset.copy(a.uvOffset),b.uvScale.copy(a.uvScale)):a instanceof THREE.LOD?b=new THREE.LOD:a instanceof THREE.MarchingCubes?(b=new THREE.MarchingCubes(a.resolution,a.material),b.field.set(a.field),b.isolation=a.isolation):a instanceof THREE.Object3D&&(b=new THREE.Object3D);b.name=a.name;b.parent=a.parent;b.up.copy(a.up);b.position.copy(a.position);b.rotation instanceof THREE.Vector3&&b.rotation.copy(a.rotation);b.eulerOrder=a.eulerOrder;b.scale.copy(a.scale);b.dynamic=a.dynamic;b.doubleSided=a.doubleSided;
+b.flipSided=a.flipSided;b.renderDepth=a.renderDepth;b.rotationAutoUpdate=a.rotationAutoUpdate;b.matrix.copy(a.matrix);b.matrixWorld.copy(a.matrixWorld);b.matrixRotationWorld.copy(a.matrixRotationWorld);b.matrixAutoUpdate=a.matrixAutoUpdate;b.matrixWorldNeedsUpdate=a.matrixWorldNeedsUpdate;b.quaternion.copy(a.quaternion);b.useQuaternion=a.useQuaternion;b.boundRadius=a.boundRadius;b.boundRadiusScale=a.boundRadiusScale;b.visible=a.visible;b.castShadow=a.castShadow;b.receiveShadow=a.receiveShadow;b.frustumCulled=
+a.frustumCulled;for(var c=0;c<a.children.length;c++){var d=THREE.SceneUtils.cloneObject(a.children[c]);b.children[c]=d;d.parent=b}if(a instanceof THREE.LOD)for(c=0;c<a.LODs.length;c++)b.LODs[c]={visibleAtDistance:a.LODs[c].visibleAtDistance,object3D:b.children[c]};return b},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
+if(THREE.WebGLRenderer)THREE.ShaderUtils={lib:{fresnel:{uniforms:{mRefractionRatio:{type:"f",value:1.02},mFresnelBias:{type:"f",value:0.1},mFresnelPower:{type:"f",value:2},mFresnelScale:{type:"f",value:1},tCube:{type:"t",value:1,texture:null}},fragmentShader:"uniform samplerCube tCube;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 reflectedColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\nvec4 refractedColor = vec4( 1.0, 1.0, 1.0, 1.0 );\nrefractedColor.r = textureCube( tCube, vec3( -vRefract[0].x, vRefract[0].yz ) ).r;\nrefractedColor.g = textureCube( tCube, vec3( -vRefract[1].x, vRefract[1].yz ) ).g;\nrefractedColor.b = textureCube( tCube, vec3( -vRefract[2].x, vRefract[2].yz ) ).b;\nrefractedColor.a = 1.0;\ngl_FragColor = mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) );\n}",
+vertexShader:"uniform float mRefractionRatio;\nuniform float mFresnelBias;\nuniform float mFresnelScale;\nuniform float mFresnelPower;\nvarying vec3 vReflect;\nvarying vec3 vRefract[3];\nvarying float vReflectionFactor;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvec3 nWorld = normalize ( mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal );\nvec3 I = mPosition.xyz - cameraPosition;\nvReflect = reflect( I, nWorld );\nvRefract[0] = refract( normalize( I ), nWorld, mRefractionRatio );\nvRefract[1] = refract( normalize( I ), nWorld, mRefractionRatio * 0.99 );\nvRefract[2] = refract( normalize( I ), nWorld, mRefractionRatio * 0.98 );\nvReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), nWorld ), mFresnelPower );\ngl_Position = projectionMatrix * mvPosition;\n}"},
+normal:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},tDiffuse:{type:"t",value:0,texture:null},tCube:{type:"t",value:1,texture:null},tNormal:{type:"t",value:2,texture:null},tSpecular:{type:"t",value:3,texture:null},tAO:{type:"t",value:4,texture:null},tDisplacement:{type:"t",value:5,texture:null},uNormalScale:{type:"f",
+value:1},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f",value:30},uOpacity:{type:"f",value:1},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),
+fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform float uNormalScale;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;",
+THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec3 pointVector = normalize( vPointLight[ i ].xyz );\nfloat pointDistance = vPointLight[ i ].w;\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;\nif ( enableReflection ) {\nvec3 wPos = cameraPosition - vViewPosition;\nvec3 vReflect = reflect( normalize( wPos ), normal );\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}",
+THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;",
+THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvViewPosition = -mvPosition.xyz;\nvNormal = normalMatrix * normal;\nvTangent = normalMatrix * tangent.xyz;\nvBinormal = cross( vNormal, vTangent ) * tangent.w;\nvUv = uv * uRepeat + uOffset;\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#ifdef VERTEX_TEXTURES\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\nvec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;\ngl_Position = projectionMatrix * displacedPosition;\n#else\ngl_Position = projectionMatrix * mvPosition;\n#endif",
+THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:1,texture:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vViewPosition;\nvoid main() {\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvViewPosition = cameraPosition - mPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vViewPosition;\nvoid main() {\nvec3 wPos = cameraPosition - vViewPosition;\ngl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );\n}"}}};
+THREE.BufferGeometry=function(){this.id=THREE.GeometryCount++;this.vertexColorArray=this.vertexUvArray=this.vertexNormalArray=this.vertexPositionArray=this.vertexIndexArray=this.vertexColorBuffer=this.vertexUvBuffer=this.vertexNormalBuffer=this.vertexPositionBuffer=this.vertexIndexBuffer=null;this.dynamic=!1;this.boundingSphere=this.boundingBox=null;this.morphTargets=[]};THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,computeBoundingBox:function(){},computeBoundingSphere:function(){}};
+THREE.Curve=function(){};THREE.Curve.prototype.getPoint=function(){console.log("Warning, getPoint() not implemented!");return null};THREE.Curve.prototype.getPointAt=function(a){return this.getPoint(this.getUtoTmapping(a))};THREE.Curve.prototype.getPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPoint(b/a));return c};THREE.Curve.prototype.getSpacedPoints=function(a){a||(a=5);var b,c=[];for(b=0;b<=a;b++)c.push(this.getPointAt(b/a));return c};
+THREE.Curve.prototype.getLength=function(){var a=this.getLengths();return a[a.length-1]};THREE.Curve.prototype.getLengths=function(a){a||(a=200);if(this.cacheArcLengths&&this.cacheArcLengths.length==a+1)return this.cacheArcLengths;var b=[],c,d=this.getPoint(0),f,g=0;b.push(0);for(f=1;f<=a;f++)c=this.getPoint(f/a),g+=c.distanceTo(d),b.push(g),d=c;return this.cacheArcLengths=b};
+THREE.Curve.prototype.getUtoTmapping=function(a,b){var c=this.getLengths(),d=0,f=c.length,g;g=b?b:a*c[f-1];for(var e=0,h=f-1,i;e<=h;)if(d=Math.floor(e+(h-e)/2),i=c[d]-g,0>i)e=d+1;else if(0<i)h=d-1;else{h=d;break}d=h;if(c[d]==g)return d/(f-1);e=c[d];return c=(d+(g-e)/(c[d+1]-e))/(f-1)};THREE.Curve.prototype.getNormalVector=function(a){a=this.getTangent(a);return new THREE.Vector2(-a.y,a.x)};
+THREE.Curve.prototype.getTangent=function(a){var b=a-1.0E-4,a=a+1.0E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);a=this.getPoint(a);return b.clone().subSelf(a).normalize()};THREE.Curve.prototype.getTangentAt=function(a){return this.getTangent(this.getUtoTmapping(a))};THREE.LineCurve=function(a,b){a instanceof THREE.Vector2?(this.v1=a,this.v2=b):THREE.LineCurve.oldConstructor.apply(this,arguments)};
+THREE.LineCurve.oldConstructor=function(a,b,c,d){this.constructor(new THREE.Vector2(a,b),new THREE.Vector2(c,d))};THREE.LineCurve.prototype=new THREE.Curve;THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.sub(this.v2,this.v1);b.multiplyScalar(a).addSelf(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};
+THREE.LineCurve.prototype.getTangent=function(){var a=new THREE.Vector2;a.sub(this.v2,this.v1);a.normalize();return a};THREE.QuadraticBezierCurve=function(a,b,c){if(!(b instanceof THREE.Vector2))var d=Array.prototype.slice.call(arguments),a=new THREE.Vector2(d[0],d[1]),b=new THREE.Vector2(d[2],d[3]),c=new THREE.Vector2(d[4],d[5]);this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=new THREE.Curve;THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve;
+THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return new THREE.Vector2(b,a)};THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);b=new THREE.Vector2(b,a);b.normalize();return b};
+THREE.CubicBezierCurve=function(a,b,c,d){if(!(b instanceof THREE.Vector2))var f=Array.prototype.slice.call(arguments),a=new THREE.Vector2(f[0],f[1]),b=new THREE.Vector2(f[2],f[3]),c=new THREE.Vector2(f[4],f[5]),d=new THREE.Vector2(f[6],f[7]);this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=new THREE.Curve;THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve;
+THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)};THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b};
+THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=new THREE.Curve;THREE.SplineCurve.prototype.constructor=THREE.SplineCurve;
+THREE.SplineCurve.prototype.getPoint=function(a){var b=new THREE.Vector2,c=[],d=this.points,f;f=(d.length-1)*a;a=Math.floor(f);f-=a;c[0]=0==a?a:a-1;c[1]=a;c[2]=a>d.length-2?a:a+1;c[3]=a>d.length-3?a:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,f);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,f);return b};THREE.ArcCurve=function(a,b,c,d,f,g){this.aX=a;this.aY=b;this.aRadius=c;this.aStartAngle=d;this.aEndAngle=f;this.aClockwise=g};
+THREE.ArcCurve.prototype=new THREE.Curve;THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;THREE.ArcCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;this.aClockwise||(a=1-a);b=this.aStartAngle+a*b;a=this.aX+this.aRadius*Math.cos(b);b=this.aY+this.aRadius*Math.sin(b);return new THREE.Vector2(a,b)};
+THREE.Curve.Utils={tangentQuadraticBezier:function(a,b,c,d){return 2*(1-a)*(c-b)+2*a*(d-c)},tangentCubicBezier:function(a,b,c,d,f){return-3*b*(1-a)*(1-a)+3*c*(1-a)*(1-a)-6*a*c*(1-a)+6*a*d*(1-a)-3*a*a*d+3*a*a*f},tangentSpline:function(a){return 6*a*a-6*a+(3*a*a-4*a+1)+(-6*a*a+6*a)+(3*a*a-2*a)},interpolate:function(a,b,c,d,f){var a=0.5*(c-a),d=0.5*(d-b),g=f*f;return(2*b-2*c+a+d)*f*g+(-3*b+3*c-2*a-d)*g+a*f+b}};
+THREE.Curve.create=function(a,b){a.prototype=new THREE.Curve;a.prototype.constructor=a;a.prototype.getPoint=b;return a};THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.sub(this.v2,this.v1);b.multiplyScalar(a);b.addSelf(this.v1);return b});
+THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)});
+THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)});
+THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,f;f=(d.length-1)*a;a=Math.floor(f);f-=a;c[0]=0==a?a:a-1;c[1]=a;c[2]=a>d.length-2?a:a+1;c[3]=a>d.length-3?a:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,f);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,f);b.z=THREE.Curve.Utils.interpolate(d[c[0]].z,d[c[1]].z,d[c[2]].z,d[c[3]].z,f);return b});
+THREE.CurvePath=function(){this.curves=[];this.bends=[];this.autoClose=!1};THREE.CurvePath.prototype=new THREE.Curve;THREE.CurvePath.prototype.constructor=THREE.CurvePath;THREE.CurvePath.prototype.add=function(a){this.curves.push(a)};THREE.CurvePath.prototype.checkConnection=function(){};THREE.CurvePath.prototype.closePath=function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length-1].getPoint(1);a.equals(b)||this.curves.push(new THREE.LineCurve(b,a))};
+THREE.CurvePath.prototype.getPoint=function(a){for(var b=a*this.getLength(),c=this.getCurveLengths(),a=0;a<c.length;){if(c[a]>=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]};
+THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;c<d;c++)b+=this.curves[c].getLength(),a.push(b);return this.cacheLengths=a};
+THREE.CurvePath.prototype.getBoundingBox=function(){var a=this.getPoints(),b,c,d,f;b=c=Number.NEGATIVE_INFINITY;d=f=Number.POSITIVE_INFINITY;var g,e,h,i;i=new THREE.Vector2;for(e=0,h=a.length;e<h;e++){g=a[e];if(g.x>b)b=g.x;else if(g.x<d)d=g.x;if(g.y>c)c=g.y;else if(g.y<c)f=g.y;i.addSelf(g.x,g.y)}return{minX:d,minY:f,maxX:b,maxY:c,centroid:i.divideScalar(h)}};THREE.CurvePath.prototype.createPointsGeometry=function(a){return this.createGeometry(this.getPoints(a,!0))};
+THREE.CurvePath.prototype.createSpacedPointsGeometry=function(a){return this.createGeometry(this.getSpacedPoints(a,!0))};THREE.CurvePath.prototype.createGeometry=function(a){for(var b=new THREE.Geometry,c=0;c<a.length;c++)b.vertices.push(new THREE.Vertex(new THREE.Vector3(a[c].x,a[c].y,0)));return b};THREE.CurvePath.prototype.addWrapPath=function(a){this.bends.push(a)};
+THREE.CurvePath.prototype.getTransformedPoints=function(a,b){var c=this.getPoints(a),d,f;if(!b)b=this.bends;for(d=0,f=b.length;d<f;d++)c=this.getWrapPoints(c,b[d]);return c};THREE.CurvePath.prototype.getTransformedSpacedPoints=function(a,b){var c=this.getSpacedPoints(a),d,f;if(!b)b=this.bends;for(d=0,f=b.length;d<f;d++)c=this.getWrapPoints(c,b[d]);return c};
+THREE.CurvePath.prototype.getWrapPoints=function(a,b){var c=this.getBoundingBox(),d,f,g,e,h,i;for(d=0,f=a.length;d<f;d++)g=a[d],e=g.x,h=g.y,i=e/c.maxX,i=b.getUtoTmapping(i,e),e=b.getPoint(i),h=b.getNormalVector(i).multiplyScalar(h),g.x=e.x+h.x,g.y=e.y+h.y;return a};
+THREE.EventTarget=function(){var a={};this.addEventListener=function(b,c){void 0==a[b]&&(a[b]=[]);-1===a[b].indexOf(c)&&a[b].push(c)};this.dispatchEvent=function(b){for(var c in a[b.type])a[b.type][c](b)};this.removeEventListener=function(b,c){var d=a[b].indexOf(c);-1!==d&&a[b].splice(d,1)}};THREE.Gyroscope=function(){THREE.Object3D.call(this)};THREE.Gyroscope.prototype=new THREE.Object3D;THREE.Gyroscope.prototype.constructor=THREE.Gyroscope;
+THREE.Gyroscope.prototype.updateMatrixWorld=function(a){this.matrixAutoUpdate&&this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)this.parent?(this.matrixWorld.multiply(this.parent.matrixWorld,this.matrix),this.matrixWorld.decompose(this.translationWorld,this.rotationWorld,this.scaleWorld),this.matrix.decompose(this.translationObject,this.rotationObject,this.scaleObject),this.matrixWorld.compose(this.translationWorld,this.rotationObject,this.scaleWorld)):this.matrixWorld.copy(this.matrix),this.matrixWorldNeedsUpdate=
+!1,a=!0;for(var b=0,c=this.children.length;b<c;b++)this.children[b].updateMatrixWorld(a)};THREE.Gyroscope.prototype.translationWorld=new THREE.Vector3;THREE.Gyroscope.prototype.translationObject=new THREE.Vector3;THREE.Gyroscope.prototype.rotationWorld=new THREE.Quaternion;THREE.Gyroscope.prototype.rotationObject=new THREE.Quaternion;THREE.Gyroscope.prototype.scaleWorld=new THREE.Vector3;THREE.Gyroscope.prototype.scaleObject=new THREE.Vector3;
+THREE.Path=function(a){THREE.CurvePath.call(this);this.actions=[];a&&this.fromPoints(a)};THREE.Path.prototype=new THREE.CurvePath;THREE.Path.prototype.constructor=THREE.Path;THREE.PathActions={MOVE_TO:"moveTo",LINE_TO:"lineTo",QUADRATIC_CURVE_TO:"quadraticCurveTo",BEZIER_CURVE_TO:"bezierCurveTo",CSPLINE_THRU:"splineThru",ARC:"arc"};THREE.Path.prototype.fromPoints=function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b].x,a[b].y)};
+THREE.Path.prototype.moveTo=function(a,b){var c=Array.prototype.slice.call(arguments);this.actions.push({action:THREE.PathActions.MOVE_TO,args:c})};THREE.Path.prototype.lineTo=function(a,b){var c=Array.prototype.slice.call(arguments),d=this.actions[this.actions.length-1].args;this.curves.push(new THREE.LineCurve(new THREE.Vector2(d[d.length-2],d[d.length-1]),new THREE.Vector2(a,b)));this.actions.push({action:THREE.PathActions.LINE_TO,args:c})};
+THREE.Path.prototype.quadraticCurveTo=function(a,b,c,d){var f=Array.prototype.slice.call(arguments),g=this.actions[this.actions.length-1].args;this.curves.push(new THREE.QuadraticBezierCurve(new THREE.Vector2(g[g.length-2],g[g.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d)));this.actions.push({action:THREE.PathActions.QUADRATIC_CURVE_TO,args:f})};
+THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,f,g){var e=Array.prototype.slice.call(arguments),h=this.actions[this.actions.length-1].args;this.curves.push(new THREE.CubicBezierCurve(new THREE.Vector2(h[h.length-2],h[h.length-1]),new THREE.Vector2(a,b),new THREE.Vector2(c,d),new THREE.Vector2(f,g)));this.actions.push({action:THREE.PathActions.BEZIER_CURVE_TO,args:e})};
+THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);this.curves.push(new THREE.SplineCurve(c));this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};
+THREE.Path.prototype.arc=function(a,b,c,d,f,g){var e=Array.prototype.slice.call(arguments);this.curves.push(new THREE.ArcCurve(a,b,c,d,f,g));this.actions.push({action:THREE.PathActions.ARC,args:e})};THREE.Path.prototype.getSpacedPoints=function(a){a||(a=40);for(var b=[],c=0;c<a;c++)b.push(this.getPoint(c/a));return b};
+THREE.Path.prototype.getPoints=function(a,b){var a=a||12,c=[],d,f,g,e,h,i,j,k,q,m,o,p,n;for(d=0,f=this.actions.length;d<f;d++)switch(g=this.actions[d],e=g.action,g=g.args,e){case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(g[0],g[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:h=g[2];i=g[3];q=g[0];m=g[1];0<c.length?(e=c[c.length-1],o=e.x,p=e.y):(e=this.actions[d-1].args,o=e[e.length-2],p=e[e.length-1]);for(e=1;e<=a;e++)n=e/a,g=THREE.Shape.Utils.b2(n,o,q,h),n=THREE.Shape.Utils.b2(n,p,m,
+i),c.push(new THREE.Vector2(g,n));break;case THREE.PathActions.BEZIER_CURVE_TO:h=g[4];i=g[5];q=g[0];m=g[1];j=g[2];k=g[3];0<c.length?(e=c[c.length-1],o=e.x,p=e.y):(e=this.actions[d-1].args,o=e[e.length-2],p=e[e.length-1]);for(e=1;e<=a;e++)n=e/a,g=THREE.Shape.Utils.b3(n,o,q,j,h),n=THREE.Shape.Utils.b3(n,p,m,k,i),c.push(new THREE.Vector2(g,n));break;case THREE.PathActions.CSPLINE_THRU:e=this.actions[d-1].args;e=[new THREE.Vector2(e[e.length-2],e[e.length-1])];n=a*g[0].length;e=e.concat(g[0]);g=new THREE.SplineCurve(e);
+for(e=1;e<=n;e++)c.push(g.getPointAt(e/n));break;case THREE.PathActions.ARC:e=this.actions[d-1].args;h=g[0];i=g[1];j=g[2];q=g[3];n=g[4];m=!!g[5];k=e[e.length-2];o=e[e.length-1];0==e.length&&(k=o=0);p=n-q;var r=2*a;for(e=1;e<=r;e++)n=e/r,m||(n=1-n),n=q+n*p,g=k+h+j*Math.cos(n),n=o+i+j*Math.sin(n),c.push(new THREE.Vector2(g,n))}b&&c.push(c[0]);return c};THREE.Path.prototype.transform=function(a,b){this.getBoundingBox();return this.getWrapPoints(this.getPoints(b),a)};
+THREE.Path.prototype.nltransform=function(a,b,c,d,f,g){var e=this.getPoints(),h,i,j,k,q;for(h=0,i=e.length;h<i;h++)j=e[h],k=j.x,q=j.y,j.x=a*k+b*q+c,j.y=d*q+f*k+g;return e};
+THREE.Path.prototype.debug=function(a){var b=this.getBoundingBox();a||(a=document.createElement("canvas"),a.setAttribute("width",b.maxX+100),a.setAttribute("height",b.maxY+100),document.body.appendChild(a));b=a.getContext("2d");b.fillStyle="white";b.fillRect(0,0,a.width,a.height);b.strokeStyle="black";b.beginPath();var c,d,f;for(a=0,c=this.actions.length;a<c;a++)d=this.actions[a],f=d.args,d=d.action,d!=THREE.PathActions.CSPLINE_THRU&&b[d].apply(b,f);b.stroke();b.closePath();b.strokeStyle="red";d=
+this.getPoints();for(a=0,c=d.length;a<c;a++)f=d[a],b.beginPath(),b.arc(f.x,f.y,1.5,0,2*Math.PI,!1),b.stroke(),b.closePath()};
+THREE.Path.prototype.toShapes=function(){var a,b,c,d,f=[],g=new THREE.Path;for(a=0,b=this.actions.length;a<b;a++)c=this.actions[a],d=c.args,c=c.action,c==THREE.PathActions.MOVE_TO&&0!=g.actions.length&&(f.push(g),g=new THREE.Path),g[c].apply(g,d);0!=g.actions.length&&f.push(g);if(0==f.length)return[];var e;d=[];a=!THREE.Shape.Utils.isClockWise(f[0].getPoints());if(1==f.length)return g=f[0],e=new THREE.Shape,e.actions=g.actions,e.curves=g.curves,d.push(e),d;if(a){e=new THREE.Shape;for(a=0,b=f.length;a<
+b;a++)g=f[a],THREE.Shape.Utils.isClockWise(g.getPoints())?(e.actions=g.actions,e.curves=g.curves,d.push(e),e=new THREE.Shape):e.holes.push(g)}else{for(a=0,b=f.length;a<b;a++)g=f[a],THREE.Shape.Utils.isClockWise(g.getPoints())?(e&&d.push(e),e=new THREE.Shape,e.actions=g.actions,e.curves=g.curves):e.holes.push(g);d.push(e)}return d};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=new THREE.Path;THREE.Shape.prototype.constructor=THREE.Path;
+THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d};THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d};
+THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}};
+THREE.Shape.Utils={removeHoles:function(a,b){var c=a.concat(),d=c.concat(),f,g,e,h,i,j,k,q,m,o,p=[];for(i=0;i<b.length;i++){j=b[i];Array.prototype.push.apply(d,j);g=Number.POSITIVE_INFINITY;for(f=0;f<j.length;f++){m=j[f];o=[];for(q=0;q<c.length;q++)k=c[q],k=m.distanceToSquared(k),o.push(k),k<g&&(g=k,e=f,h=q)}f=0<=h-1?h-1:c.length-1;g=0<=e-1?e-1:j.length-1;var n=[j[e],c[h],c[f]];q=THREE.FontUtils.Triangulate.area(n);var r=[j[e],j[g],c[h]];m=THREE.FontUtils.Triangulate.area(r);o=h;k=e;h+=1;e+=-1;0>
+h&&(h+=c.length);h%=c.length;0>e&&(e+=j.length);e%=j.length;f=0<=h-1?h-1:c.length-1;g=0<=e-1?e-1:j.length-1;n=[j[e],c[h],c[f]];n=THREE.FontUtils.Triangulate.area(n);r=[j[e],j[g],c[h]];r=THREE.FontUtils.Triangulate.area(r);q+m>n+r&&(h=o,e=k,0>h&&(h+=c.length),h%=c.length,0>e&&(e+=j.length),e%=j.length,f=0<=h-1?h-1:c.length-1,g=0<=e-1?e-1:j.length-1);q=c.slice(0,h);m=c.slice(h);o=j.slice(e);k=j.slice(0,e);g=[j[e],j[g],c[h]];p.push([j[e],c[h],c[f]]);p.push(g);c=q.concat(o).concat(k).concat(m)}return{shape:c,
+isolatedPts:p,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,f=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),g,e,h,i,j={};for(g=0,e=d.length;g<e;g++)i=d[g].x+":"+d[g].y,void 0!==j[i]&&console.log("Duplicate point",i),j[i]=g;for(g=0,e=c.length;g<e;g++){h=c[g];for(d=0;3>d;d++)i=h[d].x+":"+h[d].y,i=j[i],void 0!==i&&(h[d]=i)}for(g=0,e=f.length;g<e;g++){h=f[g];for(d=0;3>d;d++)i=h[d].x+":"+h[d].y,i=j[i],void 0!==i&&(h[d]=i)}return c.concat(f)},
+isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,f){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+
+this.b3p3(a,f)}};THREE.TextPath=function(a,b){THREE.Path.call(this);this.parameters=b||{};this.set(a)};THREE.TextPath.prototype.set=function(a,b){b=b||this.parameters;this.text=a;var c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",f=void 0!==b.weight?b.weight:"normal",g=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=f;THREE.FontUtils.style=g};
+THREE.TextPath.prototype.toShapes=function(){for(var a=THREE.FontUtils.drawText(this.text).paths,b=[],c=0,d=a.length;c<d;c++)Array.prototype.push.apply(b,a[c].toShapes());return b};
+THREE.AnimationHandler=function(){var a=[],b={},c={update:function(b){for(var c=0;c<a.length;c++)a[c].update(b)},addToUpdate:function(b){-1===a.indexOf(b)&&a.push(b)},removeFromUpdate:function(b){b=a.indexOf(b);-1!==b&&a.splice(b,1)},add:function(a){void 0!==b[a.name]&&console.log("THREE.AnimationHandler.add: Warning! "+a.name+" already exists in library. Overwriting.");b[a.name]=a;if(!0!==a.initialized){for(var c=0;c<a.hierarchy.length;c++){for(var d=0;d<a.hierarchy[c].keys.length;d++){if(0>a.hierarchy[c].keys[d].time)a.hierarchy[c].keys[d].time=
+0;if(void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var h=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(h[0],h[1],h[2],h[3])}}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){h={};for(d=0;d<a.hierarchy[c].keys.length;d++)for(var i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++){var j=a.hierarchy[c].keys[d].morphTargets[i];h[j]=-1}a.hierarchy[c].usedMorphTargets=h;for(d=0;d<a.hierarchy[c].keys.length;d++){var k=
+{};for(j in h){for(i=0;i<a.hierarchy[c].keys[d].morphTargets.length;i++)if(a.hierarchy[c].keys[d].morphTargets[i]===j){k[j]=a.hierarchy[c].keys[d].morphTargetsInfluences[i];break}i===a.hierarchy[c].keys[d].morphTargets.length&&(k[j]=0)}a.hierarchy[c].keys[d].morphTargetsInfluences=k}}for(d=1;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].time===a.hierarchy[c].keys[d-1].time&&(a.hierarchy[c].keys.splice(d,1),d--);for(d=0;d<a.hierarchy[c].keys.length;d++)a.hierarchy[c].keys[d].index=d}d=parseInt(a.length*
+a.fps,10);a.JIT={};a.JIT.hierarchy=[];for(c=0;c<a.hierarchy.length;c++)a.JIT.hierarchy.push(Array(d));a.initialized=!0}},get:function(a){if("string"===typeof a){if(b[a])return b[a];console.log("THREE.AnimationHandler.get: Couldn't find animation "+a);return null}},parse:function(a){var b=[];if(a instanceof THREE.SkinnedMesh)for(var c=0;c<a.bones.length;c++)b.push(a.bones[c]);else d(a,b);return b}},d=function(a,b){b.push(a);for(var c=0;c<a.children.length;c++)d(a.children[c],b)};c.LINEAR=0;c.CATMULLROM=
+1;c.CATMULLROM_FORWARD=2;return c}();THREE.Animation=function(a,b,c,d){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=this.isPaused=!0;this.interpolationType=void 0!==c?c:THREE.AnimationHandler.LINEAR;this.JITCompile=void 0!==d?d:!0;this.points=[];this.target=new THREE.Vector3};
+THREE.Animation.prototype.play=function(a,b){if(!this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;var c,d=this.hierarchy.length,f;for(c=0;c<d;c++){f=this.hierarchy[c];if(this.interpolationType!==THREE.AnimationHandler.CATMULLROM_FORWARD)f.useQuaternion=!0;f.matrixAutoUpdate=!0;if(void 0===f.animationCache)f.animationCache={},f.animationCache.prevKey={pos:0,rot:0,scl:0},f.animationCache.nextKey={pos:0,rot:0,scl:0},f.animationCache.originalMatrix=f instanceof
+THREE.Bone?f.skinMatrix:f.matrix;var g=f.animationCache.prevKey;f=f.animationCache.nextKey;g.pos=this.data.hierarchy[c].keys[0];g.rot=this.data.hierarchy[c].keys[0];g.scl=this.data.hierarchy[c].keys[0];f.pos=this.getNextKeyWith("pos",c,1);f.rot=this.getNextKeyWith("rot",c,1);f.scl=this.getNextKeyWith("scl",c,1)}this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)};
+THREE.Animation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused};
+THREE.Animation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this);for(var a=0;a<this.hierarchy.length;a++)if(void 0!==this.hierarchy[a].animationCache)this.hierarchy[a]instanceof THREE.Bone?this.hierarchy[a].skinMatrix=this.hierarchy[a].animationCache.originalMatrix:this.hierarchy[a].matrix=this.hierarchy[a].animationCache.originalMatrix,delete this.hierarchy[a].animationCache};
+THREE.Animation.prototype.update=function(a){if(this.isPlaying){var b=["pos","rot","scl"],c,d,f,g,e,h,i,j,k=this.data.JIT.hierarchy,q,m;m=this.currentTime+=a*this.timeScale;q=this.currentTime%=this.data.length;j=parseInt(Math.min(q*this.data.fps,this.data.length*this.data.fps),10);for(var o=0,p=this.hierarchy.length;o<p;o++)if(a=this.hierarchy[o],i=a.animationCache,this.JITCompile&&void 0!==k[o][j])a instanceof THREE.Bone?(a.skinMatrix=k[o][j],a.matrixAutoUpdate=!1,a.matrixWorldNeedsUpdate=!1):(a.matrix=
+k[o][j],a.matrixAutoUpdate=!1,a.matrixWorldNeedsUpdate=!0);else{if(this.JITCompile)a instanceof THREE.Bone?a.skinMatrix=a.animationCache.originalMatrix:a.matrix=a.animationCache.originalMatrix;for(var n=0;3>n;n++){c=b[n];e=i.prevKey[c];h=i.nextKey[c];if(h.time<=m){if(q<m)if(this.loop){e=this.data.hierarchy[o].keys[0];for(h=this.getNextKeyWith(c,o,1);h.time<q;)e=h,h=this.getNextKeyWith(c,o,h.index+1)}else{this.stop();return}else{do e=h,h=this.getNextKeyWith(c,o,h.index+1);while(h.time<q)}i.prevKey[c]=
+e;i.nextKey[c]=h}a.matrixAutoUpdate=!0;a.matrixWorldNeedsUpdate=!0;d=(q-e.time)/(h.time-e.time);f=e[c];g=h[c];if(0>d||1<d)console.log("THREE.Animation.update: Warning! Scale out of bounds:"+d+" on bone "+o),d=0>d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=f[0]+(g[0]-f[0])*d,c.y=f[1]+(g[1]-f[1])*d,c.z=f[2]+(g[2]-f[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)if(this.points[0]=
+this.getPrevKeyWith("pos",o,e.index-1).pos,this.points[1]=f,this.points[2]=g,this.points[3]=this.getNextKeyWith("pos",o,h.index+1).pos,d=0.33*d+0.33,f=this.interpolateCatmullRom(this.points,d),c.x=f[0],c.y=f[1],c.z=f[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)d=this.interpolateCatmullRom(this.points,1.01*d),this.target.set(d[0],d[1],d[2]),this.target.subSelf(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0)}else if("rot"===
+c)THREE.Quaternion.slerp(f,g,a.quaternion,d);else if("scl"===c)c=a.scale,c.x=f[0]+(g[0]-f[0])*d,c.y=f[1]+(g[1]-f[1])*d,c.z=f[2]+(g[2]-f[2])*d}}if(this.JITCompile&&void 0===k[0][j]){this.hierarchy[0].updateMatrixWorld(!0);for(o=0;o<this.hierarchy.length;o++)k[o][j]=this.hierarchy[o]instanceof THREE.Bone?this.hierarchy[o].skinMatrix.clone():this.hierarchy[o].matrix.clone()}}};
+THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],f,g,e,h,i,j;f=(a.length-1)*b;g=Math.floor(f);f-=g;c[0]=0===g?g:g-1;c[1]=g;c[2]=g>a.length-2?g:g+1;c[3]=g>a.length-3?g:g+2;g=a[c[0]];h=a[c[1]];i=a[c[2]];j=a[c[3]];c=f*f;e=f*c;d[0]=this.interpolate(g[0],h[0],i[0],j[0],f,c,e);d[1]=this.interpolate(g[1],h[1],i[1],j[1],f,c,e);d[2]=this.interpolate(g[2],h[2],i[2],j[2],f,c,e);return d};
+THREE.Animation.prototype.interpolate=function(a,b,c,d,f,g,e){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*e+(-3*(b-c)-2*a-d)*g+a*f+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]};
+THREE.Animation.prototype.getPrevKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]};
+THREE.KeyFrameAnimation=function(a,b,c){this.root=a;this.data=THREE.AnimationHandler.get(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=0.001;this.isPlaying=!1;this.loop=this.isPaused=!0;this.JITCompile=void 0!==c?c:!0;a=0;for(b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var f=0;f<c.length;f++){var g=c[f],e=this.getNextKeyWith(g,a,0);e&&e.apply(g)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix();
+d.matrixWorldNeedsUpdate=!0}}};
+THREE.KeyFrameAnimation.prototype.play=function(a,b){if(!this.isPlaying){this.isPlaying=!0;this.loop=void 0!==a?a:!0;this.currentTime=void 0!==b?b:0;this.startTimeMs=b;this.startTime=1E7;this.endTime=-this.startTime;var c,d=this.hierarchy.length,f,g;for(c=0;c<d;c++){f=this.hierarchy[c];g=this.data.hierarchy[c];f.useQuaternion=!0;if(void 0===g.animationCache)g.animationCache={},g.animationCache.prevKey=null,g.animationCache.nextKey=null,g.animationCache.originalMatrix=f instanceof THREE.Bone?f.skinMatrix:
+f.matrix;f=this.data.hierarchy[c].keys;if(f.length)g.animationCache.prevKey=f[0],g.animationCache.nextKey=f[1],this.startTime=Math.min(f[0].time,this.startTime),this.endTime=Math.max(f[f.length-1].time,this.endTime)}this.update(0)}this.isPaused=!1;THREE.AnimationHandler.addToUpdate(this)};THREE.KeyFrameAnimation.prototype.pause=function(){this.isPaused?THREE.AnimationHandler.addToUpdate(this):THREE.AnimationHandler.removeFromUpdate(this);this.isPaused=!this.isPaused};
+THREE.KeyFrameAnimation.prototype.stop=function(){this.isPaused=this.isPlaying=!1;THREE.AnimationHandler.removeFromUpdate(this);for(var a=0;a<this.data.hierarchy.length;a++){var b=this.hierarchy[a],c=this.data.hierarchy[a];if(void 0!==c.animationCache){var d=c.animationCache.originalMatrix;b instanceof THREE.Bone?(d.copy(b.skinMatrix),b.skinMatrix=d):(d.copy(b.matrix),b.matrix=d);delete c.animationCache}}};
+THREE.KeyFrameAnimation.prototype.update=function(a){if(this.isPlaying){var b,c,d,f,g=this.data.JIT.hierarchy,e,h,i;h=this.currentTime+=a*this.timeScale;e=this.currentTime%=this.data.length;if(e<this.startTimeMs)e=this.currentTime=this.startTimeMs+e;f=parseInt(Math.min(e*this.data.fps,this.data.length*this.data.fps),10);if((i=e<h)&&!this.loop){for(var a=0,j=this.hierarchy.length;a<j;a++){var k=this.data.hierarchy[a].keys,g=this.data.hierarchy[a].sids;d=k.length-1;f=this.hierarchy[a];if(k.length){for(k=
+0;k<g.length;k++)e=g[k],(h=this.getPrevKeyWith(e,a,d))&&h.apply(e);this.data.hierarchy[a].node.updateMatrix();f.matrixWorldNeedsUpdate=!0}}this.stop()}else if(!(e<this.startTime)){a=0;for(j=this.hierarchy.length;a<j;a++){d=this.hierarchy[a];b=this.data.hierarchy[a];var k=b.keys,q=b.animationCache;if(this.JITCompile&&void 0!==g[a][f])d instanceof THREE.Bone?(d.skinMatrix=g[a][f],d.matrixWorldNeedsUpdate=!1):(d.matrix=g[a][f],d.matrixWorldNeedsUpdate=!0);else if(k.length){if(this.JITCompile&&q)d instanceof
+THREE.Bone?d.skinMatrix=q.originalMatrix:d.matrix=q.originalMatrix;b=q.prevKey;c=q.nextKey;if(b&&c){if(c.time<=h){if(i&&this.loop){b=k[0];for(c=k[1];c.time<e;)b=c,c=k[b.index+1]}else if(!i)for(var m=k.length-1;c.time<e&&c.index!==m;)b=c,c=k[b.index+1];q.prevKey=b;q.nextKey=c}c.time>=e?b.interpolate(c,e):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===g[0][f]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;a<this.hierarchy.length;a++)g[a][f]=
+this.hierarchy[a]instanceof THREE.Bone?this.hierarchy[a].skinMatrix.clone():this.hierarchy[a].matrix.clone()}}}};THREE.KeyFrameAnimation.prototype.getNextKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c%=b.length;c<b.length;c++)if(b[c].hasTarget(a))return b[c];return b[0]};THREE.KeyFrameAnimation.prototype.getPrevKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c=0<=c?c:c+b.length;0<=c;c--)if(b[c].hasTarget(a))return b[c];return b[b.length-1]};
+THREE.CubeCamera=function(a,b,c,d){this.heightOffset=c;this.position=new THREE.Vector3(0,c,0);this.cameraPX=new THREE.PerspectiveCamera(90,1,a,b);this.cameraNX=new THREE.PerspectiveCamera(90,1,a,b);this.cameraPY=new THREE.PerspectiveCamera(90,1,a,b);this.cameraNY=new THREE.PerspectiveCamera(90,1,a,b);this.cameraPZ=new THREE.PerspectiveCamera(90,1,a,b);this.cameraNZ=new THREE.PerspectiveCamera(90,1,a,b);this.cameraPX.position=this.position;this.cameraNX.position=this.position;this.cameraPY.position=
+this.position;this.cameraNY.position=this.position;this.cameraPZ.position=this.position;this.cameraNZ.position=this.position;this.cameraPX.up.set(0,-1,0);this.cameraNX.up.set(0,-1,0);this.cameraPY.up.set(0,0,1);this.cameraNY.up.set(0,0,-1);this.cameraPZ.up.set(0,-1,0);this.cameraNZ.up.set(0,-1,0);this.targetPX=new THREE.Vector3(0,0,0);this.targetNX=new THREE.Vector3(0,0,0);this.targetPY=new THREE.Vector3(0,0,0);this.targetNY=new THREE.Vector3(0,0,0);this.targetPZ=new THREE.Vector3(0,0,0);this.targetNZ=
+new THREE.Vector3(0,0,0);this.renderTarget=new THREE.WebGLRenderTargetCube(d,d,{format:THREE.RGBFormat,magFilter:THREE.LinearFilter,minFilter:THREE.LinearFilter});this.updatePosition=function(a){this.position.copy(a);this.position.y+=this.heightOffset;this.targetPX.copy(this.position);this.targetNX.copy(this.position);this.targetPY.copy(this.position);this.targetNY.copy(this.position);this.targetPZ.copy(this.position);this.targetNZ.copy(this.position);this.targetPX.x+=1;this.targetNX.x-=1;this.targetPY.y+=
+1;this.targetNY.y-=1;this.targetPZ.z+=1;this.targetNZ.z-=1;this.cameraPX.lookAt(this.targetPX);this.cameraNX.lookAt(this.targetNX);this.cameraPY.lookAt(this.targetPY);this.cameraNY.lookAt(this.targetNY);this.cameraPZ.lookAt(this.targetPZ);this.cameraNZ.lookAt(this.targetNZ)};this.updateCubeMap=function(a,b){var c=this.renderTarget;c.activeCubeFace=0;a.render(b,this.cameraPX,c);c.activeCubeFace=1;a.render(b,this.cameraNX,c);c.activeCubeFace=2;a.render(b,this.cameraPY,c);c.activeCubeFace=3;a.render(b,
+this.cameraNY,c);c.activeCubeFace=4;a.render(b,this.cameraPZ,c);c.activeCubeFace=5;a.render(b,this.cameraNZ,c)}};THREE.CombinedCamera=function(a,b,c,d,f,g,e){THREE.Camera.call(this);this.fov=c;this.left=-a/2;this.right=a/2;this.top=b/2;this.bottom=-b/2;this.cameraO=new THREE.OrthographicCamera(a/-2,a/2,b/2,b/-2,g,e);this.cameraP=new THREE.PerspectiveCamera(c,a/b,d,f);this.zoom=1;this.toPerspective()};THREE.CombinedCamera.prototype=new THREE.Camera;THREE.CombinedCamera.prototype.constructor=THREE.CoolCamera;
+THREE.CombinedCamera.prototype.toPerspective=function(){this.near=this.cameraP.near;this.far=this.cameraP.far;this.cameraP.fov=this.fov/this.zoom;this.cameraP.updateProjectionMatrix();this.projectionMatrix=this.cameraP.projectionMatrix;this.inPersepectiveMode=!0;this.inOrthographicMode=!1};
+THREE.CombinedCamera.prototype.toOrthographic=function(){var a=this.cameraP.aspect,b=(this.cameraP.near+this.cameraP.far)/2,b=Math.tan(this.fov/2)*b,a=2*b*a/2,b=b/this.zoom,a=a/this.zoom;this.cameraO.left=-a;this.cameraO.right=a;this.cameraO.top=b;this.cameraO.bottom=-b;this.cameraO.updateProjectionMatrix();this.near=this.cameraO.near;this.far=this.cameraO.far;this.projectionMatrix=this.cameraO.projectionMatrix;this.inPersepectiveMode=!1;this.inOrthographicMode=!0};
+THREE.CombinedCamera.prototype.setFov=function(a){this.fov=a;this.inPersepectiveMode?this.toPerspective():this.toOrthographic()};THREE.CombinedCamera.prototype.setLens=function(a,b){var c=2*Math.atan((void 0!==b?b:24)/(2*a))*(180/Math.PI);this.setFov(c);return c};THREE.CombinedCamera.prototype.setZoom=function(a){this.zoom=a;this.inPersepectiveMode?this.toPerspective():this.toOrthographic()};
+THREE.CombinedCamera.prototype.toFrontView=function(){this.rotation.x=0;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toBackView=function(){this.rotation.x=0;this.rotation.y=Math.PI;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toLeftView=function(){this.rotation.x=0;this.rotation.y=-Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1};
+THREE.CombinedCamera.prototype.toRightView=function(){this.rotation.x=0;this.rotation.y=Math.PI/2;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toTopView=function(){this.rotation.x=-Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};THREE.CombinedCamera.prototype.toBottomView=function(){this.rotation.x=Math.PI/2;this.rotation.y=0;this.rotation.z=0;this.rotationAutoUpdate=!1};
+THREE.FirstPersonControls=function(a,b){function c(a,b){return function(){b.apply(a,arguments)}}this.object=a;this.target=new THREE.Vector3(0,0,0);this.domElement=void 0!==b?b:document;this.movementSpeed=1;this.lookSpeed=0.005;this.noFly=!1;this.lookVertical=!0;this.autoForward=!1;this.activeLook=!0;this.heightSpeed=!1;this.heightCoef=1;this.heightMin=0;this.constrainVertical=!1;this.verticalMin=0;this.verticalMax=Math.PI;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=this.autoSpeedFactor=
+0;this.mouseDragOn=this.freeze=this.moveRight=this.moveLeft=this.moveBackward=this.moveForward=!1;this.domElement===document?(this.viewHalfX=window.innerWidth/2,this.viewHalfY=window.innerHeight/2):(this.viewHalfX=this.domElement.offsetWidth/2,this.viewHalfY=this.domElement.offsetHeight/2,this.domElement.setAttribute("tabindex",-1));this.onMouseDown=function(a){this.domElement!==document&&this.domElement.focus();a.preventDefault();a.stopPropagation();if(this.activeLook)switch(a.button){case 0:this.moveForward=
+!0;break;case 2:this.moveBackward=!0}this.mouseDragOn=!0};this.onMouseUp=function(a){a.preventDefault();a.stopPropagation();if(this.activeLook)switch(a.button){case 0:this.moveForward=!1;break;case 2:this.moveBackward=!1}this.mouseDragOn=!1};this.onMouseMove=function(a){this.domElement===document?(this.mouseX=a.pageX-this.viewHalfX,this.mouseY=a.pageY-this.viewHalfY):(this.mouseX=a.pageX-this.domElement.offsetLeft-this.viewHalfX,this.mouseY=a.pageY-this.domElement.offsetTop-this.viewHalfY)};this.onKeyDown=
+function(a){switch(a.keyCode){case 38:case 87:this.moveForward=!0;break;case 37:case 65:this.moveLeft=!0;break;case 40:case 83:this.moveBackward=!0;break;case 39:case 68:this.moveRight=!0;break;case 82:this.moveUp=!0;break;case 70:this.moveDown=!0;break;case 81:this.freeze=!this.freeze}};this.onKeyUp=function(a){switch(a.keyCode){case 38:case 87:this.moveForward=!1;break;case 37:case 65:this.moveLeft=!1;break;case 40:case 83:this.moveBackward=!1;break;case 39:case 68:this.moveRight=!1;break;case 82:this.moveUp=
+!1;break;case 70:this.moveDown=!1}};this.update=function(a){var b=0;if(!this.freeze){this.heightSpeed?(b=THREE.Math.clamp(this.object.position.y,this.heightMin,this.heightMax)-this.heightMin,this.autoSpeedFactor=a*b*this.heightCoef):this.autoSpeedFactor=0;b=a*this.movementSpeed;(this.moveForward||this.autoForward&&!this.moveBackward)&&this.object.translateZ(-(b+this.autoSpeedFactor));this.moveBackward&&this.object.translateZ(b);this.moveLeft&&this.object.translateX(-b);this.moveRight&&this.object.translateX(b);
+this.moveUp&&this.object.translateY(b);this.moveDown&&this.object.translateY(-b);a*=this.lookSpeed;this.activeLook||(a=0);this.lon+=this.mouseX*a;this.lookVertical&&(this.lat-=this.mouseY*a);this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;var b=this.target,c=this.object.position;b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=c.y+100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);b=1;this.constrainVertical&&
+(b=Math.PI/(this.verticalMax-this.verticalMin));this.lon+=this.mouseX*a;this.lookVertical&&(this.lat-=this.mouseY*a*b);this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*Math.PI/180;this.theta=this.lon*Math.PI/180;if(this.constrainVertical)this.phi=THREE.Math.mapLinear(this.phi,0,Math.PI,this.verticalMin,this.verticalMax);b=this.target;c=this.object.position;b.x=c.x+100*Math.sin(this.phi)*Math.cos(this.theta);b.y=c.y+100*Math.cos(this.phi);b.z=c.z+100*Math.sin(this.phi)*Math.sin(this.theta);
+this.object.lookAt(b)}};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},!1);this.domElement.addEventListener("mousemove",c(this,this.onMouseMove),!1);this.domElement.addEventListener("mousedown",c(this,this.onMouseDown),!1);this.domElement.addEventListener("mouseup",c(this,this.onMouseUp),!1);this.domElement.addEventListener("keydown",c(this,this.onKeyDown),!1);this.domElement.addEventListener("keyup",c(this,this.onKeyUp),!1)};
+THREE.PathControls=function(a,b){function c(a){return 1>(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}function d(a,b){return function(){b.apply(a,arguments)}}function f(a,b,c,d){var f={name:c,fps:0.6,length:d,hierarchy:[]},e,g=b.getControlPointsArray(),h=b.getLength(),r=g.length,s=0;e=r-1;b={parent:-1,keys:[]};b.keys[0]={time:0,pos:g[0],rot:[0,0,0,1],scl:[1,1,1]};b.keys[e]={time:d,pos:g[e],rot:[0,0,0,1],scl:[1,1,1]};for(e=1;e<r-1;e++)s=d*h.chunks[e]/h.total,b.keys[e]={time:s,pos:g[e]};f.hierarchy[0]=b;THREE.AnimationHandler.add(f);
+return new THREE.Animation(a,c,THREE.AnimationHandler.CATMULLROM_FORWARD,!1)}function g(a,b){var c,d,f=new THREE.Geometry;for(c=0;c<a.points.length*b;c++)d=c/(a.points.length*b),d=a.getPoint(d),f.vertices[c]=new THREE.Vertex(new THREE.Vector3(d.x,d.y,d.z));return f}this.object=a;this.domElement=void 0!==b?b:document;this.id="PathControls"+THREE.PathControlsIdCounter++;this.duration=1E4;this.waypoints=[];this.useConstantSpeed=!0;this.resamplingCoef=50;this.debugPath=new THREE.Object3D;this.debugDummy=
+new THREE.Object3D;this.animationParent=new THREE.Object3D;this.lookSpeed=0.005;this.lookHorizontal=this.lookVertical=!0;this.verticalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.horizontalAngleMap={srcRange:[0,2*Math.PI],dstRange:[0,2*Math.PI]};this.target=new THREE.Object3D;this.theta=this.phi=this.lon=this.lat=this.mouseY=this.mouseX=0;this.domElement===document?(this.viewHalfX=window.innerWidth/2,this.viewHalfY=window.innerHeight/2):(this.viewHalfX=this.domElement.offsetWidth/
+2,this.viewHalfY=this.domElement.offsetHeight/2,this.domElement.setAttribute("tabindex",-1));var e=2*Math.PI,h=Math.PI/180;this.update=function(a){var b;this.lookHorizontal&&(this.lon+=this.mouseX*this.lookSpeed*a);this.lookVertical&&(this.lat-=this.mouseY*this.lookSpeed*a);this.lon=Math.max(0,Math.min(360,this.lon));this.lat=Math.max(-85,Math.min(85,this.lat));this.phi=(90-this.lat)*h;this.theta=this.lon*h;a=this.phi%e;this.phi=0<=a?a:a+e;b=this.verticalAngleMap.srcRange;a=this.verticalAngleMap.dstRange;
+b=THREE.Math.mapLinear(this.phi,b[0],b[1],a[0],a[1]);var d=a[1]-a[0];this.phi=c((b-a[0])/d)*d+a[0];b=this.horizontalAngleMap.srcRange;a=this.horizontalAngleMap.dstRange;b=THREE.Math.mapLinear(this.theta,b[0],b[1],a[0],a[1]);d=a[1]-a[0];this.theta=c((b-a[0])/d)*d+a[0];a=this.target.position;a.x=100*Math.sin(this.phi)*Math.cos(this.theta);a.y=100*Math.cos(this.phi);a.z=100*Math.sin(this.phi)*Math.sin(this.theta);this.object.lookAt(this.target.position)};this.onMouseMove=function(a){this.domElement===
+document?(this.mouseX=a.pageX-this.viewHalfX,this.mouseY=a.pageY-this.viewHalfY):(this.mouseX=a.pageX-this.domElement.offsetLeft-this.viewHalfX,this.mouseY=a.pageY-this.domElement.offsetTop-this.viewHalfY)};this.init=function(){this.spline=new THREE.Spline;this.spline.initFromArray(this.waypoints);this.useConstantSpeed&&this.spline.reparametrizeByArcLength(this.resamplingCoef);if(this.createDebugDummy){var a=new THREE.MeshLambertMaterial({color:30719}),b=new THREE.MeshLambertMaterial({color:65280}),
+c=new THREE.CubeGeometry(10,10,20),e=new THREE.CubeGeometry(2,2,10);this.animationParent=new THREE.Mesh(c,a);a=new THREE.Mesh(e,b);a.position.set(0,10,0);this.animation=f(this.animationParent,this.spline,this.id,this.duration);this.animationParent.add(this.object);this.animationParent.add(this.target);this.animationParent.add(a)}else this.animation=f(this.animationParent,this.spline,this.id,this.duration),this.animationParent.add(this.target),this.animationParent.add(this.object);if(this.createDebugPath){var a=
+this.debugPath,b=this.spline,e=g(b,10),c=g(b,10),h=new THREE.LineBasicMaterial({color:16711680,linewidth:3}),e=new THREE.Line(e,h),c=new THREE.ParticleSystem(c,new THREE.ParticleBasicMaterial({color:16755200,size:3}));e.scale.set(1,1,1);a.add(e);c.scale.set(1,1,1);a.add(c);for(var e=new THREE.SphereGeometry(1,16,8),h=new THREE.MeshBasicMaterial({color:65280}),o=0;o<b.points.length;o++)c=new THREE.Mesh(e,h),c.position.copy(b.points[o]),a.add(c)}this.domElement.addEventListener("mousemove",d(this,this.onMouseMove),
+!1)}};THREE.PathControlsIdCounter=0;
+THREE.FlyControls=function(a,b){function c(a,b){return function(){b.apply(a,arguments)}}this.object=a;this.domElement=void 0!==b?b:document;b&&this.domElement.setAttribute("tabindex",-1);this.movementSpeed=1;this.rollSpeed=0.005;this.autoForward=this.dragToLook=!1;this.object.useQuaternion=!0;this.tmpQuaternion=new THREE.Quaternion;this.mouseStatus=0;this.moveState={up:0,down:0,left:0,right:0,forward:0,back:0,pitchUp:0,pitchDown:0,yawLeft:0,yawRight:0,rollLeft:0,rollRight:0};this.moveVector=new THREE.Vector3(0,
+0,0);this.rotationVector=new THREE.Vector3(0,0,0);this.handleEvent=function(a){if("function"==typeof this[a.type])this[a.type](a)};this.keydown=function(a){if(!a.altKey){switch(a.keyCode){case 16:this.movementSpeedMultiplier=0.1;break;case 87:this.moveState.forward=1;break;case 83:this.moveState.back=1;break;case 65:this.moveState.left=1;break;case 68:this.moveState.right=1;break;case 82:this.moveState.up=1;break;case 70:this.moveState.down=1;break;case 38:this.moveState.pitchUp=1;break;case 40:this.moveState.pitchDown=
+1;break;case 37:this.moveState.yawLeft=1;break;case 39:this.moveState.yawRight=1;break;case 81:this.moveState.rollLeft=1;break;case 69:this.moveState.rollRight=1}this.updateMovementVector();this.updateRotationVector()}};this.keyup=function(a){switch(a.keyCode){case 16:this.movementSpeedMultiplier=1;break;case 87:this.moveState.forward=0;break;case 83:this.moveState.back=0;break;case 65:this.moveState.left=0;break;case 68:this.moveState.right=0;break;case 82:this.moveState.up=0;break;case 70:this.moveState.down=
+0;break;case 38:this.moveState.pitchUp=0;break;case 40:this.moveState.pitchDown=0;break;case 37:this.moveState.yawLeft=0;break;case 39:this.moveState.yawRight=0;break;case 81:this.moveState.rollLeft=0;break;case 69:this.moveState.rollRight=0}this.updateMovementVector();this.updateRotationVector()};this.mousedown=function(a){this.domElement!==document&&this.domElement.focus();a.preventDefault();a.stopPropagation();if(this.dragToLook)this.mouseStatus++;else switch(a.button){case 0:this.object.moveForward=
+!0;break;case 2:this.object.moveBackward=!0}};this.mousemove=function(a){if(!this.dragToLook||0<this.mouseStatus){var b=this.getContainerDimensions(),c=b.size[0]/2,e=b.size[1]/2;this.moveState.yawLeft=-(a.pageX-b.offset[0]-c)/c;this.moveState.pitchDown=(a.pageY-b.offset[1]-e)/e;this.updateRotationVector()}};this.mouseup=function(a){a.preventDefault();a.stopPropagation();if(this.dragToLook)this.mouseStatus--,this.moveState.yawLeft=this.moveState.pitchDown=0;else switch(a.button){case 0:this.moveForward=
+!1;break;case 2:this.moveBackward=!1}this.updateRotationVector()};this.update=function(a){var b=a*this.movementSpeed,a=a*this.rollSpeed;this.object.translateX(this.moveVector.x*b);this.object.translateY(this.moveVector.y*b);this.object.translateZ(this.moveVector.z*b);this.tmpQuaternion.set(this.rotationVector.x*a,this.rotationVector.y*a,this.rotationVector.z*a,1).normalize();this.object.quaternion.multiplySelf(this.tmpQuaternion);this.object.matrix.setPosition(this.object.position);this.object.matrix.setRotationFromQuaternion(this.object.quaternion);
+this.object.matrixWorldNeedsUpdate=!0};this.updateMovementVector=function(){var a=this.moveState.forward||this.autoForward&&!this.moveState.back?1:0;this.moveVector.x=-this.moveState.left+this.moveState.right;this.moveVector.y=-this.moveState.down+this.moveState.up;this.moveVector.z=-a+this.moveState.back};this.updateRotationVector=function(){this.rotationVector.x=-this.moveState.pitchDown+this.moveState.pitchUp;this.rotationVector.y=-this.moveState.yawRight+this.moveState.yawLeft;this.rotationVector.z=
+-this.moveState.rollRight+this.moveState.rollLeft};this.getContainerDimensions=function(){return this.domElement!=document?{size:[this.domElement.offsetWidth,this.domElement.offsetHeight],offset:[this.domElement.offsetLeft,this.domElement.offsetTop]}:{size:[window.innerWidth,window.innerHeight],offset:[0,0]}};this.domElement.addEventListener("mousemove",c(this,this.mousemove),!1);this.domElement.addEventListener("mousedown",c(this,this.mousedown),!1);this.domElement.addEventListener("mouseup",c(this,
+this.mouseup),!1);this.domElement.addEventListener("keydown",c(this,this.keydown),!1);this.domElement.addEventListener("keyup",c(this,this.keyup),!1);this.updateMovementVector();this.updateRotationVector()};
+THREE.RollControls=function(a,b){this.object=a;this.domElement=void 0!==b?b:document;this.mouseLook=!0;this.autoForward=!1;this.rollSpeed=this.movementSpeed=this.lookSpeed=1;this.constrainVertical=[-0.9,0.9];this.object.matrixAutoUpdate=!1;this.forward=new THREE.Vector3(0,0,1);this.roll=0;var c=new THREE.Vector3,d=new THREE.Vector3,f=new THREE.Vector3,g=new THREE.Matrix4,e=!1,h=1,i=0,j=0,k=0,q=0,m=0,o=window.innerWidth/2,p=window.innerHeight/2;this.update=function(a){if(this.mouseLook){var b=a*this.lookSpeed;
+this.rotateHorizontally(b*q);this.rotateVertically(b*m)}b=a*this.movementSpeed;this.object.translateZ(-b*(0<i||this.autoForward&&!(0>i)?1:i));this.object.translateX(b*j);this.object.translateY(b*k);e&&(this.roll+=this.rollSpeed*a*h);if(this.forward.y>this.constrainVertical[1])this.forward.y=this.constrainVertical[1],this.forward.normalize();else if(this.forward.y<this.constrainVertical[0])this.forward.y=this.constrainVertical[0],this.forward.normalize();f.copy(this.forward);d.set(0,1,0);c.cross(d,
+f).normalize();d.cross(f,c).normalize();this.object.matrix.n11=c.x;this.object.matrix.n12=d.x;this.object.matrix.n13=f.x;this.object.matrix.n21=c.y;this.object.matrix.n22=d.y;this.object.matrix.n23=f.y;this.object.matrix.n31=c.z;this.object.matrix.n32=d.z;this.object.matrix.n33=f.z;g.identity();g.n11=Math.cos(this.roll);g.n12=-Math.sin(this.roll);g.n21=Math.sin(this.roll);g.n22=Math.cos(this.roll);this.object.matrix.multiplySelf(g);this.object.matrixWorldNeedsUpdate=!0;this.object.matrix.n14=this.object.position.x;
+this.object.matrix.n24=this.object.position.y;this.object.matrix.n34=this.object.position.z};this.translateX=function(a){this.object.position.x+=this.object.matrix.n11*a;this.object.position.y+=this.object.matrix.n21*a;this.object.position.z+=this.object.matrix.n31*a};this.translateY=function(a){this.object.position.x+=this.object.matrix.n12*a;this.object.position.y+=this.object.matrix.n22*a;this.object.position.z+=this.object.matrix.n32*a};this.translateZ=function(a){this.object.position.x-=this.object.matrix.n13*
+a;this.object.position.y-=this.object.matrix.n23*a;this.object.position.z-=this.object.matrix.n33*a};this.rotateHorizontally=function(a){c.set(this.object.matrix.n11,this.object.matrix.n21,this.object.matrix.n31);c.multiplyScalar(a);this.forward.subSelf(c);this.forward.normalize()};this.rotateVertically=function(a){d.set(this.object.matrix.n12,this.object.matrix.n22,this.object.matrix.n32);d.multiplyScalar(a);this.forward.addSelf(d);this.forward.normalize()};this.domElement.addEventListener("contextmenu",
+function(a){a.preventDefault()},!1);this.domElement.addEventListener("mousemove",function(a){q=(a.clientX-o)/window.innerWidth;m=(a.clientY-p)/window.innerHeight},!1);this.domElement.addEventListener("mousedown",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=1;break;case 2:i=-1}},!1);this.domElement.addEventListener("mouseup",function(a){a.preventDefault();a.stopPropagation();switch(a.button){case 0:i=0;break;case 2:i=0}},!1);this.domElement.addEventListener("keydown",
+function(a){switch(a.keyCode){case 38:case 87:i=1;break;case 37:case 65:j=-1;break;case 40:case 83:i=-1;break;case 39:case 68:j=1;break;case 81:e=!0;h=1;break;case 69:e=!0;h=-1;break;case 82:k=1;break;case 70:k=-1}},!1);this.domElement.addEventListener("keyup",function(a){switch(a.keyCode){case 38:case 87:i=0;break;case 37:case 65:j=0;break;case 40:case 83:i=0;break;case 39:case 68:j=0;break;case 81:e=!1;break;case 69:e=!1;break;case 82:k=0;break;case 70:k=0}},!1)};
+THREE.TrackballControls=function(a,b){THREE.EventTarget.call(this);var c=this;this.object=a;this.domElement=void 0!==b?b:document;this.enabled=!0;this.screen={width:window.innerWidth,height:window.innerHeight,offsetLeft:0,offsetTop:0};this.radius=(this.screen.width+this.screen.height)/4;this.rotateSpeed=1;this.zoomSpeed=1.2;this.panSpeed=0.3;this.staticMoving=this.noPan=this.noZoom=this.noRotate=!1;this.dynamicDampingFactor=0.2;this.minDistance=0;this.maxDistance=Infinity;this.keys=[65,83,68];this.target=
+new THREE.Vector3;var d=new THREE.Vector3,f=!1,g=-1,e=new THREE.Vector3,h=new THREE.Vector3,i=new THREE.Vector3,j=new THREE.Vector2,k=new THREE.Vector2,q=new THREE.Vector2,m=new THREE.Vector2,o={type:"change"};this.handleEvent=function(a){if("function"==typeof this[a.type])this[a.type](a)};this.getMouseOnScreen=function(a,b){return new THREE.Vector2(0.5*((a-c.screen.offsetLeft)/c.radius),0.5*((b-c.screen.offsetTop)/c.radius))};this.getMouseProjectionOnBall=function(a,b){var d=new THREE.Vector3((a-
+0.5*c.screen.width-c.screen.offsetLeft)/c.radius,(0.5*c.screen.height+c.screen.offsetTop-b)/c.radius,0),f=d.length();1<f?d.normalize():d.z=Math.sqrt(1-f*f);e.copy(c.object.position).subSelf(c.target);f=c.object.up.clone().setLength(d.y);f.addSelf(c.object.up.clone().crossSelf(e).setLength(d.x));f.addSelf(e.setLength(d.z));return f};this.rotateCamera=function(){var a=Math.acos(h.dot(i)/h.length()/i.length());if(a){var b=(new THREE.Vector3).cross(h,i).normalize(),d=new THREE.Quaternion,a=a*c.rotateSpeed;
+d.setFromAxisAngle(b,-a);d.multiplyVector3(e);d.multiplyVector3(c.object.up);d.multiplyVector3(i);c.staticMoving?h=i:(d.setFromAxisAngle(b,a*(c.dynamicDampingFactor-1)),d.multiplyVector3(h))}};this.zoomCamera=function(){var a=1+(k.y-j.y)*c.zoomSpeed;1!==a&&0<a&&(e.multiplyScalar(a),c.staticMoving?j=k:j.y+=(k.y-j.y)*this.dynamicDampingFactor)};this.panCamera=function(){var a=m.clone().subSelf(q);if(a.lengthSq()){a.multiplyScalar(e.length()*c.panSpeed);var b=e.clone().crossSelf(c.object.up).setLength(a.x);
+b.addSelf(c.object.up.clone().setLength(a.y));c.object.position.addSelf(b);c.target.addSelf(b);c.staticMoving?q=m:q.addSelf(a.sub(m,q).multiplyScalar(c.dynamicDampingFactor))}};this.checkDistances=function(){if(!c.noZoom||!c.noPan)c.object.position.lengthSq()>c.maxDistance*c.maxDistance&&c.object.position.setLength(c.maxDistance),e.lengthSq()<c.minDistance*c.minDistance&&c.object.position.add(c.target,e.setLength(c.minDistance))};this.update=function(){e.copy(c.object.position).subSelf(c.target);
+c.noRotate||c.rotateCamera();c.noZoom||c.zoomCamera();c.noPan||c.panCamera();c.object.position.add(c.target,e);c.checkDistances();c.object.lookAt(c.target);0<d.distanceTo(c.object.position)&&(c.dispatchEvent(o),d.copy(c.object.position))};this.domElement.addEventListener("contextmenu",function(a){a.preventDefault()},!1);this.domElement.addEventListener("mousemove",function(a){c.enabled&&(f&&(h=i=c.getMouseProjectionOnBall(a.clientX,a.clientY),j=k=c.getMouseOnScreen(a.clientX,a.clientY),q=m=c.getMouseOnScreen(a.clientX,
+a.clientY),f=!1),-1!==g&&(0===g&&!c.noRotate?i=c.getMouseProjectionOnBall(a.clientX,a.clientY):1===g&&!c.noZoom?k=c.getMouseOnScreen(a.clientX,a.clientY):2===g&&!c.noPan&&(m=c.getMouseOnScreen(a.clientX,a.clientY))))},!1);this.domElement.addEventListener("mousedown",function(a){if(c.enabled&&(a.preventDefault(),a.stopPropagation(),-1===g))g=a.button,0===g&&!c.noRotate?h=i=c.getMouseProjectionOnBall(a.clientX,a.clientY):1===g&&!c.noZoom?j=k=c.getMouseOnScreen(a.clientX,a.clientY):this.noPan||(q=m=
+c.getMouseOnScreen(a.clientX,a.clientY))},!1);this.domElement.addEventListener("mouseup",function(a){c.enabled&&(a.preventDefault(),a.stopPropagation(),g=-1)},!1);window.addEventListener("keydown",function(a){c.enabled&&-1===g&&(a.keyCode===c.keys[0]&&!c.noRotate?g=0:a.keyCode===c.keys[1]&&!c.noZoom?g=1:a.keyCode===c.keys[2]&&!c.noPan&&(g=2),-1!==g&&(f=!0))},!1);window.addEventListener("keyup",function(){c.enabled&&-1!==g&&(g=-1)},!1)};
+THREE.CubeGeometry=function(a,b,c,d,f,g,e,h){function i(a,b,c,e,h,i,k,m){var n,o=d||1,q=f||1,p=h/2,r=i/2,s=j.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)n="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)n="y",q=g||1;else if("z"===a&&"y"===b||"y"===a&&"z"===b)n="x",o=g||1;var l=o+1,t=q+1,w=h/o,E=i/q,S=new THREE.Vector3;S[n]=0<k?1:-1;for(h=0;h<t;h++)for(i=0;i<l;i++){var R=new THREE.Vector3;R[a]=(i*w-p)*c;R[b]=(h*E-r)*e;R[n]=k;j.vertices.push(new THREE.Vertex(R))}for(h=0;h<q;h++)for(i=0;i<o;i++)a=
+new THREE.Face4(i+l*h+s,i+l*(h+1)+s,i+1+l*(h+1)+s,i+1+l*h+s),a.normal.copy(S),a.vertexNormals.push(S.clone(),S.clone(),S.clone(),S.clone()),a.materialIndex=m,j.faces.push(a),j.faceVertexUvs[0].push([new THREE.UV(i/o,h/q),new THREE.UV(i/o,(h+1)/q),new THREE.UV((i+1)/o,(h+1)/q),new THREE.UV((i+1)/o,h/q)])}THREE.Geometry.call(this);var j=this,k=a/2,q=b/2,m=c/2,o,p,n,r,s,t;if(void 0!==e){if(e instanceof Array)this.materials=e;else{this.materials=[];for(o=0;6>o;o++)this.materials.push(e)}o=0;r=1;p=2;s=
+3;n=4;t=5}else this.materials=[];this.sides={px:!0,nx:!0,py:!0,ny:!0,pz:!0,nz:!0};if(void 0!=h)for(var w in h)void 0!==this.sides[w]&&(this.sides[w]=h[w]);this.sides.px&&i("z","y",-1,-1,c,b,k,o);this.sides.nx&&i("z","y",1,-1,c,b,-k,r);this.sides.py&&i("x","z",1,1,a,c,q,p);this.sides.ny&&i("x","z",1,-1,a,c,-q,s);this.sides.pz&&i("x","y",1,-1,a,b,m,n);this.sides.nz&&i("x","y",-1,-1,a,b,-m,t);this.computeCentroids();this.mergeVertices()};THREE.CubeGeometry.prototype=new THREE.Geometry;
+THREE.CubeGeometry.prototype.constructor=THREE.CubeGeometry;
+THREE.CylinderGeometry=function(a,b,c,d,f,g){THREE.Geometry.call(this);var a=void 0!==a?a:20,b=void 0!==b?b:20,c=void 0!==c?c:100,e=c/2,d=d||8,f=f||1,h,i,j=[],k=[];for(i=0;i<=f;i++){var q=[],m=[],o=i/f,p=o*(b-a)+a;for(h=0;h<=d;h++){var n=h/d,r=p*Math.sin(2*n*Math.PI),s=-o*c+e,t=p*Math.cos(2*n*Math.PI);this.vertices.push(new THREE.Vertex(new THREE.Vector3(r,s,t)));q.push(this.vertices.length-1);m.push(new THREE.UV(n,o))}j.push(q);k.push(m)}for(i=0;i<f;i++)for(h=0;h<d;h++){var c=j[i][h],q=j[i+1][h],
+m=j[i+1][h+1],o=j[i][h+1],p=this.vertices[c].position.clone().setY(0).normalize(),n=this.vertices[q].position.clone().setY(0).normalize(),r=this.vertices[m].position.clone().setY(0).normalize(),s=this.vertices[o].position.clone().setY(0).normalize(),t=k[i][h].clone(),w=k[i+1][h].clone(),u=k[i+1][h+1].clone(),v=k[i][h+1].clone();this.faces.push(new THREE.Face4(c,q,m,o,[p,n,r,s]));this.faceVertexUvs[0].push([t,w,u,v])}if(!g&&0<a){this.vertices.push(new THREE.Vertex(new THREE.Vector3(0,e,0)));for(h=
+0;h<d;h++)c=j[0][h],q=j[0][h+1],m=this.vertices.length-1,p=new THREE.Vector3(0,1,0),n=new THREE.Vector3(0,1,0),r=new THREE.Vector3(0,1,0),t=k[0][h].clone(),w=k[0][h+1].clone(),u=new THREE.UV(w.u,0),this.faces.push(new THREE.Face3(c,q,m,[p,n,r])),this.faceVertexUvs[0].push([t,w,u])}if(!g&&0<b){this.vertices.push(new THREE.Vertex(new THREE.Vector3(0,-e,0)));for(h=0;h<d;h++)c=j[i][h+1],q=j[i][h],m=this.vertices.length-1,p=new THREE.Vector3(0,-1,0),n=new THREE.Vector3(0,-1,0),r=new THREE.Vector3(0,-1,
+0),t=k[i][h+1].clone(),w=k[i][h].clone(),u=new THREE.UV(w.u,1),this.faces.push(new THREE.Face3(c,q,m,[p,n,r])),this.faceVertexUvs[0].push([t,w,u])}this.computeCentroids();this.computeFaceNormals()};THREE.CylinderGeometry.prototype=new THREE.Geometry;THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;
+THREE.ExtrudeGeometry=function(a,b){if("undefined"!==typeof a){THREE.Geometry.call(this);var a=a instanceof Array?a:[a],c,d,f=a.length;this.shapebb=a[f-1].getBoundingBox();for(d=0;d<f;d++)c=a[d],this.addShape(c,b);this.computeCentroids();this.computeFaceNormals()}};THREE.ExtrudeGeometry.prototype=new THREE.Geometry;THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry;
+THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.log("die");return b.clone().multiplyScalar(c).addSelf(a)}function d(a,b,c){var d=THREE.ExtrudeGeometry.__v1,f=THREE.ExtrudeGeometry.__v2,e=THREE.ExtrudeGeometry.__v3,g=THREE.ExtrudeGeometry.__v4,h=THREE.ExtrudeGeometry.__v5,i=THREE.ExtrudeGeometry.__v6;d.set(a.x-b.x,a.y-b.y);f.set(a.x-c.x,a.y-c.y);d=d.normalize();f=f.normalize();e.set(-d.y,d.x);g.set(f.y,-f.x);h.copy(a).addSelf(e);i.copy(a).addSelf(g);if(h.equals(i))return g.clone();
+h.copy(b).addSelf(e);i.copy(c).addSelf(g);e=d.dot(g);g=i.subSelf(h).dot(g);0===e&&(console.log("Either infinite or no solutions!"),0===g?console.log("Its finite solutions."):console.log("Too bad, no solutions."));g/=e;return 0>g?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).addSelf(h).subSelf(a).clone()}function f(a){for(y=a.length;0<=--y;){$=y;C=y-1;0>C&&(C=a.length-1);for(var b=
+0,c=o+2*k,b=0;b<c;b++){var d=L*b,f=L*(b+1),e=ca+$+d,g=ca+C+d,h=ca+C+f,i=ca+$+f,e=e+D,g=g+D,h=h+D,i=i+D;B.faces.push(new THREE.Face4(e,g,h,i,null,null,u));var f=B.vertices[e].position.x,d=B.vertices[e].position.y,e=B.vertices[e].position.z,j=B.vertices[g].position.x,l=B.vertices[g].position.y,g=B.vertices[g].position.z,m=B.vertices[h].position.x,n=B.vertices[h].position.y,h=B.vertices[h].position.z,q=B.vertices[i].position.x,p=B.vertices[i].position.y,i=B.vertices[i].position.z;0.01>Math.abs(d-l)?
+B.faceVertexUvs[0].push([new THREE.UV(f,e),new THREE.UV(j,g),new THREE.UV(m,h),new THREE.UV(q,i)]):B.faceVertexUvs[0].push([new THREE.UV(d,e),new THREE.UV(l,g),new THREE.UV(n,h),new THREE.UV(p,i)])}}}function g(a,b,c){B.vertices.push(new THREE.Vertex(new THREE.Vector3(a,b,c)))}function e(a,b,c){a+=D;b+=D;c+=D;B.faces.push(new THREE.Face3(a,b,c,null,null,w));var d=B.vertices[b].position.x,b=B.vertices[b].position.y,f=B.vertices[c].position.x,c=B.vertices[c].position.y;B.faceVertexUvs[0].push([new THREE.UV(B.vertices[a].position.x,
+1-B.vertices[a].position.y),new THREE.UV(d,1-b),new THREE.UV(f,1-c)])}var h=void 0!==b.amount?b.amount:100,i=void 0!==b.bevelThickness?b.bevelThickness:6,j=void 0!==b.bevelSize?b.bevelSize:i-2,k=void 0!==b.bevelSegments?b.bevelSegments:3,q=void 0!==b.bevelEnabled?b.bevelEnabled:!0,m=void 0!==b.curveSegments?b.curveSegments:12,o=void 0!==b.steps?b.steps:1,p=b.bendPath,n=b.extrudePath,r,s=!1,t=void 0!==b.useSpacedPoints?b.useSpacedPoints:!1,w=b.material,u=b.extrudeMaterial;if(n)r=n.getPoints(m),o=r.length,
+s=!0,q=!1;q||(j=i=k=0);var v,A,F,B=this,D=this.vertices.length;p&&a.addWrapPath(p);m=t?a.extractAllSpacedPoints(m):a.extractAllPoints(m);p=m.shape;m=m.holes;if(n=!THREE.Shape.Utils.isClockWise(p)){p=p.reverse();for(A=0,F=m.length;A<F;A++)v=m[A],THREE.Shape.Utils.isClockWise(v)&&(m[A]=v.reverse());n=!1}n=THREE.Shape.Utils.triangulateShape(p,m);t=p;for(A=0,F=m.length;A<F;A++)v=m[A],p=p.concat(v);for(var H,I,Q,P,L=p.length,K=n.length,O=[],y=0,l=t.length,$=l-1,C=y+1;y<l;y++,$++,C++)$===l&&($=0),C===l&&
+(C=0),O[y]=d(t[y],t[$],t[C]);var E=[],S,R=O.concat();for(A=0,F=m.length;A<F;A++){v=m[A];S=[];for(y=0,l=v.length,$=l-1,C=y+1;y<l;y++,$++,C++)$===l&&($=0),C===l&&(C=0),S[y]=d(v[y],v[$],v[C]);E.push(S);R=R.concat(S)}for(H=0;H<k;H++){I=H/k;Q=i*(1-I);I=j*Math.sin(I*Math.PI/2);for(y=0,l=t.length;y<l;y++)P=c(t[y],O[y],I),g(P.x,P.y,-Q);for(A=0,F=m.length;A<F;A++){v=m[A];S=E[A];for(y=0,l=v.length;y<l;y++)P=c(v[y],S[y],I),g(P.x,P.y,-Q)}}I=j;for(y=0;y<L;y++)P=q?c(p[y],R[y],I):p[y],s?g(P.x,P.y+r[0].y,r[0].x):
+g(P.x,P.y,0);for(H=1;H<=o;H++)for(y=0;y<L;y++)P=q?c(p[y],R[y],I):p[y],s?g(P.x,P.y+r[H-1].y,r[H-1].x):g(P.x,P.y,h/o*H);for(H=k-1;0<=H;H--){I=H/k;Q=i*(1-I);I=j*Math.sin(I*Math.PI/2);for(y=0,l=t.length;y<l;y++)P=c(t[y],O[y],I),g(P.x,P.y,h+Q);for(A=0,F=m.length;A<F;A++){v=m[A];S=E[A];for(y=0,l=v.length;y<l;y++)P=c(v[y],S[y],I),s?g(P.x,P.y+r[o-1].y,r[o-1].x+Q):g(P.x,P.y,h+Q)}}if(q){i=0*L;for(y=0;y<K;y++)h=n[y],e(h[2]+i,h[1]+i,h[0]+i);i=L*(o+2*k);for(y=0;y<K;y++)h=n[y],e(h[0]+i,h[1]+i,h[2]+i)}else{for(y=
+0;y<K;y++)h=n[y],e(h[2],h[1],h[0]);for(y=0;y<K;y++)h=n[y],e(h[0]+L*o,h[1]+L*o,h[2]+L*o)}var ca=0;f(t);ca+=t.length;for(A=0,F=m.length;A<F;A++)v=m[A],f(v),ca+=v.length};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2;THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;
+THREE.LatheGeometry=function(a,b,c){THREE.Geometry.call(this);this.steps=b||12;this.angle=c||2*Math.PI;for(var b=this.angle/this.steps,c=[],d=[],f=[],g=[],e=(new THREE.Matrix4).setRotationZ(b),h=0;h<a.length;h++)this.vertices.push(new THREE.Vertex(a[h])),c[h]=a[h].clone(),d[h]=this.vertices.length-1;for(var i=0;i<=this.angle+0.001;i+=b){for(h=0;h<c.length;h++)i<this.angle?(c[h]=e.multiplyVector3(c[h].clone()),this.vertices.push(new THREE.Vertex(c[h])),f[h]=this.vertices.length-1):f=g;0==i&&(g=d);
+for(h=0;h<d.length-1;h++)this.faces.push(new THREE.Face4(f[h],f[h+1],d[h+1],d[h])),this.faceVertexUvs[0].push([new THREE.UV(1-i/this.angle,h/a.length),new THREE.UV(1-i/this.angle,(h+1)/a.length),new THREE.UV(1-(i-b)/this.angle,(h+1)/a.length),new THREE.UV(1-(i-b)/this.angle,h/a.length)]);d=f;f=[]}this.computeCentroids();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=new THREE.Geometry;THREE.LatheGeometry.prototype.constructor=THREE.LatheGeometry;
+THREE.PlaneGeometry=function(a,b,c,d){THREE.Geometry.call(this);for(var f=a/2,g=b/2,c=c||1,d=d||1,e=c+1,h=d+1,i=a/c,j=b/d,k=new THREE.Vector3(0,0,1),a=0;a<h;a++)for(b=0;b<e;b++)this.vertices.push(new THREE.Vertex(new THREE.Vector3(b*i-f,-(a*j-g),0)));for(a=0;a<d;a++)for(b=0;b<c;b++)f=new THREE.Face4(b+e*a,b+e*(a+1),b+1+e*(a+1),b+1+e*a),f.normal.copy(k),f.vertexNormals.push(k.clone(),k.clone(),k.clone(),k.clone()),this.faces.push(f),this.faceVertexUvs[0].push([new THREE.UV(b/c,a/d),new THREE.UV(b/
+c,(a+1)/d),new THREE.UV((b+1)/c,(a+1)/d),new THREE.UV((b+1)/c,a/d)]);this.computeCentroids()};THREE.PlaneGeometry.prototype=new THREE.Geometry;THREE.PlaneGeometry.prototype.constructor=THREE.PlaneGeometry;
+THREE.SphereGeometry=function(a,b,c,d,f,g,e){THREE.Geometry.call(this);var a=a||50,d=void 0!==d?d:0,f=void 0!==f?f:2*Math.PI,g=void 0!==g?g:0,e=void 0!==e?e:Math.PI,b=Math.max(3,Math.floor(b)||8),c=Math.max(2,Math.floor(c)||6),h,i,j=[],k=[];for(i=0;i<=c;i++){var q=[],m=[];for(h=0;h<=b;h++){var o=h/b,p=i/c,n=-a*Math.cos(d+o*f)*Math.sin(g+p*e),r=a*Math.cos(g+p*e),s=a*Math.sin(d+o*f)*Math.sin(g+p*e);this.vertices.push(new THREE.Vertex(new THREE.Vector3(n,r,s)));q.push(this.vertices.length-1);m.push(new THREE.UV(o,
+p))}j.push(q);k.push(m)}for(i=0;i<c;i++)for(h=0;h<b;h++){var d=j[i][h+1],f=j[i][h],g=j[i+1][h],e=j[i+1][h+1],q=this.vertices[d].position.clone().normalize(),m=this.vertices[f].position.clone().normalize(),o=this.vertices[g].position.clone().normalize(),p=this.vertices[e].position.clone().normalize(),n=k[i][h+1].clone(),r=k[i][h].clone(),s=k[i+1][h].clone(),t=k[i+1][h+1].clone();Math.abs(this.vertices[d].position.y)==a?(this.faces.push(new THREE.Face3(d,g,e,[q,o,p])),this.faceVertexUvs[0].push([n,
+s,t])):Math.abs(this.vertices[g].position.y)==a?(this.faces.push(new THREE.Face3(d,f,g,[q,m,o])),this.faceVertexUvs[0].push([n,r,s])):(this.faces.push(new THREE.Face4(d,f,g,e,[q,m,o,p])),this.faceVertexUvs[0].push([n,r,s,t]))}this.computeCentroids();this.computeFaceNormals();this.boundingSphere={radius:a}};THREE.SphereGeometry.prototype=new THREE.Geometry;THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;
+THREE.TextGeometry=function(a,b){var c=(new THREE.TextPath(a,b)).toShapes();b.amount=void 0!==b.height?b.height:50;if(void 0===b.bevelThickness)b.bevelThickness=10;if(void 0===b.bevelSize)b.bevelSize=8;if(void 0===b.bevelEnabled)b.bevelEnabled=!1;if(b.bend){var d=c[c.length-1].getBoundingBox().maxX;b.bendPath=new THREE.QuadraticBezierCurve(new THREE.Vector2(0,0),new THREE.Vector2(d/2,120),new THREE.Vector2(d,0))}THREE.ExtrudeGeometry.call(this,c,b)};THREE.TextGeometry.prototype=new THREE.ExtrudeGeometry;
+THREE.TextGeometry.prototype.constructor=THREE.TextGeometry;
+THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){return this.faces[this.face][this.weight][this.style]},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]=a},drawText:function(a){for(var b=this.getFace(),c=this.size/b.resolution,d=
+0,f=(""+a).split(""),g=f.length,e=[],a=0;a<g;a++){var h=new THREE.Path,h=this.extractGlyphPoints(f[a],b,c,d,h),d=d+h.offset;e.push(h.path)}return{paths:e,offset:d/2}},extractGlyphPoints:function(a,b,c,d,f){var g=[],e,h,i,j,k,q,m,o,p,n,r,s=b.glyphs[a]||b.glyphs["?"];if(s){if(s.o){b=s._cachedOutline||(s._cachedOutline=s.o.split(" "));j=b.length;for(a=0;a<j;)switch(i=b[a++],i){case "m":i=b[a++]*c+d;k=b[a++]*c;g.push(new THREE.Vector2(i,k));f.moveTo(i,k);break;case "l":i=b[a++]*c+d;k=b[a++]*c;g.push(new THREE.Vector2(i,
+k));f.lineTo(i,k);break;case "q":i=b[a++]*c+d;k=b[a++]*c;o=b[a++]*c+d;p=b[a++]*c;f.quadraticCurveTo(o,p,i,k);if(e=g[g.length-1]){q=e.x;m=e.y;for(e=1,h=this.divisions;e<=h;e++){var t=e/h,w=THREE.Shape.Utils.b2(t,q,o,i),t=THREE.Shape.Utils.b2(t,m,p,k);g.push(new THREE.Vector2(w,t))}}break;case "b":if(i=b[a++]*c+d,k=b[a++]*c,o=b[a++]*c+d,p=b[a++]*-c,n=b[a++]*c+d,r=b[a++]*-c,f.bezierCurveTo(i,k,o,p,n,r),e=g[g.length-1]){q=e.x;m=e.y;for(e=1,h=this.divisions;e<=h;e++)t=e/h,w=THREE.Shape.Utils.b3(t,q,o,
+n,i),t=THREE.Shape.Utils.b3(t,m,p,r,k),g.push(new THREE.Vector2(w,t))}}}return{offset:s.ha*c,points:g,path:f}}}};
+(function(a){var b=function(a){for(var b=a.length,f=0,g=b-1,e=0;e<b;g=e++)f+=a[g].x*a[e].y-a[e].x*a[g].y;return 0.5*f};a.Triangulate=function(a,d){var f=a.length;if(3>f)return null;var g=[],e=[],h=[],i,j,k;if(0<b(a))for(j=0;j<f;j++)e[j]=j;else for(j=0;j<f;j++)e[j]=f-1-j;var q=2*f;for(j=f-1;2<f;){if(0>=q--){console.log("Warning, unable to triangulate polygon!");break}i=j;f<=i&&(i=0);j=i+1;f<=j&&(j=0);k=j+1;f<=k&&(k=0);var m;a:{m=a;var o=i,p=j,n=k,r=f,s=e,t=void 0,w=void 0,u=void 0,v=void 0,A=void 0,
+F=void 0,B=void 0,D=void 0,H=void 0,w=m[s[o]].x,u=m[s[o]].y,v=m[s[p]].x,A=m[s[p]].y,F=m[s[n]].x,B=m[s[n]].y;if(1.0E-10>(v-w)*(B-u)-(A-u)*(F-w))m=!1;else{for(t=0;t<r;t++)if(!(t==o||t==p||t==n)){var D=m[s[t]].x,H=m[s[t]].y,I=void 0,Q=void 0,P=void 0,L=void 0,K=void 0,O=void 0,y=void 0,l=void 0,$=void 0,C=void 0,E=void 0,S=void 0,I=P=K=void 0,I=F-v,Q=B-A,P=w-F,L=u-B,K=v-w,O=A-u,y=D-w,l=H-u,$=D-v,C=H-A,E=D-F,S=H-B,I=I*C-Q*$,K=K*l-O*y,P=P*S-L*E;if(0<=I&&0<=P&&0<=K){m=!1;break a}}m=!0}}if(m){g.push([a[e[i]],
+a[e[j]],a[e[k]]]);h.push([e[i],e[j],e[k]]);for(i=j,k=j+1;k<f;i++,k++)e[i]=e[k];f--;q=2*f}}return d?h:g};a.Triangulate.area=b;return a})(THREE.FontUtils);self._typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};
+THREE.TorusGeometry=function(a,b,c,d,f){THREE.Geometry.call(this);this.radius=a||100;this.tube=b||40;this.segmentsR=c||8;this.segmentsT=d||6;this.arc=f||2*Math.PI;f=new THREE.Vector3;a=[];b=[];for(c=0;c<=this.segmentsR;c++)for(d=0;d<=this.segmentsT;d++){var g=d/this.segmentsT*this.arc,e=2*c/this.segmentsR*Math.PI;f.x=this.radius*Math.cos(g);f.y=this.radius*Math.sin(g);var h=new THREE.Vector3;h.x=(this.radius+this.tube*Math.cos(e))*Math.cos(g);h.y=(this.radius+this.tube*Math.cos(e))*Math.sin(g);h.z=
+this.tube*Math.sin(e);this.vertices.push(new THREE.Vertex(h));a.push(new THREE.UV(d/this.segmentsT,1-c/this.segmentsR));b.push(h.clone().subSelf(f).normalize())}for(c=1;c<=this.segmentsR;c++)for(d=1;d<=this.segmentsT;d++){var f=(this.segmentsT+1)*c+d-1,g=(this.segmentsT+1)*(c-1)+d-1,e=(this.segmentsT+1)*(c-1)+d,h=(this.segmentsT+1)*c+d,i=new THREE.Face4(f,g,e,h,[b[f],b[g],b[e],b[h]]);i.normal.addSelf(b[f]);i.normal.addSelf(b[g]);i.normal.addSelf(b[e]);i.normal.addSelf(b[h]);i.normal.normalize();this.faces.push(i);
+this.faceVertexUvs[0].push([a[f].clone(),a[g].clone(),a[e].clone(),a[h].clone()])}this.computeCentroids()};THREE.TorusGeometry.prototype=new THREE.Geometry;THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry;
+THREE.TorusKnotGeometry=function(a,b,c,d,f,g,e){function h(a,b,c,d,f,e){var g=Math.cos(a);Math.cos(b);b=Math.sin(a);a*=c/d;c=Math.cos(a);g*=0.5*f*(2+c);b=0.5*f*(2+c)*b;f=0.5*e*f*Math.sin(a);return new THREE.Vector3(g,b,f)}THREE.Geometry.call(this);this.radius=a||200;this.tube=b||40;this.segmentsR=c||64;this.segmentsT=d||8;this.p=f||2;this.q=g||3;this.heightScale=e||1;this.grid=Array(this.segmentsR);c=new THREE.Vector3;d=new THREE.Vector3;f=new THREE.Vector3;for(a=0;a<this.segmentsR;++a){this.grid[a]=
+Array(this.segmentsT);for(b=0;b<this.segmentsT;++b){var i=2*(a/this.segmentsR)*this.p*Math.PI,e=2*(b/this.segmentsT)*Math.PI,g=h(i,e,this.q,this.p,this.radius,this.heightScale),i=h(i+0.01,e,this.q,this.p,this.radius,this.heightScale);c.sub(i,g);d.add(i,g);f.cross(c,d);d.cross(f,c);f.normalize();d.normalize();i=-this.tube*Math.cos(e);e=this.tube*Math.sin(e);g.x+=i*d.x+e*f.x;g.y+=i*d.y+e*f.y;g.z+=i*d.z+e*f.z;this.grid[a][b]=this.vertices.push(new THREE.Vertex(new THREE.Vector3(g.x,g.y,g.z)))-1}}for(a=
+0;a<this.segmentsR;++a)for(b=0;b<this.segmentsT;++b){var f=(a+1)%this.segmentsR,g=(b+1)%this.segmentsT,c=this.grid[a][b],d=this.grid[f][b],f=this.grid[f][g],g=this.grid[a][g],e=new THREE.UV(a/this.segmentsR,b/this.segmentsT),i=new THREE.UV((a+1)/this.segmentsR,b/this.segmentsT),j=new THREE.UV((a+1)/this.segmentsR,(b+1)/this.segmentsT),k=new THREE.UV(a/this.segmentsR,(b+1)/this.segmentsT);this.faces.push(new THREE.Face4(c,d,f,g));this.faceVertexUvs[0].push([e,i,j,k])}this.computeCentroids();this.computeFaceNormals();
+this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=new THREE.Geometry;THREE.TorusKnotGeometry.prototype.constructor=THREE.TorusKnotGeometry;
+THREE.PolyhedronGeometry=function(a,b,c,d){function f(a){var b=new THREE.Vertex(a.normalize());b.index=i.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+0.5,a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+0.5;b.uv=new THREE.UV(c,a);return b}function g(a,b,c,d){1>d?(d=new THREE.Face3(a.index,b.index,c.index,[a.position.clone(),b.position.clone(),c.position.clone()]),d.centroid.addSelf(a.position).addSelf(b.position).addSelf(c.position).divideScalar(3),d.normal=d.centroid.clone().normalize(),
+i.faces.push(d),d=Math.atan2(d.centroid.z,-d.centroid.x),i.faceVertexUvs[0].push([h(a.uv,a.position,d),h(b.uv,b.position,d),h(c.uv,c.position,d)])):(d-=1,g(a,e(a,b),e(a,c),d),g(e(a,b),b,e(b,c),d),g(e(a,c),e(b,c),c,d),g(e(a,b),e(b,c),e(a,c),d))}function e(a,b){q[a.index]||(q[a.index]=[]);q[b.index]||(q[b.index]=[]);var c=q[a.index][b.index];void 0===c&&(q[a.index][b.index]=q[b.index][a.index]=c=f((new THREE.Vector3).add(a.position,b.position).divideScalar(2)));return c}function h(a,b,c){0>c&&1===a.u&&
+(a=new THREE.UV(a.u-1,a.v));0===b.x&&0===b.z&&(a=new THREE.UV(c/2/Math.PI+0.5,a.v));return a}THREE.Geometry.call(this);for(var c=c||1,d=d||0,i=this,j=0,k=a.length;j<k;j++)f(new THREE.Vector3(a[j][0],a[j][1],a[j][2]));for(var q=[],a=this.vertices,j=0,k=b.length;j<k;j++)g(a[b[j][0]],a[b[j][1]],a[b[j][2]],d);this.mergeVertices();j=0;for(k=this.vertices.length;j<k;j++)this.vertices[j].position.multiplyScalar(c);this.boundingSphere={radius:c}};THREE.PolyhedronGeometry.prototype=new THREE.Geometry;
+THREE.PolyhedronGeometry.prototype.constructor=THREE.PolyhedronGeometry;THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[[-1,c,0],[1,c,0],[-1,-c,0],[1,-c,0],[0,-1,c],[0,1,c],[0,-1,-c],[0,1,-c],[c,0,-1],[c,0,1],[-c,0,-1],[-c,0,1]],[[0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],[1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],[3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],[4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1]],a,b)};THREE.IcosahedronGeometry.prototype=new THREE.Geometry;
+THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;THREE.OctahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],[[0,2,4],[0,4,3],[0,3,5],[0,5,2],[1,2,5],[1,5,3],[1,3,4],[1,4,2]],a,b)};THREE.OctahedronGeometry.prototype=new THREE.Geometry;THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry;
+THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[[1,1,1],[-1,-1,1],[-1,1,-1],[1,-1,-1]],[[2,1,0],[0,3,2],[1,3,0],[2,3,1]],a,b)};THREE.TetrahedronGeometry.prototype=new THREE.Geometry;THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry;
+THREE.AxisHelper=function(){THREE.Object3D.call(this);var a=new THREE.Geometry;a.vertices.push(new THREE.Vertex);a.vertices.push(new THREE.Vertex(new THREE.Vector3(0,100,0)));var b=new THREE.CylinderGeometry(0,5,25,5,1),c;c=new THREE.Line(a,new THREE.LineBasicMaterial({color:16711680}));c.rotation.z=-Math.PI/2;this.add(c);c=new THREE.Mesh(b,new THREE.MeshBasicMaterial({color:16711680}));c.position.x=100;c.rotation.z=-Math.PI/2;this.add(c);c=new THREE.Line(a,new THREE.LineBasicMaterial({color:65280}));
+this.add(c);c=new THREE.Mesh(b,new THREE.MeshBasicMaterial({color:65280}));c.position.y=100;this.add(c);c=new THREE.Line(a,new THREE.LineBasicMaterial({color:255}));c.rotation.x=Math.PI/2;this.add(c);c=new THREE.Mesh(b,new THREE.MeshBasicMaterial({color:255}));c.position.z=100;c.rotation.x=Math.PI/2;this.add(c)};THREE.AxisHelper.prototype=new THREE.Object3D;THREE.AxisHelper.prototype.constructor=THREE.AxisHelper;
+THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.lineGeometry.vertices.push(new THREE.Vertex(new THREE.Vector3));d.lineGeometry.colors.push(new THREE.Color(b));void 0===d.pointMap[a]&&(d.pointMap[a]=[]);d.pointMap[a].push(d.lineGeometry.vertices.length-1)}THREE.Object3D.call(this);var d=this;this.lineGeometry=new THREE.Geometry;this.lineMaterial=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors});this.pointMap={};b("n1","n2",16755200);b("n2",
+"n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);
+this.update(a);this.lines=new THREE.Line(this.lineGeometry,this.lineMaterial,THREE.LinePieces);this.add(this.lines)};THREE.CameraHelper.prototype=new THREE.Object3D;THREE.CameraHelper.prototype.constructor=THREE.CameraHelper;
+THREE.CameraHelper.prototype.update=function(a){function b(a,b,g,e){THREE.CameraHelper.__v.set(b,g,e);THREE.CameraHelper.__projector.unprojectVector(THREE.CameraHelper.__v,THREE.CameraHelper.__c);a=c.pointMap[a];if(void 0!==a){b=0;for(g=a.length;b<g;b++)c.lineGeometry.vertices[a[b]].position.copy(THREE.CameraHelper.__v)}}var c=this;THREE.CameraHelper.__c.projectionMatrix.copy(a.projectionMatrix);b("c",0,0,-1);b("t",0,0,1);b("n1",-1,-1,-1);b("n2",1,-1,-1);b("n3",-1,1,-1);b("n4",1,1,-1);b("f1",-1,-1,
+1);b("f2",1,-1,1);b("f3",-1,1,1);b("f4",1,1,1);b("u1",0.7,1.1,-1);b("u2",-0.7,1.1,-1);b("u3",0,2,-1);b("cf1",-1,0,1);b("cf2",1,0,1);b("cf3",0,-1,1);b("cf4",0,1,1);b("cn1",-1,0,-1);b("cn2",1,0,-1);b("cn3",0,-1,-1);b("cn4",0,1,-1);this.lineGeometry.__dirtyVertices=!0};THREE.CameraHelper.__projector=new THREE.Projector;THREE.CameraHelper.__v=new THREE.Vector3;THREE.CameraHelper.__c=new THREE.Camera;
+THREE.SubdivisionModifier=function(a){this.subdivisions=void 0===a?1:a;this.useOldVertexColors=!1;this.supportUVs=!0};THREE.SubdivisionModifier.prototype.constructor=THREE.SubdivisionModifier;THREE.SubdivisionModifier.prototype.modify=function(a){for(var b=this.subdivisions;0<b--;)this.smooth(a)};
+THREE.SubdivisionModifier.prototype.smooth=function(a){function b(a,b,c,d,h,i){var j=new THREE.Face4(a,b,c,d,null,h.color,h.material);if(e.useOldVertexColors){j.vertexColors=[];for(var k,n,o,q=0;4>q;q++){o=i[q];k=new THREE.Color;k.setRGB(0,0,0);for(var p=0;p<o.length;p++)n=h.vertexColors[o[p]-1],k.r+=n.r,k.g+=n.g,k.b+=n.b;k.r/=o.length;k.g/=o.length;k.b/=o.length;j.vertexColors[q]=k}}f.push(j);(!e.supportUVs||0!=m.length)&&g.push([m[a],m[b],m[c],m[d]])}function c(a,b){return Math.min(a,b)+"_"+Math.max(a,
+b)}var d=[],f=[],g=[],e=this,h=a.vertices,d=a.faces,i=h.concat(),j=[],k={},q={},m=[],o,p,n,r,s,t=a.faceVertexUvs[0];for(o=0,p=t.length;o<p;o++)for(n=0,r=t[o].length;n<r;n++)s=d[o]["abcd".charAt(n)],m[s]||(m[s]=t[o][n]);var w;for(o=0,p=d.length;o<p;o++)if(s=d[o],j.push(s.centroid),i.push(new THREE.Vertex(s.centroid)),e.supportUVs&&0!=m.length){w=new THREE.UV;if(s instanceof THREE.Face3)w.u=m[s.a].u+m[s.b].u+m[s.c].u,w.v=m[s.a].v+m[s.b].v+m[s.c].v,w.u/=3,w.v/=3;else if(s instanceof THREE.Face4)w.u=
+m[s.a].u+m[s.b].u+m[s.c].u+m[s.d].u,w.v=m[s.a].v+m[s.b].v+m[s.c].v+m[s.d].v,w.u/=4,w.v/=4;m.push(w)}p=function(a){function b(a,c,d){void 0===a[c]&&(a[c]=[]);a[c].push(d)}var d,f,e,g,h={};for(d=0,f=a.faces.length;d<f;d++)e=a.faces[d],e instanceof THREE.Face3?(g=c(e.a,e.b),b(h,g,d),g=c(e.b,e.c),b(h,g,d),g=c(e.c,e.a),b(h,g,d)):e instanceof THREE.Face4&&(g=c(e.a,e.b),b(h,g,d),g=c(e.b,e.c),b(h,g,d),g=c(e.c,e.d),b(h,g,d),g=c(e.d,e.a),b(h,g,d));return h}(a);var u=0,t=h.length,v,A,F={},B={},D=function(a,
+b){void 0===F[a]&&(F[a]=[]);F[a].push(b)},H=function(a,b){void 0===B[a]&&(B[a]={});B[a][b]=null};for(o in p){w=p[o];v=o.split("_");A=v[0];v=v[1];D(A,[A,v]);D(v,[A,v]);for(n=0,r=w.length;n<r;n++)s=w[n],H(A,s,o),H(v,s,o);2>w.length&&(q[o]=!0)}for(o in p)if(w=p[o],s=w[0],w=w[1],v=o.split("_"),A=v[0],v=v[1],r=new THREE.Vector3,q[o]?(r.addSelf(h[A].position),r.addSelf(h[v].position),r.multiplyScalar(0.5)):(r.addSelf(j[s]),r.addSelf(j[w]),r.addSelf(h[A].position),r.addSelf(h[v].position),r.multiplyScalar(0.25)),
+k[o]=t+d.length+u,i.push(new THREE.Vertex(r)),u++,e.supportUVs&&0!=m.length)w=new THREE.UV,w.u=m[A].u+m[v].u,w.v=m[A].v+m[v].v,w.u/=2,w.v/=2,m.push(w);var I,Q;v=["123","12","2","23"];r=["123","23","3","31"];var D=["123","31","1","12"],H=["1234","12","2","23"],P=["1234","23","3","34"],L=["1234","34","4","41"],K=["1234","41","1","12"];for(o=0,p=j.length;o<p;o++)s=d[o],w=t+o,s instanceof THREE.Face3?(u=c(s.a,s.b),A=c(s.b,s.c),I=c(s.c,s.a),b(w,k[u],s.b,k[A],s,v),b(w,k[A],s.c,k[I],s,r),b(w,k[I],s.a,k[u],
+s,D)):s instanceof THREE.Face4?(u=c(s.a,s.b),A=c(s.b,s.c),I=c(s.c,s.d),Q=c(s.d,s.a),b(w,k[u],s.b,k[A],s,H),b(w,k[A],s.c,k[I],s,P),b(w,k[I],s.d,k[Q],s,L),b(w,k[Q],s.a,k[u],s,K)):console.log("face should be a face!",s);d=i;i=new THREE.Vector3;k=new THREE.Vector3;for(o=0,p=h.length;o<p;o++)if(void 0!==F[o]){i.set(0,0,0);k.set(0,0,0);s=new THREE.Vector3(0,0,0);w=0;for(n in B[o])i.addSelf(j[n]),w++;u=0;t=F[o].length;for(n=0;n<t;n++)q[c(F[o][n][0],F[o][n][1])]&&u++;if(2!=u){i.divideScalar(w);for(n=0;n<
+t;n++)w=F[o][n],w=h[w[0]].position.clone().addSelf(h[w[1]].position).divideScalar(2),k.addSelf(w);k.divideScalar(t);s.addSelf(h[o].position);s.multiplyScalar(t-3);s.addSelf(i);s.addSelf(k.multiplyScalar(2));s.divideScalar(t);d[o].position=s}}a.vertices=d;a.faces=f;a.faceVertexUvs[0]=g;delete a.__tmpVertices;a.computeCentroids();a.computeFaceNormals();a.computeVertexNormals()};
+THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}};
+THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:"anonymous",addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/
+a.total).toFixed(0)+"%"):b+((a.loaded/1E3).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");a.pop();return(1>a.length?".":a.join("/"))+"/"},initMaterials:function(a,b,c){a.materials=[];for(var d=0;d<b.length;++d)a.materials[d]=THREE.Loader.prototype.createMaterial(b[d],c)},hasNormals:function(a){var b,c,d=a.materials.length;for(c=0;c<d;c++)if(b=a.materials[c],b instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=
+Math.log(a)/Math.LN2;return Math.floor(a)==a}function d(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function f(a,b){var e=new Image;e.onload=function(){if(!c(this.width)||!c(this.height)){var b=d(this.width),e=d(this.height);a.image.width=b;a.image.height=e;a.image.getContext("2d").drawImage(this,0,0,b,e)}else a.image=this;a.needsUpdate=!0};e.crossOrigin=h.crossOrigin;e.src=b}function g(a,c,d,e,g,h){var i=document.createElement("canvas");a[c]=new THREE.Texture(i);a[c].sourceFile=d;
+if(e){a[c].repeat.set(e[0],e[1]);if(1!=e[0])a[c].wrapS=THREE.RepeatWrapping;if(1!=e[1])a[c].wrapT=THREE.RepeatWrapping}g&&a[c].offset.set(g[0],g[1]);if(h){e={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(void 0!==e[h[0]])a[c].wrapS=e[h[0]];if(void 0!==e[h[1]])a[c].wrapT=e[h[1]]}f(a[c],b+"/"+d)}function e(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var h=this,i="MeshLambertMaterial",j={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,wireframe:a.wireframe};a.shading&&
+("Phong"==a.shading?i="MeshPhongMaterial":"Basic"==a.shading&&(i="MeshBasicMaterial"));if(a.blending)if("Additive"==a.blending)j.blending=THREE.AdditiveBlending;else if("Subtractive"==a.blending)j.blending=THREE.SubtractiveBlending;else if("Multiply"==a.blending)j.blending=THREE.MultiplyBlending;if(void 0!==a.transparent||1>a.opacity)j.transparent=a.transparent;if(void 0!==a.depthTest)j.depthTest=a.depthTest;if(void 0!==a.vertexColors)if("face"==a.vertexColors)j.vertexColors=THREE.FaceColors;else if(a.vertexColors)j.vertexColors=
+THREE.VertexColors;if(a.colorDiffuse)j.color=e(a.colorDiffuse);else if(a.DbgColor)j.color=a.DbgColor;if(a.colorSpecular)j.specular=e(a.colorSpecular);if(a.colorAmbient)j.ambient=e(a.colorAmbient);if(a.transparency)j.opacity=a.transparency;if(a.specularCoef)j.shininess=a.specularCoef;a.mapDiffuse&&b&&g(j,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap);a.mapLight&&b&&g(j,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap);a.mapNormal&&b&&g(j,"normalMap",
+a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap);a.mapSpecular&&b&&g(j,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap);if(a.mapNormal){var i=THREE.ShaderUtils.lib.normal,k=THREE.UniformsUtils.clone(i.uniforms);k.tNormal.texture=j.normalMap;if(a.mapNormalFactor)k.uNormalScale.value=a.mapNormalFactor;if(j.map)k.tDiffuse.texture=j.map,k.enableDiffuse.value=!0;if(j.specularMap)k.tSpecular.texture=j.specularMap,k.enableSpecular.value=!0;if(j.lightMap)k.tAO.texture=
+j.lightMap,k.enableAO.value=!0;k.uDiffuseColor.value.setHex(j.color);k.uSpecularColor.value.setHex(j.specular);k.uAmbientColor.value.setHex(j.ambient);k.uShininess.value=j.shininess;if(void 0!==j.opacity)k.uOpacity.value=j.opacity;j=new THREE.ShaderMaterial({fragmentShader:i.fragmentShader,vertexShader:i.vertexShader,uniforms:k,lights:!0,fog:!0})}else j=new THREE[i](j);if(void 0!==a.DbgName)j.name=a.DbgName;return j}};THREE.BinaryLoader=function(a){THREE.Loader.call(this,a)};
+THREE.BinaryLoader.prototype=new THREE.Loader;THREE.BinaryLoader.prototype.constructor=THREE.BinaryLoader;THREE.BinaryLoader.prototype.supr=THREE.Loader.prototype;THREE.BinaryLoader.prototype.load=function(a,b,c,d){var c=c?c:this.extractUrlBase(a),d=d?d:this.extractUrlBase(a),f=this.showProgress?THREE.Loader.prototype.updateProgress:null;this.onLoadStart();this.loadAjaxJSON(this,a,b,c,d,f)};
+THREE.BinaryLoader.prototype.loadAjaxJSON=function(a,b,c,d,f,g){var e=new XMLHttpRequest;e.onreadystatechange=function(){if(4==e.readyState)if(200==e.status||0==e.status){var h=JSON.parse(e.responseText);a.loadAjaxBuffers(h,c,f,d,g)}else console.error("THREE.BinaryLoader: Couldn't load ["+b+"] ["+e.status+"]")};e.open("GET",b,!0);e.overrideMimeType&&e.overrideMimeType("text/plain; charset=x-user-defined");e.setRequestHeader("Content-Type","text/plain");e.send(null)};
+THREE.BinaryLoader.prototype.loadAjaxBuffers=function(a,b,c,d,f){var g=new XMLHttpRequest,e=c+"/"+a.buffers,h=0;g.onreadystatechange=function(){4==g.readyState?200==g.status||0==g.status?THREE.BinaryLoader.prototype.createBinModel(g.response,b,d,a.materials):console.error("THREE.BinaryLoader: Couldn't load ["+e+"] ["+g.status+"]"):3==g.readyState?f&&(0==h&&(h=g.getResponseHeader("Content-Length")),f({total:h,loaded:g.responseText.length})):2==g.readyState&&(h=g.getResponseHeader("Content-Length"))};
+g.open("GET",e,!0);g.responseType="arraybuffer";g.send(null)};
+THREE.BinaryLoader.prototype.createBinModel=function(a,b,c,d){var f=function(b){var c,f,i,j,k,q,m,o,p,n,r,s,t,w,u;function v(a){return a%4?4-a%4:0}function A(a,b){return(new Uint8Array(a,b,1))[0]}function F(a,b){return(new Uint32Array(a,b,1))[0]}function B(b,c){var d,e,f,g,h,i,j,k,l=new Uint32Array(a,c,3*b);for(d=0;d<b;d++){e=l[3*d];f=l[3*d+1];g=l[3*d+2];h=y[2*e];e=y[2*e+1];i=y[2*f];j=y[2*f+1];f=y[2*g];k=y[2*g+1];g=L.faceVertexUvs[0];var m=[];m.push(new THREE.UV(h,e));m.push(new THREE.UV(i,j));m.push(new THREE.UV(f,
+k));g.push(m)}}function D(b,c){var d,e,f,g,h,i,j,k,l,m,n=new Uint32Array(a,c,4*b);for(d=0;d<b;d++){e=n[4*d];f=n[4*d+1];g=n[4*d+2];h=n[4*d+3];i=y[2*e];e=y[2*e+1];j=y[2*f];l=y[2*f+1];k=y[2*g];m=y[2*g+1];g=y[2*h];f=y[2*h+1];h=L.faceVertexUvs[0];var o=[];o.push(new THREE.UV(i,e));o.push(new THREE.UV(j,l));o.push(new THREE.UV(k,m));o.push(new THREE.UV(g,f));h.push(o)}}function H(b,c,d){for(var e,f,g,h,c=new Uint32Array(a,c,3*b),i=new Uint16Array(a,d,b),d=0;d<b;d++)e=c[3*d],f=c[3*d+1],g=c[3*d+2],h=i[d],
+L.faces.push(new THREE.Face3(e,f,g,null,null,h))}function I(b,c,d){for(var e,f,g,h,i,c=new Uint32Array(a,c,4*b),j=new Uint16Array(a,d,b),d=0;d<b;d++)e=c[4*d],f=c[4*d+1],g=c[4*d+2],h=c[4*d+3],i=j[d],L.faces.push(new THREE.Face4(e,f,g,h,null,null,i))}function Q(b,c,d,e){for(var f,g,h,i,j,k,l,c=new Uint32Array(a,c,3*b),d=new Uint32Array(a,d,3*b),m=new Uint16Array(a,e,b),e=0;e<b;e++){f=c[3*e];g=c[3*e+1];h=c[3*e+2];j=d[3*e];k=d[3*e+1];l=d[3*e+2];i=m[e];var n=O[3*k],o=O[3*k+1];k=O[3*k+2];var q=O[3*l],p=
+O[3*l+1];l=O[3*l+2];L.faces.push(new THREE.Face3(f,g,h,[new THREE.Vector3(O[3*j],O[3*j+1],O[3*j+2]),new THREE.Vector3(n,o,k),new THREE.Vector3(q,p,l)],null,i))}}function P(b,c,d,e){for(var f,g,h,i,j,k,l,m,n,c=new Uint32Array(a,c,4*b),d=new Uint32Array(a,d,4*b),o=new Uint16Array(a,e,b),e=0;e<b;e++){f=c[4*e];g=c[4*e+1];h=c[4*e+2];i=c[4*e+3];k=d[4*e];l=d[4*e+1];m=d[4*e+2];n=d[4*e+3];j=o[e];var q=O[3*l],p=O[3*l+1];l=O[3*l+2];var r=O[3*m],s=O[3*m+1];m=O[3*m+2];var t=O[3*n],u=O[3*n+1];n=O[3*n+2];L.faces.push(new THREE.Face4(f,
+g,h,i,[new THREE.Vector3(O[3*k],O[3*k+1],O[3*k+2]),new THREE.Vector3(q,p,l),new THREE.Vector3(r,s,m),new THREE.Vector3(t,u,n)],null,j))}}var L=this,K=0,O=[],y=[],l,$,C;THREE.Geometry.call(this);THREE.Loader.prototype.initMaterials(L,d,b);(function(a,b,c){for(var a=new Uint8Array(a,b,c),d="",e=0;e<c;e++)d+=String.fromCharCode(a[b+e]);return d})(a,K,12);c=A(a,K+12);A(a,K+13);A(a,K+14);A(a,K+15);f=A(a,K+16);i=A(a,K+17);j=A(a,K+18);k=A(a,K+19);q=F(a,K+20);m=F(a,K+20+4);o=F(a,K+20+8);b=F(a,K+20+12);p=
+F(a,K+20+16);n=F(a,K+20+20);r=F(a,K+20+24);s=F(a,K+20+28);t=F(a,K+20+32);w=F(a,K+20+36);u=F(a,K+20+40);K+=c;c=3*f+k;C=4*f+k;l=b*c;$=p*(c+3*i);f=n*(c+3*j);k=r*(c+3*i+3*j);c=s*C;i=t*(C+4*i);j=w*(C+4*j);K+=function(b){var b=new Float32Array(a,b,3*q),c,d,e,f;for(c=0;c<q;c++)d=b[3*c],e=b[3*c+1],f=b[3*c+2],L.vertices.push(new THREE.Vertex(new THREE.Vector3(d,e,f)));return 3*q*Float32Array.BYTES_PER_ELEMENT}(K);K+=function(b){if(m){var b=new Int8Array(a,b,3*m),c,d,e,f;for(c=0;c<m;c++)d=b[3*c],e=b[3*c+1],
+f=b[3*c+2],O.push(d/127,e/127,f/127)}return 3*m*Int8Array.BYTES_PER_ELEMENT}(K);K+=v(3*m);K+=function(b){if(o){var b=new Float32Array(a,b,2*o),c,d,e;for(c=0;c<o;c++)d=b[2*c],e=b[2*c+1],y.push(d,e)}return 2*o*Float32Array.BYTES_PER_ELEMENT}(K);l=K+l+v(2*b);$=l+$+v(2*p);f=$+f+v(2*n);k=f+k+v(2*r);c=k+c+v(2*s);i=c+i+v(2*t);j=i+j+v(2*w);(function(a){if(n){var b=a+3*n*Uint32Array.BYTES_PER_ELEMENT;H(n,a,b+3*n*Uint32Array.BYTES_PER_ELEMENT);B(n,b)}})($);(function(a){if(r){var b=a+3*r*Uint32Array.BYTES_PER_ELEMENT,
+c=b+3*r*Uint32Array.BYTES_PER_ELEMENT;Q(r,a,b,c+3*r*Uint32Array.BYTES_PER_ELEMENT);B(r,c)}})(f);(function(a){if(w){var b=a+4*w*Uint32Array.BYTES_PER_ELEMENT;I(w,a,b+4*w*Uint32Array.BYTES_PER_ELEMENT);D(w,b)}})(i);(function(a){if(u){var b=a+4*u*Uint32Array.BYTES_PER_ELEMENT,c=b+4*u*Uint32Array.BYTES_PER_ELEMENT;P(u,a,b,c+4*u*Uint32Array.BYTES_PER_ELEMENT);D(u,c)}})(j);b&&H(b,K,K+3*b*Uint32Array.BYTES_PER_ELEMENT);(function(a){if(p){var b=a+3*p*Uint32Array.BYTES_PER_ELEMENT;Q(p,a,b,b+3*p*Uint32Array.BYTES_PER_ELEMENT)}})(l);
+s&&I(s,k,k+4*s*Uint32Array.BYTES_PER_ELEMENT);(function(a){if(t){var b=a+4*t*Uint32Array.BYTES_PER_ELEMENT;P(t,a,b,b+4*t*Uint32Array.BYTES_PER_ELEMENT)}})(c);this.computeCentroids();this.computeFaceNormals();THREE.Loader.prototype.hasNormals(this)&&this.computeTangents()};f.prototype=new THREE.Geometry;f.prototype.constructor=f;b(new f(c))};
+THREE.ColladaLoader=function(){function a(a,d,f){U=a;d=d||Ta;void 0!==f&&(a=f.split("/"),a.pop(),Sa=(1>a.length?".":a.join("/"))+"/");if((a=U.evaluate("//dae:asset",U,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null).iterateNext())&&a.childNodes)for(f=0;f<a.childNodes.length;f++){var i=a.childNodes[f];switch(i.nodeName){case "unit":(i=i.getAttribute("meter"))&&parseFloat(i);break;case "up_axis":Fa=i.textContent.charAt(0)}}if(!Ea.convertUpAxis||Fa===Ea.upAxis)Wa=null;else switch(Fa){case "X":Wa="Y"===
+Ea.upAxis?"XtoY":"XtoZ";break;case "Y":Wa="X"===Ea.upAxis?"YtoX":"YtoZ";break;case "Z":Wa="X"===Ea.upAxis?"ZtoX":"ZtoY"}Ka=b("//dae:library_images/dae:image",e,"image");ib=b("//dae:library_materials/dae:material",B,"material");db=b("//dae:library_effects/dae:effect",P,"effect");ha=b("//dae:library_geometries/dae:geometry",r,"geometry");lb=b(".//dae:library_cameras/dae:camera",$,"camera");qa=b("//dae:library_controllers/dae:controller",h,"controller");Ga=b("//dae:library_animations/dae:animation",
+K,"animation");Za=b(".//dae:library_visual_scenes/dae:visual_scene",k,"visual_scene");La=[];sa=[];(a=U.evaluate(".//dae:scene/dae:instance_visual_scene",U,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null).iterateNext())?(a=a.getAttribute("url").replace(/^#/,""),ea=Za[0<a.length?a:"visual_scene0"]):ea=null;ba=new THREE.Object3D;for(a=0;a<ea.nodes.length;a++)ba.add(g(ea.nodes[a]));cb=[];c(ba);a={scene:ba,morphs:La,skins:sa,animations:cb,dae:{images:Ka,materials:ib,cameras:lb,effects:db,geometries:ha,controllers:qa,
+animations:Ga,visualScenes:Za,scene:ea}};d&&d(a);return a}function b(a,b,c){for(var a=U.evaluate(a,U,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null),d={},e=a.iterateNext(),f=0;e;){e=(new b).parse(e);if(!e.id||0==e.id.length)e.id=c+f++;d[e.id]=e;e=a.iterateNext()}return d}function c(a){var b=ea.getChildById(a.name,!0),d=null;if(b&&b.keys){d={fps:60,hierarchy:[{node:b,keys:b.keys,sids:b.sids}],node:a,name:"animation_"+a.name,length:0};cb.push(d);for(var e=0,f=b.keys.length;e<f;e++)d.length=Math.max(d.length,
+b.keys[e].time)}else d={hierarchy:[{keys:[],sids:[]}]};e=0;for(f=a.children.length;e<f;e++)for(var b=0,g=c(a.children[e]).hierarchy.length;b<g;b++)d.hierarchy.push({keys:[],sids:[]});return d}function d(a,b,c,e){a.world=a.world||new THREE.Matrix4;a.world.copy(a.matrix);if(a.channels&&a.channels.length){var f=a.channels[0].sampler.output[c];f instanceof THREE.Matrix4&&a.world.copy(f)}e&&a.world.multiply(e,a.world);b.push(a);for(e=0;e<a.nodes.length;e++)d(a.nodes[e],b,c,a.world)}function f(a,b,c){var e,
+f=qa[b.url];if(!f||!f.skin)console.log("ColladaLoader: Could not find skin controller.");else if(!b.skeleton||!b.skeleton.length)console.log("ColladaLoader: Could not find the skeleton for the skin. ");else{var c=1E6,g=-c,h=0;for(e in Ga)for(var i=Ga[e],j=0;j<i.sampler.length;j++){var k=i.sampler[j];k.create();c=Math.min(c,k.startTime);g=Math.max(g,k.endTime);h=Math.max(h,k.input.length)}e=h;for(var b=ea.getChildById(b.skeleton[0],!0)||ea.getChildBySid(b.skeleton[0],!0),l,m,g=new THREE.Vector3,n,
+j=0;j<a.vertices.length;j++)f.skin.bindShapeMatrix.multiplyVector3(a.vertices[j].position);for(c=0;c<e;c++){h=[];i=[];for(j=0;j<a.vertices.length;j++)i.push(new THREE.Vertex(new THREE.Vector3));d(b,h,c);j=h;k=f.skin;for(m=0;m<j.length;m++)if(l=j[m],n=-1,"JOINT"==l.type){for(var o=0;o<k.joints.length;o++)if(l.sid==k.joints[o]){n=o;break}if(0<=n){o=k.invBindMatrices[n];l.invBindMatrix=o;l.skinningMatrix=new THREE.Matrix4;l.skinningMatrix.multiply(l.world,o);l.weights=[];for(o=0;o<k.weights.length;o++)for(var q=
+0;q<k.weights[o].length;q++){var p=k.weights[o][q];p.joint==n&&l.weights.push(p)}}else throw"ColladaLoader: Could not find joint '"+l.sid+"'.";}for(j=0;j<h.length;j++)if("JOINT"==h[j].type)for(k=0;k<h[j].weights.length;k++)l=h[j].weights[k],m=l.index,l=l.weight,n=a.vertices[m],m=i[m],g.x=n.position.x,g.y=n.position.y,g.z=n.position.z,h[j].skinningMatrix.multiplyVector3(g),m.position.x+=g.x*l,m.position.y+=g.y*l,m.position.z+=g.z*l;a.morphTargets.push({name:"target_"+c,vertices:i})}}}function g(a){var b=
+new THREE.Object3D,c,d,e,h;for(e=0;e<a.controllers.length;e++){var i=qa[a.controllers[e].url];switch(i.type){case "skin":if(ha[i.skin.source]){var j=new n;j.url=i.skin.source;j.instance_material=a.controllers[e].instance_material;a.geometries.push(j);c=a.controllers[e]}else if(qa[i.skin.source]&&(d=i=qa[i.skin.source],i.morph&&ha[i.morph.source]))j=new n,j.url=i.morph.source,j.instance_material=a.controllers[e].instance_material,a.geometries.push(j);break;case "morph":if(ha[i.morph.source])j=new n,
+j.url=i.morph.source,j.instance_material=a.controllers[e].instance_material,a.geometries.push(j),d=a.controllers[e];console.log("ColladaLoader: Morph-controller partially supported.")}}for(e=0;e<a.geometries.length;e++){var i=a.geometries[e],j=i.instance_material,i=ha[i.url],k={},l=[],m=0,q;if(i&&i.mesh&&i.mesh.primitives){if(0==b.name.length)b.name=i.id;if(j)for(h=0;h<j.length;h++){q=j[h];var p=ib[q.target],r=db[p.instance_effect.url].shader;r.material.opacity=!r.material.opacity?1:r.material.opacity;
+k[q.symbol]=m;l.push(r.material);q=r.material;q.name=null==p.name||""===p.name?p.id:p.name;m++}j=q||new THREE.MeshLambertMaterial({color:14540253,shading:THREE.FlatShading});i=i.mesh.geometry3js;if(1<m){j=new THREE.MeshFaceMaterial;i.materials=l;for(h=0;h<i.faces.length;h++)l=i.faces[h],l.materialIndex=k[l.daeMaterial]}if(void 0!==c)f(i,c),j.morphTargets=!0,j=new THREE.SkinnedMesh(i,j),j.skeleton=c.skeleton,j.skinController=qa[c.url],j.skinInstanceController=c,j.name="skin_"+sa.length,sa.push(j);
+else if(void 0!==d){h=i;k=d instanceof o?qa[d.url]:d;if(!k||!k.morph)console.log("could not find morph controller!");else{k=k.morph;for(l=0;l<k.targets.length;l++)if(m=ha[k.targets[l]],m.mesh&&m.mesh.primitives&&m.mesh.primitives.length)m=m.mesh.primitives[0].geometry,m.vertices.length===h.vertices.length&&h.morphTargets.push({name:"target_1",vertices:m.vertices});h.morphTargets.push({name:"target_Z",vertices:h.vertices})}j.morphTargets=!0;j=new THREE.Mesh(i,j);j.name="morph_"+La.length;La.push(j)}else j=
+new THREE.Mesh(i,j);1<a.geometries.length?b.add(j):b=j}}for(e=0;e<a.cameras.length;e++)b=lb[a.cameras[e].url],b=new THREE.PerspectiveCamera(b.fov,b.aspect_ratio,b.znear,b.zfar);b.name=a.id||"";b.matrix=a.matrix;e=a.matrix.decompose();b.position=e[0];b.quaternion=e[1];b.useQuaternion=!0;b.scale=e[2];Ea.centerGeometry&&b.geometry&&(e=THREE.GeometryUtils.center(b.geometry),b.quaternion.multiplyVector3(e.multiplySelf(b.scale)),b.position.subSelf(e));for(e=0;e<a.nodes.length;e++)b.add(g(a.nodes[e],a));
+return b}function e(){this.init_from=this.id=""}function h(){this.type=this.name=this.id="";this.morph=this.skin=null}function i(){this.weights=this.targets=this.source=this.method=null}function j(){this.source="";this.bindShapeMatrix=null;this.invBindMatrices=[];this.joints=[];this.weights=[]}function k(){this.name=this.id="";this.nodes=[];this.scene=new THREE.Object3D}function q(){this.sid=this.name=this.id="";this.nodes=[];this.controllers=[];this.transforms=[];this.geometries=[];this.channels=
+[];this.matrix=new THREE.Matrix4}function m(){this.type=this.sid="";this.data=[];this.obj=null}function o(){this.url="";this.skeleton=[];this.instance_material=[]}function p(){this.target=this.symbol=""}function n(){this.url="";this.instance_material=[]}function r(){this.id="";this.mesh=null}function s(a){this.geometry=a.id;this.primitives=[];this.geometry3js=this.vertices=null}function t(){}function w(){this.material="";this.count=0;this.inputs=[];this.vcount=null;this.p=[];this.geometry=new THREE.Geometry}
+function u(){this.source="";this.stride=this.count=0;this.params=[]}function v(){this.input={}}function A(){this.semantic="";this.offset=0;this.source="";this.set=0}function F(a){this.id=a;this.type=null}function B(){this.name=this.id="";this.instance_effect=null}function D(){this.color=new THREE.Color(0);this.color.setRGB(Math.random(),Math.random(),Math.random());this.color.a=1;this.texOpts=this.texcoord=this.texture=null}function H(a,b){this.type=a;this.effect=b;this.material=null}function I(a){this.effect=
+a;this.format=this.init_from=null}function Q(a){this.effect=a;this.mipfilter=this.magfilter=this.minfilter=this.wrap_t=this.wrap_s=this.source=null}function P(){this.name=this.id="";this.sampler=this.surface=this.shader=null}function L(){this.url=""}function K(){this.name=this.id="";this.source={};this.sampler=[];this.channel=[]}function O(a){this.animation=a;this.target=this.source="";this.member=this.arrIndices=this.arrSyntax=this.dotSyntax=this.sid=this.fullSid=null}function y(a){this.id="";this.animation=
+a;this.inputs=[];this.endTime=this.startTime=this.interpolation=this.strideOut=this.output=this.input=null;this.duration=0}function l(a){this.targets=[];this.time=a}function $(){this.name=this.id=""}function C(){this.url=""}function E(a){return"dae"==a?"http://www.collada.org/2005/11/COLLADASchema":null}function S(a){for(var a=ca(a),b=[],c=0,d=a.length;c<d;c++)b.push(parseFloat(a[c]));return b}function R(a){for(var a=ca(a),b=[],c=0,d=a.length;c<d;c++)b.push(parseInt(a[c],10));return b}function ca(a){return 0<
+a.length?a.replace(/^\s+/,"").replace(/\s+$/,"").split(/\s+/):[]}function ka(a,b,c){return a.hasAttribute(b)?parseInt(a.getAttribute(b),10):c}function ia(a,b){if(Ea.convertUpAxis&&Fa!==Ea.upAxis)switch(Wa){case "XtoY":var c=a[0];a[0]=b*a[1];a[1]=c;break;case "XtoZ":c=a[2];a[2]=a[1];a[1]=a[0];a[0]=c;break;case "YtoX":c=a[0];a[0]=a[1];a[1]=b*c;break;case "YtoZ":c=a[1];a[1]=b*a[2];a[2]=c;break;case "ZtoX":c=a[0];a[0]=a[1];a[1]=a[2];a[2]=c;break;case "ZtoY":c=a[1],a[1]=a[2],a[2]=b*c}}function N(a,b){var c=
+[a[b],a[b+1],a[b+2]];ia(c,-1);return new THREE.Vector3(c[0],c[1],c[2])}function aa(a){if(Ea.convertUpAxis){var b=[a[0],a[4],a[8]];ia(b,-1);a[0]=b[0];a[4]=b[1];a[8]=b[2];b=[a[1],a[5],a[9]];ia(b,-1);a[1]=b[0];a[5]=b[1];a[9]=b[2];b=[a[2],a[6],a[10]];ia(b,-1);a[2]=b[0];a[6]=b[1];a[10]=b[2];b=[a[0],a[1],a[2]];ia(b,-1);a[0]=b[0];a[1]=b[1];a[2]=b[2];b=[a[4],a[5],a[6]];ia(b,-1);a[4]=b[0];a[5]=b[1];a[6]=b[2];b=[a[8],a[9],a[10]];ia(b,-1);a[8]=b[0];a[9]=b[1];a[10]=b[2];b=[a[3],a[7],a[11]];ia(b,-1);a[3]=b[0];
+a[7]=b[1];a[11]=b[2]}return new THREE.Matrix4(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15])}var U=null,ba=null,ea,Ta=null,Ja={},Ka={},Ga={},qa={},ha={},ib={},db={},lb={},cb,Za,Sa,La,sa,za=THREE.SmoothShading,Ea={centerGeometry:!1,convertUpAxis:!1,subdivideFaces:!0,upAxis:"Y"},Fa="Y",Wa=null,mb=Math.PI/180;e.prototype.parse=function(a){this.id=a.getAttribute("id");for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if("init_from"==c.nodeName)this.init_from=
+c.textContent}return this};h.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");this.type="none";for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "skin":this.skin=(new j).parse(c);this.type=c.nodeName;break;case "morph":this.morph=(new i).parse(c),this.type=c.nodeName}}return this};i.prototype.parse=function(a){var b={},c=[],d;this.method=a.getAttribute("method");this.source=a.getAttribute("source").replace(/^#/,"");for(d=
+0;d<a.childNodes.length;d++){var e=a.childNodes[d];if(1==e.nodeType)switch(e.nodeName){case "source":e=(new F).parse(e);b[e.id]=e;break;case "targets":c=this.parseInputs(e);break;default:console.log(e.nodeName)}}for(d=0;d<c.length;d++)switch(a=c[d],e=b[a.source],a.semantic){case "MORPH_TARGET":this.targets=e.read();break;case "MORPH_WEIGHT":this.weights=e.read()}return this};i.prototype.parseInputs=function(a){for(var b=[],c=0;c<a.childNodes.length;c++){var d=a.childNodes[c];if(1==d.nodeType)switch(d.nodeName){case "input":b.push((new A).parse(d))}}return b};
+j.prototype.parse=function(a){var b={},c,d;this.source=a.getAttribute("source").replace(/^#/,"");this.invBindMatrices=[];this.joints=[];this.weights=[];for(var e=0;e<a.childNodes.length;e++){var f=a.childNodes[e];if(1==f.nodeType)switch(f.nodeName){case "bind_shape_matrix":f=S(f.textContent);this.bindShapeMatrix=aa(f);break;case "source":f=(new F).parse(f);b[f.id]=f;break;case "joints":c=f;break;case "vertex_weights":d=f;break;default:console.log(f.nodeName)}}this.parseJoints(c,b);this.parseWeights(d,
+b);return this};j.prototype.parseJoints=function(a,b){for(var c=0;c<a.childNodes.length;c++){var d=a.childNodes[c];if(1==d.nodeType)switch(d.nodeName){case "input":var d=(new A).parse(d),e=b[d.source];if("JOINT"==d.semantic)this.joints=e.read();else if("INV_BIND_MATRIX"==d.semantic)this.invBindMatrices=e.read()}}};j.prototype.parseWeights=function(a,b){for(var c,d,e=[],f=0;f<a.childNodes.length;f++){var g=a.childNodes[f];if(1==g.nodeType)switch(g.nodeName){case "input":e.push((new A).parse(g));break;
+case "v":c=R(g.textContent);break;case "vcount":d=R(g.textContent)}}for(f=g=0;f<d.length;f++){for(var h=d[f],i=[],j=0;j<h;j++){for(var k={},l=0;l<e.length;l++){var m=e[l],n=c[g+m.offset];switch(m.semantic){case "JOINT":k.joint=n;break;case "WEIGHT":k.weight=b[m.source].data[n]}}i.push(k);g+=e.length}for(j=0;j<i.length;j++)i[j].index=f;this.weights.push(i)}};k.prototype.getChildById=function(a,b){for(var c=0;c<this.nodes.length;c++){var d=this.nodes[c].getChildById(a,b);if(d)return d}return null};
+k.prototype.getChildBySid=function(a,b){for(var c=0;c<this.nodes.length;c++){var d=this.nodes[c].getChildBySid(a,b);if(d)return d}return null};k.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");this.nodes=[];for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "node":this.nodes.push((new q).parse(c))}}return this};q.prototype.getChannelForTransform=function(a){for(var b=0;b<this.channels.length;b++){var c=this.channels[b],
+d=c.target.split("/");d.shift();var e=d.shift(),f=0<=e.indexOf("."),g=0<=e.indexOf("("),h;if(f)d=e.split("."),e=d.shift(),d.shift();else if(g){h=e.split("(");e=h.shift();for(d=0;d<h.length;d++)h[d]=parseInt(h[d].replace(/\)/,""))}if(e==a)return c.info={sid:e,dotSyntax:f,arrSyntax:g,arrIndices:h},c}return null};q.prototype.getChildById=function(a,b){if(this.id==a)return this;if(b)for(var c=0;c<this.nodes.length;c++){var d=this.nodes[c].getChildById(a,b);if(d)return d}return null};q.prototype.getChildBySid=
+function(a,b){if(this.sid==a)return this;if(b)for(var c=0;c<this.nodes.length;c++){var d=this.nodes[c].getChildBySid(a,b);if(d)return d}return null};q.prototype.getTransformBySid=function(a){for(var b=0;b<this.transforms.length;b++)if(this.transforms[b].sid==a)return this.transforms[b];return null};q.prototype.parse=function(a){var b;this.id=a.getAttribute("id");this.sid=a.getAttribute("sid");this.name=a.getAttribute("name");this.type=a.getAttribute("type");this.type="JOINT"==this.type?this.type:
+"NODE";this.nodes=[];this.transforms=[];this.geometries=[];this.cameras=[];this.controllers=[];this.matrix=new THREE.Matrix4;for(var c=0;c<a.childNodes.length;c++)if(b=a.childNodes[c],1==b.nodeType)switch(b.nodeName){case "node":this.nodes.push((new q).parse(b));break;case "instance_camera":this.cameras.push((new C).parse(b));break;case "instance_controller":this.controllers.push((new o).parse(b));break;case "instance_geometry":this.geometries.push((new n).parse(b));break;case "instance_light":break;
+case "instance_node":b=b.getAttribute("url").replace(/^#/,"");(b=U.evaluate(".//dae:library_nodes//dae:node[@id='"+b+"']",U,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null).iterateNext())&&this.nodes.push((new q).parse(b));break;case "rotate":case "translate":case "scale":case "matrix":case "lookat":case "skew":this.transforms.push((new m).parse(b));break;case "extra":break;default:console.log(b.nodeName)}a=[];c=1E6;b=-1E6;for(var d in Ga)for(var e=Ga[d],f=0;f<e.channel.length;f++){var g=e.channel[f],
+h=e.sampler[f];d=g.target.split("/")[0];if(d==this.id)h.create(),g.sampler=h,c=Math.min(c,h.startTime),b=Math.max(b,h.endTime),a.push(g)}if(a.length)this.startTime=c,this.endTime=b;if((this.channels=a)&&this.channels.length){d=[];a=[];c=0;for(e=this.channels.length;c<e;c++){b=this.channels[c];f=b.fullSid;g=b.member;if(Ea.convertUpAxis)switch(g){case "X":switch(Wa){case "XtoY":case "XtoZ":case "YtoX":g="Y";break;case "ZtoX":g="Z"}break;case "Y":switch(Wa){case "XtoY":case "YtoX":case "ZtoX":g="X";
+break;case "XtoZ":case "YtoZ":case "ZtoY":g="Z"}break;case "Z":switch(Wa){case "XtoZ":g="X";break;case "YtoZ":case "ZtoX":case "ZtoY":g="Y"}}var h=b.sampler,i=h.input,j=this.getTransformBySid(b.sid);if(j){-1===a.indexOf(f)&&a.push(f);b=0;for(var k=i.length;b<k;b++){var p=i[b],r=h.getData(j.type,b),s;s=null;for(var t=0,u=d.length;t<u&&null==s;t++){var v=d[t];if(v.time===p)s=v;else if(v.time>p)break}if(!s){s=new l(p);t=-1;u=0;for(v=d.length;u<v&&-1==t;u++)d[u].time>=p&&(t=u);p=t;d.splice(-1==p?d.length:
+p,0,s)}s.addTarget(f,j,g,r)}}else console.log('Could not find transform "'+b.sid+'" in node '+this.id)}for(c=0;c<a.length;c++){e=a[c];for(b=0;b<d.length;b++)if(s=d[b],!s.hasTarget(e)){h=d;f=s;j=b;g=e;i=void 0;a:{i=j?j-1:0;for(i=0<=i?i:i+h.length;0<=i;i--)if(k=h[i],k.hasTarget(g)){i=k;break a}i=null}k=void 0;a:{for(j+=1;j<h.length;j++)if(k=h[j],k.hasTarget(g))break a;k=null}if(i&&k){h=(f.time-i.time)/(k.time-i.time);i=i.getTarget(g);j=k.getTarget(g).data;k=i.data;r=void 0;if(k.length){r=[];for(p=0;p<
+k.length;++p)r[p]=k[p]+(j[p]-k[p])*h}else r=k+(j-k)*h;f.addTarget(g,i.transform,i.member,r)}}}this.keys=d;this.sids=a}this.updateMatrix();return this};q.prototype.updateMatrix=function(){this.matrix.identity();for(var a=0;a<this.transforms.length;a++)this.transforms[a].apply(this.matrix)};m.prototype.parse=function(a){this.sid=a.getAttribute("sid");this.type=a.nodeName;this.data=S(a.textContent);this.convert();return this};m.prototype.convert=function(){switch(this.type){case "matrix":this.obj=aa(this.data);
+break;case "rotate":this.angle=this.data[3]*mb;case "translate":ia(this.data,-1);this.obj=new THREE.Vector3(this.data[0],this.data[1],this.data[2]);break;case "scale":ia(this.data,1);this.obj=new THREE.Vector3(this.data[0],this.data[1],this.data[2]);break;default:console.log("Can not convert Transform of type "+this.type)}};m.prototype.apply=function(a){switch(this.type){case "matrix":a.multiplySelf(this.obj);break;case "translate":a.translate(this.obj);break;case "rotate":a.rotateByAxis(this.obj,
+this.angle);break;case "scale":a.scale(this.obj)}};m.prototype.update=function(a,b){switch(this.type){case "matrix":console.log("Currently not handling matrix transform updates");break;case "translate":case "scale":switch(b){case "X":this.obj.x=a;break;case "Y":this.obj.y=a;break;case "Z":this.obj.z=a;break;default:this.obj.x=a[0],this.obj.y=a[1],this.obj.z=a[2]}break;case "rotate":switch(b){case "X":this.obj.x=a;break;case "Y":this.obj.y=a;break;case "Z":this.obj.z=a;break;case "ANGLE":this.angle=
+a*mb;break;default:this.obj.x=a[0],this.obj.y=a[1],this.obj.z=a[2],this.angle=a[3]*mb}}};o.prototype.parse=function(a){this.url=a.getAttribute("url").replace(/^#/,"");this.skeleton=[];this.instance_material=[];for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "skeleton":this.skeleton.push(c.textContent.replace(/^#/,""));break;case "bind_material":if(c=U.evaluate(".//dae:instance_material",c,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null))for(var d=
+c.iterateNext();d;)this.instance_material.push((new p).parse(d)),d=c.iterateNext()}}return this};p.prototype.parse=function(a){this.symbol=a.getAttribute("symbol");this.target=a.getAttribute("target").replace(/^#/,"");return this};n.prototype.parse=function(a){this.url=a.getAttribute("url").replace(/^#/,"");this.instance_material=[];for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType&&"bind_material"==c.nodeName){if(a=U.evaluate(".//dae:instance_material",c,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+null))for(b=a.iterateNext();b;)this.instance_material.push((new p).parse(b)),b=a.iterateNext();break}}return this};r.prototype.parse=function(a){this.id=a.getAttribute("id");for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "mesh":this.mesh=(new s(this)).parse(c)}}return this};s.prototype.parse=function(a){this.primitives=[];var b;for(b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "source":var d=c.getAttribute("id");void 0==Ja[d]&&(Ja[d]=
+(new F(d)).parse(c));break;case "vertices":this.vertices=(new v).parse(c);break;case "triangles":this.primitives.push((new w).parse(c));break;case "polygons":console.warn("polygon holes not yet supported!");case "polylist":this.primitives.push((new t).parse(c))}}this.geometry3js=new THREE.Geometry;a=Ja[this.vertices.input.POSITION.source].data;for(b=0;b<a.length;b+=3)this.geometry3js.vertices.push(new THREE.Vertex(N(a,b)));for(b=0;b<this.primitives.length;b++)a=this.primitives[b],a.setVertices(this.vertices),
+this.handlePrimitive(a,this.geometry3js);this.geometry3js.computeCentroids();this.geometry3js.computeFaceNormals();this.geometry3js.calcNormals&&(this.geometry3js.computeVertexNormals(),delete this.geometry3js.calcNormals);this.geometry3js.computeBoundingBox();return this};s.prototype.handlePrimitive=function(a,b){var c=0,d,e,f=a.p,g=a.inputs,h,i,j,k,l=0,m=3,n=0,o=[];for(d=0;d<g.length;d++){h=g[d];var q=h.offset+1,n=n<q?q:n;switch(h.semantic){case "TEXCOORD":o.push(h.set)}}for(;c<f.length;){var p=
+[],r=[],q={},s=[];a.vcount&&(m=a.vcount[l++]);for(d=0;d<m;d++)for(e=0;e<g.length;e++)switch(h=g[e],k=Ja[h.source],i=f[c+d*n+h.offset],j=k.accessor.params.length,j*=i,h.semantic){case "VERTEX":p.push(i);break;case "NORMAL":r.push(N(k.data,j));break;case "TEXCOORD":void 0===q[h.set]&&(q[h.set]=[]);q[h.set].push(new THREE.UV(k.data[j],1-k.data[j+1]));break;case "COLOR":s.push((new THREE.Color).setRGB(k.data[j],k.data[j+1],k.data[j+2]))}e=null;d=[];if(0==r.length)if(h=this.vertices.input.NORMAL){k=Ja[h.source];
+j=k.accessor.params.length;h=0;for(i=p.length;h<i;h++)r.push(N(k.data,p[h]*j))}else b.calcNormals=!0;if(3===m)d.push(new THREE.Face3(p[0],p[1],p[2],r,s.length?s:new THREE.Color));else if(4===m)d.push(new THREE.Face4(p[0],p[1],p[2],p[3],r,s.length?s:new THREE.Color));else if(4<m&&Ea.subdivideFaces){s=s.length?s:new THREE.Color;for(e=1;e<m-1;)d.push(new THREE.Face3(p[0],p[e],p[e+1],[r[0],r[e++],r[e]],s))}if(d.length){h=0;for(i=d.length;h<i;h++){e=d[h];e.daeMaterial=a.material;b.faces.push(e);for(e=
+0;e<o.length;e++)p=q[o[e]],p=4<m?[p[0],p[h+1],p[h+2]]:4===m?[p[0],p[1],p[2],p[3]]:[p[0],p[1],p[2]],b.faceVertexUvs[e]||(b.faceVertexUvs[e]=[]),b.faceVertexUvs[e].push(p)}}else console.log("dropped face with vcount "+m+" for geometry with id: "+b.id);c+=n*m}};t.prototype=new w;t.prototype.constructor=t;w.prototype.setVertices=function(a){for(var b=0;b<this.inputs.length;b++)if(this.inputs[b].source==a.id)this.inputs[b].source=a.input.POSITION.source};w.prototype.parse=function(a){this.inputs=[];this.material=
+a.getAttribute("material");this.count=ka(a,"count",0);for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "input":this.inputs.push((new A).parse(a.childNodes[b]));break;case "vcount":this.vcount=R(c.textContent);break;case "p":this.p=R(c.textContent)}}return this};u.prototype.parse=function(a){this.params=[];this.source=a.getAttribute("source");this.count=ka(a,"count",0);this.stride=ka(a,"stride",0);for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if("param"==
+c.nodeName){var d={};d.name=c.getAttribute("name");d.type=c.getAttribute("type");this.params.push(d)}}return this};v.prototype.parse=function(a){this.id=a.getAttribute("id");for(var b=0;b<a.childNodes.length;b++)if("input"==a.childNodes[b].nodeName){var c=(new A).parse(a.childNodes[b]);this.input[c.semantic]=c}return this};A.prototype.parse=function(a){this.semantic=a.getAttribute("semantic");this.source=a.getAttribute("source").replace(/^#/,"");this.set=ka(a,"set",-1);this.offset=ka(a,"offset",0);
+if("TEXCOORD"==this.semantic&&0>this.set)this.set=0;return this};F.prototype.parse=function(a){this.id=a.getAttribute("id");for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "bool_array":for(var d=ca(c.textContent),e=[],f=0,g=d.length;f<g;f++)e.push("true"==d[f]||"1"==d[f]?!0:!1);this.data=e;this.type=c.nodeName;break;case "float_array":this.data=S(c.textContent);this.type=c.nodeName;break;case "int_array":this.data=R(c.textContent);this.type=c.nodeName;break;case "IDREF_array":case "Name_array":this.data=
+ca(c.textContent);this.type=c.nodeName;break;case "technique_common":for(d=0;d<c.childNodes.length;d++)if("accessor"==c.childNodes[d].nodeName){this.accessor=(new u).parse(c.childNodes[d]);break}}}return this};F.prototype.read=function(){var a=[],b=this.accessor.params[0];switch(b.type){case "IDREF":case "Name":case "name":case "float":return this.data;case "float4x4":for(b=0;b<this.data.length;b+=16){var c=this.data.slice(b,b+16),c=aa(c);a.push(c)}break;default:console.log("ColladaLoader: Source: Read dont know how to read "+
+b.type+".")}return a};B.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");for(var b=0;b<a.childNodes.length;b++)if("instance_effect"==a.childNodes[b].nodeName){this.instance_effect=(new L).parse(a.childNodes[b]);break}return this};D.prototype.isColor=function(){return null==this.texture};D.prototype.isTexture=function(){return null!=this.texture};D.prototype.parse=function(a){for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "color":c=
+S(c.textContent);this.color=new THREE.Color(0);this.color.setRGB(c[0],c[1],c[2]);this.color.a=c[3];break;case "texture":this.texture=c.getAttribute("texture"),this.texcoord=c.getAttribute("texcoord"),this.texOpts={offsetU:0,offsetV:0,repeatU:1,repeatV:1,wrapU:1,wrapV:1},this.parseTexture(c)}}return this};D.prototype.parseTexture=function(a){if(!a.childNodes)return this;a.childNodes[1]&&"extra"===a.childNodes[1].nodeName&&(a=a.childNodes[1],a.childNodes[1]&&"technique"===a.childNodes[1].nodeName&&
+(a=a.childNodes[1]));for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];switch(c.nodeName){case "offsetU":case "offsetV":case "repeatU":case "repeatV":this.texOpts[c.nodeName]=parseFloat(c.textContent);break;case "wrapU":case "wrapV":this.texOpts[c.nodeName]=parseInt(c.textContent);break;default:this.texOpts[c.nodeName]=c.textContent}}return this};H.prototype.parse=function(a){for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "ambient":case "emission":case "diffuse":case "specular":case "transparent":this[c.nodeName]=
+(new D).parse(c);break;case "shininess":case "reflectivity":case "transparency":var d;d=U.evaluate(".//dae:float",c,E,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);for(var e=d.iterateNext(),f=[];e;)f.push(e),e=d.iterateNext();d=f;0<d.length&&(this[c.nodeName]=parseFloat(d[0].textContent))}}this.create();return this};H.prototype.create=function(){var a={},b=void 0!==this.transparency&&1>this.transparency,c;for(c in this)switch(c){case "ambient":case "emission":case "diffuse":case "specular":var d=this[c];
+if(d instanceof D)if(d.isTexture()){if(this.effect.sampler&&this.effect.surface&&this.effect.sampler.source==this.effect.surface.sid){var e=Ka[this.effect.surface.init_from];if(e)e=THREE.ImageUtils.loadTexture(Sa+e.init_from),e.wrapS=d.texOpts.wrapU?THREE.RepeatWrapping:THREE.ClampToEdgeWrapping,e.wrapT=d.texOpts.wrapV?THREE.RepeatWrapping:THREE.ClampToEdgeWrapping,e.offset.x=d.texOpts.offsetU,e.offset.y=d.texOpts.offsetV,e.repeat.x=d.texOpts.repeatU,e.repeat.y=d.texOpts.repeatV,a.map=e}}else"diffuse"==
+c?a.color=d.color.getHex():b||(a[c]=d.color.getHex());break;case "shininess":case "reflectivity":a[c]=this[c];break;case "transparency":if(b)a.transparent=!0,a.opacity=this[c],b=!0}a.shading=za;return this.material=new THREE.MeshLambertMaterial(a)};I.prototype.parse=function(a){for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "init_from":this.init_from=c.textContent;break;case "format":this.format=c.textContent;break;default:console.log("unhandled Surface prop: "+
+c.nodeName)}}return this};Q.prototype.parse=function(a){for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "source":this.source=c.textContent;break;case "minfilter":this.minfilter=c.textContent;break;case "magfilter":this.magfilter=c.textContent;break;case "mipfilter":this.mipfilter=c.textContent;break;case "wrap_s":this.wrap_s=c.textContent;break;case "wrap_t":this.wrap_t=c.textContent;break;default:console.log("unhandled Sampler2D prop: "+c.nodeName)}}return this};
+P.prototype.create=function(){if(null==this.shader)return null};P.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");this.shader=null;for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "profile_COMMON":this.parseTechnique(this.parseProfileCOMMON(c))}}return this};P.prototype.parseNewparam=function(a){for(var b=a.getAttribute("sid"),c=0;c<a.childNodes.length;c++){var d=a.childNodes[c];if(1==d.nodeType)switch(d.nodeName){case "surface":this.surface=
+(new I(this)).parse(d);this.surface.sid=b;break;case "sampler2D":this.sampler=(new Q(this)).parse(d);this.sampler.sid=b;break;case "extra":break;default:console.log(d.nodeName)}}};P.prototype.parseProfileCOMMON=function(a){for(var b,c=0;c<a.childNodes.length;c++){var d=a.childNodes[c];if(1==d.nodeType)switch(d.nodeName){case "profile_COMMON":this.parseProfileCOMMON(d);break;case "technique":b=d;break;case "newparam":this.parseNewparam(d);break;case "extra":break;default:console.log(d.nodeName)}}return b};
+P.prototype.parseTechnique=function(a){for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "constant":case "lambert":case "blinn":case "phong":this.shader=(new H(c.nodeName,this)).parse(c)}}};L.prototype.parse=function(a){this.url=a.getAttribute("url").replace(/^#/,"");return this};K.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");this.source={};for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];
+if(1==c.nodeType)switch(c.nodeName){case "source":c=(new F).parse(c);this.source[c.id]=c;break;case "sampler":this.sampler.push((new y(this)).parse(c));break;case "channel":this.channel.push((new O(this)).parse(c))}}return this};O.prototype.parse=function(a){this.source=a.getAttribute("source").replace(/^#/,"");this.target=a.getAttribute("target");var b=this.target.split("/");b.shift();var a=b.shift(),c=0<=a.indexOf("."),d=0<=a.indexOf("(");if(c)b=a.split("."),this.sid=b.shift(),this.member=b.shift();
+else if(d){b=a.split("(");this.sid=b.shift();for(var e=0;e<b.length;e++)b[e]=parseInt(b[e].replace(/\)/,""));this.arrIndices=b}else this.sid=a;this.fullSid=a;this.dotSyntax=c;this.arrSyntax=d;return this};y.prototype.parse=function(a){this.id=a.getAttribute("id");this.inputs=[];for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "input":this.inputs.push((new A).parse(c))}}return this};y.prototype.create=function(){for(var a=0;a<this.inputs.length;a++){var b=
+this.inputs[a],c=this.animation.source[b.source];switch(b.semantic){case "INPUT":this.input=c.read();break;case "OUTPUT":this.output=c.read();this.strideOut=c.accessor.stride;break;case "INTERPOLATION":this.interpolation=c.read();break;case "IN_TANGENT":break;case "OUT_TANGENT":break;default:console.log(b.semantic)}}this.duration=this.endTime=this.startTime=0;if(this.input.length){this.startTime=1E8;this.endTime=-1E8;for(a=0;a<this.input.length;a++)this.startTime=Math.min(this.startTime,this.input[a]),
+this.endTime=Math.max(this.endTime,this.input[a]);this.duration=this.endTime-this.startTime}};y.prototype.getData=function(a,b){var c;if(1<this.strideOut){c=[];for(var b=b*this.strideOut,d=0;d<this.strideOut;++d)c[d]=this.output[b+d];if(3===this.strideOut)switch(a){case "rotate":case "translate":ia(c,-1);break;case "scale":ia(c,1)}}else c=this.output[b];return c};l.prototype.addTarget=function(a,b,c,d){this.targets.push({sid:a,member:c,transform:b,data:d})};l.prototype.apply=function(a){for(var b=
+0;b<this.targets.length;++b){var c=this.targets[b];(!a||c.sid===a)&&c.transform.update(c.data,c.member)}};l.prototype.getTarget=function(a){for(var b=0;b<this.targets.length;++b)if(this.targets[b].sid===a)return this.targets[b];return null};l.prototype.hasTarget=function(a){for(var b=0;b<this.targets.length;++b)if(this.targets[b].sid===a)return!0;return!1};l.prototype.interpolate=function(a,b){for(var c=0;c<this.targets.length;++c){var d=this.targets[c],e=a.getTarget(d.sid);if(e){var f=(b-this.time)/
+(a.time-this.time),g=e.data,h=d.data;if(0>f||1<f)console.log("Key.interpolate: Warning! Scale out of bounds:"+f),f=0>f?0:1;if(h.length)for(var e=[],i=0;i<h.length;++i)e[i]=h[i]+(g[i]-h[i])*f;else e=h+(g-h)*f}else e=d.data;d.transform.update(e,d.member)}};$.prototype.parse=function(a){this.id=a.getAttribute("id");this.name=a.getAttribute("name");for(var b=0;b<a.childNodes.length;b++){var c=a.childNodes[b];if(1==c.nodeType)switch(c.nodeName){case "optics":this.parseOptics(c)}}return this};$.prototype.parseOptics=
+function(a){for(var b=0;b<a.childNodes.length;b++)if("technique_common"==a.childNodes[b].nodeName)for(var c=a.childNodes[b],d=0;d<c.childNodes.length;d++)if("perspective"==c.childNodes[d].nodeName)for(var e=c.childNodes[d],f=0;f<e.childNodes.length;f++){var g=e.childNodes[f];switch(g.nodeName){case "xfov":this.fov=g.textContent;break;case "znear":this.znear=0.4;break;case "zfar":this.zfar=1E15;break;case "aspect_ratio":this.aspect_ratio=g.textContent}}return this};C.prototype.parse=function(a){this.url=
+a.getAttribute("url").replace(/^#/,"");return this};return{load:function(b,c,d){var e=0;if(document.implementation&&document.implementation.createDocument){var f=new XMLHttpRequest;f.overrideMimeType&&f.overrideMimeType("text/xml");f.onreadystatechange=function(){if(4==f.readyState){if(0==f.status||200==f.status)f.responseXML?(Ta=c,a(f.responseXML,void 0,b)):console.error("ColladaLoader: Empty or non-existing file ("+b+")")}else 3==f.readyState&&d&&(0==e&&(e=f.getResponseHeader("Content-Length")),
+d({total:e,loaded:f.responseText.length}))};f.open("GET",b,!0);f.send(null)}else alert("Don't know how to parse XML!")},parse:a,setPreferredShading:function(a){za=a},applySkin:f,geometries:ha,options:Ea}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a)};THREE.JSONLoader.prototype=new THREE.Loader;THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;THREE.JSONLoader.prototype.supr=THREE.Loader.prototype;
+THREE.JSONLoader.prototype.load=function(a,b,c){c=c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)};
+THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,f){var g=new XMLHttpRequest,e=0;g.onreadystatechange=function(){if(g.readyState===g.DONE)if(200===g.status||0===g.status){if(g.responseText){var h=JSON.parse(g.responseText);a.createModel(h,c,d)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+g.status+"]");else g.readyState===g.LOADING?f&&(0===e&&(e=g.getResponseHeader("Content-Length")),
+f({total:e,loaded:g.responseText.length})):g.readyState===g.HEADERS_RECEIVED&&(e=g.getResponseHeader("Content-Length"))};g.open("GET",b,!0);g.overrideMimeType&&g.overrideMimeType("text/plain; charset=x-user-defined");g.setRequestHeader("Content-Type","text/plain");g.send(null)};
+THREE.JSONLoader.prototype.createModel=function(a,b,c){var d=new THREE.Geometry,f=void 0!==a.scale?1/a.scale:1;this.initMaterials(d,a.materials,c);(function(b){var c,f,i,j,k,q,m,o,p,n,r,s,t,w,u=a.faces;q=a.vertices;var v=a.normals,A=a.colors,F=0;for(c=0;c<a.uvs.length;c++)a.uvs[c].length&&F++;for(c=0;c<F;c++)d.faceUvs[c]=[],d.faceVertexUvs[c]=[];j=0;for(k=q.length;j<k;)m=new THREE.Vertex,m.position.x=q[j++]*b,m.position.y=q[j++]*b,m.position.z=q[j++]*b,d.vertices.push(m);j=0;for(k=u.length;j<k;){b=
+u[j++];q=b&1;i=b&2;c=b&4;f=b&8;o=b&16;m=b&32;n=b&64;b&=128;q?(r=new THREE.Face4,r.a=u[j++],r.b=u[j++],r.c=u[j++],r.d=u[j++],q=4):(r=new THREE.Face3,r.a=u[j++],r.b=u[j++],r.c=u[j++],q=3);if(i)i=u[j++],r.materialIndex=i;i=d.faces.length;if(c)for(c=0;c<F;c++)s=a.uvs[c],p=u[j++],w=s[2*p],p=s[2*p+1],d.faceUvs[c][i]=new THREE.UV(w,p);if(f)for(c=0;c<F;c++){s=a.uvs[c];t=[];for(f=0;f<q;f++)p=u[j++],w=s[2*p],p=s[2*p+1],t[f]=new THREE.UV(w,p);d.faceVertexUvs[c][i]=t}if(o)o=3*u[j++],f=new THREE.Vector3,f.x=v[o++],
+f.y=v[o++],f.z=v[o],r.normal=f;if(m)for(c=0;c<q;c++)o=3*u[j++],f=new THREE.Vector3,f.x=v[o++],f.y=v[o++],f.z=v[o],r.vertexNormals.push(f);if(n)m=u[j++],m=new THREE.Color(A[m]),r.color=m;if(b)for(c=0;c<q;c++)m=u[j++],m=new THREE.Color(A[m]),r.vertexColors.push(m);d.faces.push(r)}})(f);(function(){var b,c,f,i;if(a.skinWeights)for(b=0,c=a.skinWeights.length;b<c;b+=2)f=a.skinWeights[b],i=a.skinWeights[b+1],d.skinWeights.push(new THREE.Vector4(f,i,0,0));if(a.skinIndices)for(b=0,c=a.skinIndices.length;b<
+c;b+=2)f=a.skinIndices[b],i=a.skinIndices[b+1],d.skinIndices.push(new THREE.Vector4(f,i,0,0));d.bones=a.bones;d.animation=a.animation})();(function(b){if(void 0!==a.morphTargets){var c,f,i,j,k,q,m,o,p;for(c=0,f=a.morphTargets.length;c<f;c++){d.morphTargets[c]={};d.morphTargets[c].name=a.morphTargets[c].name;d.morphTargets[c].vertices=[];o=d.morphTargets[c].vertices;p=a.morphTargets[c].vertices;for(i=0,j=p.length;i<j;i+=3)k=p[i]*b,q=p[i+1]*b,m=p[i+2]*b,o.push(new THREE.Vertex(new THREE.Vector3(k,q,
+m)))}}if(void 0!==a.morphColors)for(c=0,f=a.morphColors.length;c<f;c++){d.morphColors[c]={};d.morphColors[c].name=a.morphColors[c].name;d.morphColors[c].colors=[];j=d.morphColors[c].colors;k=a.morphColors[c].colors;for(b=0,i=k.length;b<i;b+=3)q=new THREE.Color(16755200),q.setRGB(k[b],k[b+1],k[b+2]),j.push(q)}})(f);d.computeCentroids();d.computeFaceNormals();this.hasNormals(d)&&d.computeTangents();b(d)};
+THREE.SceneLoader=function(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){};this.callbackSync=function(){};this.callbackProgress=function(){}};THREE.SceneLoader.prototype.constructor=THREE.SceneLoader;
+THREE.SceneLoader.prototype.load=function(a,b){var c=this,d=new XMLHttpRequest;d.onreadystatechange=function(){if(4==d.readyState)if(200==d.status||0==d.status){var f=JSON.parse(d.responseText);c.createScene(f,b,a)}else console.error("THREE.SceneLoader: Couldn't load ["+a+"] ["+d.status+"]")};d.open("GET",a,!0);d.overrideMimeType&&d.overrideMimeType("text/plain; charset=x-user-defined");d.setRequestHeader("Content-Type","text/plain");d.send(null)};
+THREE.SceneLoader.prototype.createScene=function(a,b,c){function d(a,b){return"relativeToHTML"==b?a:j+"/"+a}function f(){var a;for(m in L.objects)if(!C.objects[m])if(s=L.objects[m],void 0!==s.geometry){if(H=C.geometries[s.geometry]){a=!1;I=C.materials[s.materials[0]];(a=I instanceof THREE.ShaderMaterial)&&H.computeTangents();u=s.position;v=s.rotation;A=s.quaternion;F=s.scale;A=0;0==s.materials.length&&(I=new THREE.MeshFaceMaterial);1<s.materials.length&&(I=new THREE.MeshFaceMaterial);a=new THREE.Mesh(H,
+I);a.name=m;a.position.set(u[0],u[1],u[2]);A?(a.quaternion.set(A[0],A[1],A[2],A[3]),a.useQuaternion=!0):a.rotation.set(v[0],v[1],v[2]);a.scale.set(F[0],F[1],F[2]);a.visible=s.visible;C.scene.add(a);C.objects[m]=a;if(s.castsShadow){var b=new THREE.ShadowVolume(H);C.scene.add(b);b.position=a.position;b.rotation=a.rotation;b.scale=a.scale}s.trigger&&"none"!=s.trigger.toLowerCase()&&(b={type:s.trigger,object:s},C.triggers[a.name]=b)}}else u=s.position,v=s.rotation,A=s.quaternion,F=s.scale,A=0,a=new THREE.Object3D,
+a.name=m,a.position.set(u[0],u[1],u[2]),A?(a.quaternion.set(A[0],A[1],A[2],A[3]),a.useQuaternion=!0):a.rotation.set(v[0],v[1],v[2]),a.scale.set(F[0],F[1],F[2]),a.visible=void 0!==s.visible?s.visible:!1,C.scene.add(a),C.objects[m]=a,C.empties[m]=a,s.trigger&&"none"!=s.trigger.toLowerCase()&&(b={type:s.trigger,object:s},C.triggers[a.name]=b)}function g(a){return function(b){C.geometries[a]=b;f();O-=1;i.onLoadComplete();h()}}function e(a){return function(b){C.geometries[a]=b}}function h(){i.callbackProgress({totalModels:l,
+totalTextures:$,loadedModels:l-O,loadedTextures:$-y},C);i.onLoadProgress();0==O&&0==y&&b(C)}var i=this,j=THREE.Loader.prototype.extractUrlBase(c),k,q,m,o,p,n,r,s,t,w,u,v,A,F,B,D,H,I,Q,P,L,K,O,y,l,$,C;L=a;c=new THREE.BinaryLoader;K=new THREE.JSONLoader;y=O=0;C={scene:new THREE.Scene,geometries:{},materials:{},textures:{},objects:{},cameras:{},lights:{},fogs:{},triggers:{},empties:{}};if(L.transform)a=L.transform.position,t=L.transform.rotation,B=L.transform.scale,a&&C.scene.position.set(a[0],a[1],
+a[2]),t&&C.scene.rotation.set(t[0],t[1],t[2]),B&&C.scene.scale.set(B[0],B[1],B[2]),(a||t||B)&&C.scene.updateMatrix();a=function(){y-=1;h();i.onLoadComplete()};for(p in L.cameras)B=L.cameras[p],"perspective"==B.type?Q=new THREE.PerspectiveCamera(B.fov,B.aspect,B.near,B.far):"ortho"==B.type&&(Q=new THREE.OrthographicCamera(B.left,B.right,B.top,B.bottom,B.near,B.far)),u=B.position,t=B.target,B=B.up,Q.position.set(u[0],u[1],u[2]),Q.target=new THREE.Vector3(t[0],t[1],t[2]),B&&Q.up.set(B[0],B[1],B[2]),
+C.cameras[p]=Q;for(o in L.lights)t=L.lights[o],p=void 0!==t.color?t.color:16777215,Q=void 0!==t.intensity?t.intensity:1,"directional"==t.type?(u=t.direction,w=new THREE.DirectionalLight(p,Q),w.position.set(u[0],u[1],u[2]),w.position.normalize()):"point"==t.type?(u=t.position,w=t.distance,w=new THREE.PointLight(p,Q,w),w.position.set(u[0],u[1],u[2])):"ambient"==t.type&&(w=new THREE.AmbientLight(p)),C.scene.add(w),C.lights[o]=w;for(n in L.fogs)o=L.fogs[n],"linear"==o.type?P=new THREE.Fog(0,o.near,o.far):
+"exp2"==o.type&&(P=new THREE.FogExp2(0,o.density)),B=o.color,P.color.setRGB(B[0],B[1],B[2]),C.fogs[n]=P;if(C.cameras&&L.defaults.camera)C.currentCamera=C.cameras[L.defaults.camera];if(C.fogs&&L.defaults.fog)C.scene.fog=C.fogs[L.defaults.fog];B=L.defaults.bgcolor;C.bgColor=new THREE.Color;C.bgColor.setRGB(B[0],B[1],B[2]);C.bgColorAlpha=L.defaults.bgalpha;for(k in L.geometries)if(n=L.geometries[k],"bin_mesh"==n.type||"ascii_mesh"==n.type)O+=1,i.onLoadStart();l=O;for(k in L.geometries)if(n=L.geometries[k],
+"cube"==n.type)H=new THREE.CubeGeometry(n.width,n.height,n.depth,n.segmentsWidth,n.segmentsHeight,n.segmentsDepth,null,n.flipped,n.sides),C.geometries[k]=H;else if("plane"==n.type)H=new THREE.PlaneGeometry(n.width,n.height,n.segmentsWidth,n.segmentsHeight),C.geometries[k]=H;else if("sphere"==n.type)H=new THREE.SphereGeometry(n.radius,n.segmentsWidth,n.segmentsHeight),C.geometries[k]=H;else if("cylinder"==n.type)H=new THREE.CylinderGeometry(n.topRad,n.botRad,n.height,n.radSegs,n.heightSegs),C.geometries[k]=
+H;else if("torus"==n.type)H=new THREE.TorusGeometry(n.radius,n.tube,n.segmentsR,n.segmentsT),C.geometries[k]=H;else if("icosahedron"==n.type)H=new THREE.IcosahedronGeometry(n.radius,n.subdivisions),C.geometries[k]=H;else if("bin_mesh"==n.type)c.load(d(n.url,L.urlBaseType),g(k));else if("ascii_mesh"==n.type)K.load(d(n.url,L.urlBaseType),g(k));else if("embedded_mesh"==n.type)n=L.embeds[n.id],n.metadata=L.metadata,n&&K.createModel(n,e(k),"");for(r in L.textures)if(k=L.textures[r],k.url instanceof Array){y+=
+k.url.length;for(n=0;n<k.url.length;n++)i.onLoadStart()}else y+=1,i.onLoadStart();$=y;for(r in L.textures){k=L.textures[r];if(void 0!=k.mapping&&void 0!=THREE[k.mapping])k.mapping=new THREE[k.mapping];if(k.url instanceof Array){n=[];for(P=0;P<k.url.length;P++)n[P]=d(k.url[P],L.urlBaseType);n=THREE.ImageUtils.loadTextureCube(n,k.mapping,a)}else{n=THREE.ImageUtils.loadTexture(d(k.url,L.urlBaseType),k.mapping,a);if(void 0!=THREE[k.minFilter])n.minFilter=THREE[k.minFilter];if(void 0!=THREE[k.magFilter])n.magFilter=
+THREE[k.magFilter];if(k.repeat){n.repeat.set(k.repeat[0],k.repeat[1]);if(1!=k.repeat[0])n.wrapS=THREE.RepeatWrapping;if(1!=k.repeat[1])n.wrapT=THREE.RepeatWrapping}k.offset&&n.offset.set(k.offset[0],k.offset[1]);if(k.wrap){P={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping};if(void 0!==P[k.wrap[0]])n.wrapS=P[k.wrap[0]];if(void 0!==P[k.wrap[1]])n.wrapT=P[k.wrap[1]]}}C.textures[r]=n}for(q in L.materials){r=L.materials[q];for(D in r.parameters)if("envMap"==D||"map"==D||"lightMap"==D)r.parameters[D]=
+C.textures[r.parameters[D]];else if("shading"==D)r.parameters[D]="flat"==r.parameters[D]?THREE.FlatShading:THREE.SmoothShading;else if("blending"==D)r.parameters[D]=THREE[r.parameters[D]]?THREE[r.parameters[D]]:THREE.NormalBlending;else if("combine"==D)r.parameters[D]="MixOperation"==r.parameters[D]?THREE.MixOperation:THREE.MultiplyOperation;else if("vertexColors"==D)if("face"==r.parameters[D])r.parameters[D]=THREE.FaceColors;else if(r.parameters[D])r.parameters[D]=THREE.VertexColors;if(void 0!==
+r.parameters.opacity&&1>r.parameters.opacity)r.parameters.transparent=!0;if(r.parameters.normalMap){a=THREE.ShaderUtils.lib.normal;k=THREE.UniformsUtils.clone(a.uniforms);n=r.parameters.color;P=r.parameters.specular;c=r.parameters.ambient;K=r.parameters.shininess;k.tNormal.texture=C.textures[r.parameters.normalMap];if(r.parameters.normalMapFactor)k.uNormalScale.value=r.parameters.normalMapFactor;if(r.parameters.map)k.tDiffuse.texture=r.parameters.map,k.enableDiffuse.value=!0;if(r.parameters.lightMap)k.tAO.texture=
+r.parameters.lightMap,k.enableAO.value=!0;if(r.parameters.specularMap)k.tSpecular.texture=C.textures[r.parameters.specularMap],k.enableSpecular.value=!0;k.uDiffuseColor.value.setHex(n);k.uSpecularColor.value.setHex(P);k.uAmbientColor.value.setHex(c);k.uShininess.value=K;if(r.parameters.opacity)k.uOpacity.value=r.parameters.opacity;I=new THREE.ShaderMaterial({fragmentShader:a.fragmentShader,vertexShader:a.vertexShader,uniforms:k,lights:!0,fog:!0})}else I=new THREE[r.type](r.parameters);C.materials[q]=
+I}f();i.callbackSync(C);h()};THREE.UTF8Loader=function(){};
+THREE.UTF8Loader.prototype.load=function(a,b,c){var d=new XMLHttpRequest,f=void 0!==c.scale?c.scale:1,g=void 0!==c.offsetX?c.offsetX:0,e=void 0!==c.offsetY?c.offsetY:0,h=void 0!==c.offsetZ?c.offsetZ:0;d.onreadystatechange=function(){4==d.readyState?200==d.status||0==d.status?THREE.UTF8Loader.prototype.createModel(d.responseText,b,f,g,e,h):console.error("THREE.UTF8Loader: Couldn't load ["+a+"] ["+d.status+"]"):3!=d.readyState&&2==d.readyState&&d.getResponseHeader("Content-Length")};d.open("GET",a,
+!0);d.send(null)};THREE.UTF8Loader.prototype.decompressMesh=function(a){var b=a.charCodeAt(0);57344<=b&&(b-=2048);b++;for(var c=new Float32Array(8*b),d=1,f=0;8>f;f++){for(var g=0,e=0;e<b;++e){var h=a.charCodeAt(e+d),g=g+(h>>1^-(h&1));c[8*e+f]=g}d+=b}b=a.length-d;g=new Uint16Array(b);for(f=e=0;f<b;f++)h=a.charCodeAt(f+d),g[f]=e-h,0==h&&e++;return[c,g]};
+THREE.UTF8Loader.prototype.createModel=function(a,b,c,d,f,g){var e=function(){var b=this;b.materials=[];THREE.Geometry.call(this);var e=THREE.UTF8Loader.prototype.decompressMesh(a),j=[],k=[];(function(a,e,i){for(var j,k,r,s=a.length;i<s;i+=e)j=a[i],k=a[i+1],r=a[i+2],j=j/16383*c,k=k/16383*c,r=r/16383*c,j+=d,k+=f,r+=g,b.vertices.push(new THREE.Vertex(new THREE.Vector3(j,k,r)))})(e[0],8,0);(function(a,b,c){for(var d,e,f=a.length;c<f;c+=b)d=a[c],e=a[c+1],d/=1023,e/=1023,k.push(d,1-e)})(e[0],8,3);(function(a,
+b,c){for(var d,e,f,g=a.length;c<g;c+=b)d=a[c],e=a[c+1],f=a[c+2],d=(d-512)/511,e=(e-512)/511,f=(f-512)/511,j.push(d,e,f)})(e[0],8,5);(function(a){var c,d,e,f,g,i,t,w,u,v=a.length;for(c=0;c<v;c+=3){d=a[c];e=a[c+1];f=a[c+2];g=b;w=d;u=e;i=f;var A=j[3*e],F=j[3*e+1],B=j[3*e+2],D=j[3*f],H=j[3*f+1],I=j[3*f+2];t=new THREE.Vector3(j[3*d],j[3*d+1],j[3*d+2]);A=new THREE.Vector3(A,F,B);D=new THREE.Vector3(D,H,I);g.faces.push(new THREE.Face3(w,u,i,[t,A,D],null,0));g=k[2*d];d=k[2*d+1];i=k[2*e];t=k[2*e+1];w=k[2*
+f];u=k[2*f+1];f=b.faceVertexUvs[0];e=i;i=t;t=[];t.push(new THREE.UV(g,d));t.push(new THREE.UV(e,i));t.push(new THREE.UV(w,u));f.push(t)}})(e[1]);this.computeCentroids();this.computeFaceNormals()};e.prototype=new THREE.Geometry;e.prototype.constructor=e;b(new e)};
+THREE.MarchingCubes=function(a,b){THREE.Object3D.call(this);this.material=b;this.init=function(a){this.resolution=a;this.isolation=80;this.size=a;this.size2=this.size*this.size;this.size3=this.size2*this.size;this.halfsize=this.size/2;this.delta=2/this.size;this.yd=this.size;this.zd=this.size2;this.field=new Float32Array(this.size3);this.normal_cache=new Float32Array(3*this.size3);this.vlist=new Float32Array(36);this.nlist=new Float32Array(36);this.firstDraw=!0;this.maxCount=4096;this.count=0;this.hasNormal=
+this.hasPos=!1;this.positionArray=new Float32Array(3*this.maxCount);this.normalArray=new Float32Array(3*this.maxCount)};this.lerp=function(a,b,f){return a+(b-a)*f};this.VIntX=function(a,b,f,g,e,h,i,j,k,q){e=(e-k)/(q-k);k=this.normal_cache;b[g]=h+e*this.delta;b[g+1]=i;b[g+2]=j;f[g]=this.lerp(k[a],k[a+3],e);f[g+1]=this.lerp(k[a+1],k[a+4],e);f[g+2]=this.lerp(k[a+2],k[a+5],e)};this.VIntY=function(a,b,f,g,e,h,i,j,k,q){e=(e-k)/(q-k);k=this.normal_cache;b[g]=h;b[g+1]=i+e*this.delta;b[g+2]=j;b=a+3*this.yd;
+f[g]=this.lerp(k[a],k[b],e);f[g+1]=this.lerp(k[a+1],k[b+1],e);f[g+2]=this.lerp(k[a+2],k[b+2],e)};this.VIntZ=function(a,b,f,g,e,h,i,j,k,q){e=(e-k)/(q-k);k=this.normal_cache;b[g]=h;b[g+1]=i;b[g+2]=j+e*this.delta;b=a+3*this.zd;f[g]=this.lerp(k[a],k[b],e);f[g+1]=this.lerp(k[a+1],k[b+1],e);f[g+2]=this.lerp(k[a+2],k[b+2],e)};this.compNorm=function(a){var b=3*a;0===this.normal_cache[b]&&(this.normal_cache[b]=this.field[a-1]-this.field[a+1],this.normal_cache[b+1]=this.field[a-this.yd]-this.field[a+this.yd],
+this.normal_cache[b+2]=this.field[a-this.zd]-this.field[a+this.zd])};this.polygonize=function(a,b,f,g,e,h){var i=g+1,j=g+this.yd,k=g+this.zd,q=i+this.yd,m=i+this.zd,o=g+this.yd+this.zd,p=i+this.yd+this.zd,n=0,r=this.field[g],s=this.field[i],t=this.field[j],w=this.field[q],u=this.field[k],v=this.field[m],A=this.field[o],F=this.field[p];r<e&&(n|=1);s<e&&(n|=2);t<e&&(n|=8);w<e&&(n|=4);u<e&&(n|=16);v<e&&(n|=32);A<e&&(n|=128);F<e&&(n|=64);var B=THREE.edgeTable[n];if(0===B)return 0;var D=this.delta,H=a+
+D,I=b+D,D=f+D;B&1&&(this.compNorm(g),this.compNorm(i),this.VIntX(3*g,this.vlist,this.nlist,0,e,a,b,f,r,s));B&2&&(this.compNorm(i),this.compNorm(q),this.VIntY(3*i,this.vlist,this.nlist,3,e,H,b,f,s,w));B&4&&(this.compNorm(j),this.compNorm(q),this.VIntX(3*j,this.vlist,this.nlist,6,e,a,I,f,t,w));B&8&&(this.compNorm(g),this.compNorm(j),this.VIntY(3*g,this.vlist,this.nlist,9,e,a,b,f,r,t));B&16&&(this.compNorm(k),this.compNorm(m),this.VIntX(3*k,this.vlist,this.nlist,12,e,a,b,D,u,v));B&32&&(this.compNorm(m),
+this.compNorm(p),this.VIntY(3*m,this.vlist,this.nlist,15,e,H,b,D,v,F));B&64&&(this.compNorm(o),this.compNorm(p),this.VIntX(3*o,this.vlist,this.nlist,18,e,a,I,D,A,F));B&128&&(this.compNorm(k),this.compNorm(o),this.VIntY(3*k,this.vlist,this.nlist,21,e,a,b,D,u,A));B&256&&(this.compNorm(g),this.compNorm(k),this.VIntZ(3*g,this.vlist,this.nlist,24,e,a,b,f,r,u));B&512&&(this.compNorm(i),this.compNorm(m),this.VIntZ(3*i,this.vlist,this.nlist,27,e,H,b,f,s,v));B&1024&&(this.compNorm(q),this.compNorm(p),this.VIntZ(3*
+q,this.vlist,this.nlist,30,e,H,I,f,w,F));B&2048&&(this.compNorm(j),this.compNorm(o),this.VIntZ(3*j,this.vlist,this.nlist,33,e,a,I,f,t,A));n<<=4;for(e=g=0;-1!=THREE.triTable[n+e];)a=n+e,b=a+1,f=a+2,this.posnormtriv(this.vlist,this.nlist,3*THREE.triTable[a],3*THREE.triTable[b],3*THREE.triTable[f],h),e+=3,g++;return g};this.posnormtriv=function(a,b,f,g,e,h){var i=3*this.count;this.positionArray[i]=a[f];this.positionArray[i+1]=a[f+1];this.positionArray[i+2]=a[f+2];this.positionArray[i+3]=a[g];this.positionArray[i+
+4]=a[g+1];this.positionArray[i+5]=a[g+2];this.positionArray[i+6]=a[e];this.positionArray[i+7]=a[e+1];this.positionArray[i+8]=a[e+2];this.normalArray[i]=b[f];this.normalArray[i+1]=b[f+1];this.normalArray[i+2]=b[f+2];this.normalArray[i+3]=b[g];this.normalArray[i+4]=b[g+1];this.normalArray[i+5]=b[g+2];this.normalArray[i+6]=b[e];this.normalArray[i+7]=b[e+1];this.normalArray[i+8]=b[e+2];this.hasNormal=this.hasPos=!0;this.count+=3;this.count>=this.maxCount-3&&h(this)};this.begin=function(){this.count=0;
+this.hasNormal=this.hasPos=!1};this.end=function(a){if(0!==this.count){for(var b=3*this.count;b<this.positionArray.length;b++)this.positionArray[b]=0;a(this)}};this.addBall=function(a,b,f,g,e){var h=this.size*Math.sqrt(g/e),i=f*this.size,j=b*this.size,k=a*this.size,q=Math.floor(i-h);1>q&&(q=1);i=Math.floor(i+h);i>this.size-1&&(i=this.size-1);var m=Math.floor(j-h);1>m&&(m=1);j=Math.floor(j+h);j>this.size-1&&(j=this.size-1);var o=Math.floor(k-h);1>o&&(o=1);h=Math.floor(k+h);h>this.size-1&&(h=this.size-
+1);for(var p,n,r,s,t,w,u,k=q;k<i;k++){r=this.size2*k;t=k/this.size-f;w=t*t;for(q=m;q<j;q++){n=r+this.size*q;p=q/this.size-b;u=p*p;for(p=o;p<h;p++)s=p/this.size-a,s=g/(1.0E-6+s*s+u+w)-e,0<s&&(this.field[n+p]+=s)}}};this.addPlaneX=function(a,b){var f,g,e,h,i,j=this.size,k=this.yd,q=this.zd,m=this.field,o=j*Math.sqrt(a/b);o>j&&(o=j);for(f=0;f<o;f++)if(g=f/j,g*=g,h=a/(1.0E-4+g)-b,0<h)for(g=0;g<j;g++){i=f+g*k;for(e=0;e<j;e++)m[q*e+i]+=h}};this.addPlaneY=function(a,b){var f,g,e,h,i,j,k=this.size,q=this.yd,
+m=this.zd,o=this.field,p=k*Math.sqrt(a/b);p>k&&(p=k);for(g=0;g<p;g++)if(f=g/k,f*=f,h=a/(1.0E-4+f)-b,0<h){i=g*q;for(f=0;f<k;f++){j=i+f;for(e=0;e<k;e++)o[m*e+j]+=h}}};this.addPlaneZ=function(a,b){var f,g,e,h,i,j,k=this.size,q=this.yd,m=this.zd,o=this.field,p=k*Math.sqrt(a/b);p>k&&(p=k);for(e=0;e<p;e++)if(f=e/k,f*=f,h=a/(1.0E-4+f)-b,0<h){i=m*e;for(g=0;g<k;g++){j=i+g*q;for(f=0;f<k;f++)o[j+f]+=h}}};this.reset=function(){var a;for(a=0;a<this.size3;a++)this.normal_cache[3*a]=0,this.field[a]=0};this.render=
+function(a){this.begin();var b,f,g,e,h,i,j,k,q,m=this.size-2;for(e=1;e<m;e++){q=this.size2*e;j=(e-this.halfsize)/this.halfsize;for(g=1;g<m;g++){k=q+this.size*g;i=(g-this.halfsize)/this.halfsize;for(f=1;f<m;f++)h=(f-this.halfsize)/this.halfsize,b=k+f,this.polygonize(h,i,j,b,this.isolation,a)}}this.end(a)};this.generateGeometry=function(){var a=0,b=new THREE.Geometry,f=[];this.render(function(g){var e,h,i,j,k,q,m,o;for(e=0;e<g.count;e++)m=3*e,k=m+1,o=m+2,h=g.positionArray[m],i=g.positionArray[k],j=
+g.positionArray[o],q=new THREE.Vector3(h,i,j),h=g.normalArray[m],i=g.normalArray[k],j=g.normalArray[o],m=new THREE.Vector3(h,i,j),m.normalize(),k=new THREE.Vertex(q),b.vertices.push(k),f.push(m);q=g.count/3;for(e=0;e<q;e++)m=3*(a+e),k=m+1,o=m+2,h=f[m],i=f[k],j=f[o],m=new THREE.Face3(m,k,o,[h,i,j]),b.faces.push(m);a+=q;g.count=0});return b};this.init(a)};THREE.MarchingCubes.prototype=new THREE.Object3D;THREE.MarchingCubes.prototype.constructor=THREE.MarchingCubes;
+THREE.edgeTable=new Int32Array([0,265,515,778,1030,1295,1541,1804,2060,2309,2575,2822,3082,3331,3593,3840,400,153,915,666,1430,1183,1941,1692,2460,2197,2975,2710,3482,3219,3993,3728,560,825,51,314,1590,1855,1077,1340,2620,2869,2111,2358,3642,3891,3129,3376,928,681,419,170,1958,1711,1445,1196,2988,2725,2479,2214,4010,3747,3497,3232,1120,1385,1635,1898,102,367,613,876,3180,3429,3695,3942,2154,2403,2665,2912,1520,1273,2035,1786,502,255,1013,764,3580,3317,4095,3830,2554,2291,3065,2800,1616,1881,1107,
+1370,598,863,85,348,3676,3925,3167,3414,2650,2899,2137,2384,1984,1737,1475,1226,966,719,453,204,4044,3781,3535,3270,3018,2755,2505,2240,2240,2505,2755,3018,3270,3535,3781,4044,204,453,719,966,1226,1475,1737,1984,2384,2137,2899,2650,3414,3167,3925,3676,348,85,863,598,1370,1107,1881,1616,2800,3065,2291,2554,3830,4095,3317,3580,764,1013,255,502,1786,2035,1273,1520,2912,2665,2403,2154,3942,3695,3429,3180,876,613,367,102,1898,1635,1385,1120,3232,3497,3747,4010,2214,2479,2725,2988,1196,1445,1711,1958,170,
+419,681,928,3376,3129,3891,3642,2358,2111,2869,2620,1340,1077,1855,1590,314,51,825,560,3728,3993,3219,3482,2710,2975,2197,2460,1692,1941,1183,1430,666,915,153,400,3840,3593,3331,3082,2822,2575,2309,2060,1804,1541,1295,1030,778,515,265,0]);
+THREE.triTable=new Int32Array([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,9,8,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,2,10,0,2,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,8,3,2,10,8,10,9,8,-1,-1,-1,-1,-1,-1,-1,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,8,11,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,11,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,-1,1,11,2,1,9,11,9,8,11,-1,-1,-1,-1,-1,-1,-1,3,10,1,11,10,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,10,1,0,8,10,8,11,10,-1,-1,-1,-1,-1,-1,-1,3,9,0,3,11,9,11,10,9,-1,-1,-1,-1,-1,-1,-1,9,8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,7,3,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,1,9,4,7,1,7,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,4,7,3,0,4,1,2,10,-1,-1,-1,-1,-1,-1,-1,9,2,10,9,0,2,8,4,7,
+-1,-1,-1,-1,-1,-1,-1,2,10,9,2,9,7,2,7,3,7,9,4,-1,-1,-1,-1,8,4,7,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,4,7,11,2,4,2,0,4,-1,-1,-1,-1,-1,-1,-1,9,0,1,8,4,7,2,3,11,-1,-1,-1,-1,-1,-1,-1,4,7,11,9,4,11,9,11,2,9,2,1,-1,-1,-1,-1,3,10,1,3,11,10,7,8,4,-1,-1,-1,-1,-1,-1,-1,1,11,10,1,4,11,1,0,4,7,11,4,-1,-1,-1,-1,4,7,8,9,0,11,9,11,10,11,0,3,-1,-1,-1,-1,4,7,11,4,11,9,9,11,10,-1,-1,-1,-1,-1,-1,-1,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,5,4,1,5,0,-1,-1,-1,-1,-1,-1,
+-1,-1,-1,-1,8,5,4,8,3,5,3,1,5,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,10,4,9,5,-1,-1,-1,-1,-1,-1,-1,5,2,10,5,4,2,4,0,2,-1,-1,-1,-1,-1,-1,-1,2,10,5,3,2,5,3,5,4,3,4,8,-1,-1,-1,-1,9,5,4,2,3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,0,8,11,4,9,5,-1,-1,-1,-1,-1,-1,-1,0,5,4,0,1,5,2,3,11,-1,-1,-1,-1,-1,-1,-1,2,1,5,2,5,8,2,8,11,4,8,5,-1,-1,-1,-1,10,3,11,10,1,3,9,5,4,-1,-1,-1,-1,-1,-1,-1,4,9,5,0,8,1,8,10,1,8,11,10,-1,-1,-1,-1,5,4,0,5,0,11,5,11,10,11,0,3,-1,-1,-1,-1,5,4,8,5,
+8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,9,7,8,5,7,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,3,0,9,5,3,5,7,3,-1,-1,-1,-1,-1,-1,-1,0,7,8,0,1,7,1,5,7,-1,-1,-1,-1,-1,-1,-1,1,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,7,8,9,5,7,10,1,2,-1,-1,-1,-1,-1,-1,-1,10,1,2,9,5,0,5,3,0,5,7,3,-1,-1,-1,-1,8,0,2,8,2,5,8,5,7,10,5,2,-1,-1,-1,-1,2,10,5,2,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,7,9,5,7,8,9,3,11,2,-1,-1,-1,-1,-1,-1,-1,9,5,7,9,7,2,9,2,0,2,7,11,-1,-1,-1,-1,2,3,11,0,1,8,1,7,8,1,5,7,-1,-1,-1,-1,11,2,1,11,1,7,7,1,5,-1,-1,-1,-1,-1,-1,
+-1,9,5,8,8,5,7,10,1,3,10,3,11,-1,-1,-1,-1,5,7,0,5,0,9,7,11,0,1,0,10,11,10,0,-1,11,10,0,11,0,3,10,5,0,8,0,7,5,7,0,-1,11,10,5,7,11,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,6,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,0,1,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,1,9,8,5,10,6,-1,-1,-1,-1,-1,-1,-1,1,6,5,2,6,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,6,5,1,2,6,3,0,8,-1,-1,-1,-1,-1,-1,-1,9,6,5,9,0,6,0,2,6,-1,-1,-1,-1,-1,-1,-1,5,9,8,5,8,2,5,2,6,3,2,8,-1,-1,-1,-1,2,3,11,10,6,
+5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,0,8,11,2,0,10,6,5,-1,-1,-1,-1,-1,-1,-1,0,1,9,2,3,11,5,10,6,-1,-1,-1,-1,-1,-1,-1,5,10,6,1,9,2,9,11,2,9,8,11,-1,-1,-1,-1,6,3,11,6,5,3,5,1,3,-1,-1,-1,-1,-1,-1,-1,0,8,11,0,11,5,0,5,1,5,11,6,-1,-1,-1,-1,3,11,6,0,3,6,0,6,5,0,5,9,-1,-1,-1,-1,6,5,9,6,9,11,11,9,8,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,4,7,3,6,5,10,-1,-1,-1,-1,-1,-1,-1,1,9,0,5,10,6,8,4,7,-1,-1,-1,-1,-1,-1,-1,10,6,5,1,9,7,1,7,3,7,9,4,-1,-1,-1,-1,6,1,2,6,5,1,4,7,8,-1,-1,-1,-1,
+-1,-1,-1,1,2,5,5,2,6,3,0,4,3,4,7,-1,-1,-1,-1,8,4,7,9,0,5,0,6,5,0,2,6,-1,-1,-1,-1,7,3,9,7,9,4,3,2,9,5,9,6,2,6,9,-1,3,11,2,7,8,4,10,6,5,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,2,4,2,0,2,7,11,-1,-1,-1,-1,0,1,9,4,7,8,2,3,11,5,10,6,-1,-1,-1,-1,9,2,1,9,11,2,9,4,11,7,11,4,5,10,6,-1,8,4,7,3,11,5,3,5,1,5,11,6,-1,-1,-1,-1,5,1,11,5,11,6,1,0,11,7,11,4,0,4,11,-1,0,5,9,0,6,5,0,3,6,11,6,3,8,4,7,-1,6,5,9,6,9,11,4,7,9,7,11,9,-1,-1,-1,-1,10,4,9,6,4,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,10,6,4,9,10,0,8,3,-1,-1,-1,-1,-1,-1,-1,
+10,0,1,10,6,0,6,4,0,-1,-1,-1,-1,-1,-1,-1,8,3,1,8,1,6,8,6,4,6,1,10,-1,-1,-1,-1,1,4,9,1,2,4,2,6,4,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,9,2,4,9,2,6,4,-1,-1,-1,-1,0,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,3,2,8,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,10,4,9,10,6,4,11,2,3,-1,-1,-1,-1,-1,-1,-1,0,8,2,2,8,11,4,9,10,4,10,6,-1,-1,-1,-1,3,11,2,0,1,6,0,6,4,6,1,10,-1,-1,-1,-1,6,4,1,6,1,10,4,8,1,2,1,11,8,11,1,-1,9,6,4,9,3,6,9,1,3,11,6,3,-1,-1,-1,-1,8,11,1,8,1,0,11,6,1,9,1,4,6,4,1,-1,3,11,6,3,6,0,0,6,4,-1,-1,-1,-1,-1,-1,-1,
+6,4,8,11,6,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,10,6,7,8,10,8,9,10,-1,-1,-1,-1,-1,-1,-1,0,7,3,0,10,7,0,9,10,6,7,10,-1,-1,-1,-1,10,6,7,1,10,7,1,7,8,1,8,0,-1,-1,-1,-1,10,6,7,10,7,1,1,7,3,-1,-1,-1,-1,-1,-1,-1,1,2,6,1,6,8,1,8,9,8,6,7,-1,-1,-1,-1,2,6,9,2,9,1,6,7,9,0,9,3,7,3,9,-1,7,8,0,7,0,6,6,0,2,-1,-1,-1,-1,-1,-1,-1,7,3,2,6,7,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,11,10,6,8,10,8,9,8,6,7,-1,-1,-1,-1,2,0,7,2,7,11,0,9,7,6,7,10,9,10,7,-1,1,8,0,1,7,8,1,10,7,6,7,10,2,3,11,-1,11,2,1,11,1,7,10,6,1,6,7,1,-1,-1,-1,-1,
+8,9,6,8,6,7,9,1,6,11,6,3,1,3,6,-1,0,9,1,11,6,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,8,0,7,0,6,3,11,0,11,6,0,-1,-1,-1,-1,7,11,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,1,9,8,3,1,11,7,6,-1,-1,-1,-1,-1,-1,-1,10,1,2,6,11,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,3,0,8,6,11,7,-1,-1,-1,-1,-1,-1,-1,2,9,0,2,10,9,6,11,7,-1,-1,-1,-1,-1,-1,-1,6,11,7,2,10,3,10,8,3,10,9,8,-1,-1,-1,-1,7,
+2,3,6,2,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,0,8,7,6,0,6,2,0,-1,-1,-1,-1,-1,-1,-1,2,7,6,2,3,7,0,1,9,-1,-1,-1,-1,-1,-1,-1,1,6,2,1,8,6,1,9,8,8,7,6,-1,-1,-1,-1,10,7,6,10,1,7,1,3,7,-1,-1,-1,-1,-1,-1,-1,10,7,6,1,7,10,1,8,7,1,0,8,-1,-1,-1,-1,0,3,7,0,7,10,0,10,9,6,10,7,-1,-1,-1,-1,7,6,10,7,10,8,8,10,9,-1,-1,-1,-1,-1,-1,-1,6,8,4,11,8,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,6,11,3,0,6,0,4,6,-1,-1,-1,-1,-1,-1,-1,8,6,11,8,4,6,9,0,1,-1,-1,-1,-1,-1,-1,-1,9,4,6,9,6,3,9,3,1,11,3,6,-1,-1,-1,-1,6,8,4,6,11,8,2,10,1,-1,-1,-1,
+-1,-1,-1,-1,1,2,10,3,0,11,0,6,11,0,4,6,-1,-1,-1,-1,4,11,8,4,6,11,0,2,9,2,10,9,-1,-1,-1,-1,10,9,3,10,3,2,9,4,3,11,3,6,4,6,3,-1,8,2,3,8,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,0,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,4,2,4,6,4,3,8,-1,-1,-1,-1,1,9,4,1,4,2,2,4,6,-1,-1,-1,-1,-1,-1,-1,8,1,3,8,6,1,8,4,6,6,10,1,-1,-1,-1,-1,10,1,0,10,0,6,6,0,4,-1,-1,-1,-1,-1,-1,-1,4,6,3,4,3,8,6,10,3,0,3,9,10,9,3,-1,10,9,4,6,10,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,5,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,5,11,7,6,
+-1,-1,-1,-1,-1,-1,-1,5,0,1,5,4,0,7,6,11,-1,-1,-1,-1,-1,-1,-1,11,7,6,8,3,4,3,5,4,3,1,5,-1,-1,-1,-1,9,5,4,10,1,2,7,6,11,-1,-1,-1,-1,-1,-1,-1,6,11,7,1,2,10,0,8,3,4,9,5,-1,-1,-1,-1,7,6,11,5,4,10,4,2,10,4,0,2,-1,-1,-1,-1,3,4,8,3,5,4,3,2,5,10,5,2,11,7,6,-1,7,2,3,7,6,2,5,4,9,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,6,0,6,2,6,8,7,-1,-1,-1,-1,3,6,2,3,7,6,1,5,0,5,4,0,-1,-1,-1,-1,6,2,8,6,8,7,2,1,8,4,8,5,1,5,8,-1,9,5,4,10,1,6,1,7,6,1,3,7,-1,-1,-1,-1,1,6,10,1,7,6,1,0,7,8,7,0,9,5,4,-1,4,0,10,4,10,5,0,3,10,6,10,7,3,7,10,
+-1,7,6,10,7,10,8,5,4,10,4,8,10,-1,-1,-1,-1,6,9,5,6,11,9,11,8,9,-1,-1,-1,-1,-1,-1,-1,3,6,11,0,6,3,0,5,6,0,9,5,-1,-1,-1,-1,0,11,8,0,5,11,0,1,5,5,6,11,-1,-1,-1,-1,6,11,3,6,3,5,5,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,11,9,11,8,11,5,6,-1,-1,-1,-1,0,11,3,0,6,11,0,9,6,5,6,9,1,2,10,-1,11,8,5,11,5,6,8,0,5,10,5,2,0,2,5,-1,6,11,3,6,3,5,2,10,3,10,5,3,-1,-1,-1,-1,5,8,9,5,2,8,5,6,2,3,8,2,-1,-1,-1,-1,9,5,6,9,6,0,0,6,2,-1,-1,-1,-1,-1,-1,-1,1,5,8,1,8,0,5,6,8,3,8,2,6,2,8,-1,1,5,6,2,1,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+1,3,6,1,6,10,3,8,6,5,6,9,8,9,6,-1,10,1,0,10,0,6,9,5,0,5,6,0,-1,-1,-1,-1,0,3,8,5,6,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,5,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,7,5,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,11,7,5,8,3,0,-1,-1,-1,-1,-1,-1,-1,5,11,7,5,10,11,1,9,0,-1,-1,-1,-1,-1,-1,-1,10,7,5,10,11,7,9,8,1,8,3,1,-1,-1,-1,-1,11,1,2,11,7,1,7,5,1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,7,1,7,5,7,2,11,-1,-1,-1,-1,9,7,5,9,2,7,9,0,2,2,11,7,-1,-1,-1,-1,7,5,2,7,2,11,5,9,2,3,2,8,9,8,2,-1,2,5,10,2,3,5,3,7,5,-1,-1,
+-1,-1,-1,-1,-1,8,2,0,8,5,2,8,7,5,10,2,5,-1,-1,-1,-1,9,0,1,5,10,3,5,3,7,3,10,2,-1,-1,-1,-1,9,8,2,9,2,1,8,7,2,10,2,5,7,5,2,-1,1,3,5,3,7,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,7,0,7,1,1,7,5,-1,-1,-1,-1,-1,-1,-1,9,0,3,9,3,5,5,3,7,-1,-1,-1,-1,-1,-1,-1,9,8,7,5,9,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5,8,4,5,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,5,0,4,5,11,0,5,10,11,11,3,0,-1,-1,-1,-1,0,1,9,8,4,10,8,10,11,10,4,5,-1,-1,-1,-1,10,11,4,10,4,5,11,3,4,9,4,1,3,1,4,-1,2,5,1,2,8,5,2,11,8,4,5,8,-1,-1,-1,-1,0,4,11,0,11,3,4,5,11,
+2,11,1,5,1,11,-1,0,2,5,0,5,9,2,11,5,4,5,8,11,8,5,-1,9,4,5,2,11,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,5,10,3,5,2,3,4,5,3,8,4,-1,-1,-1,-1,5,10,2,5,2,4,4,2,0,-1,-1,-1,-1,-1,-1,-1,3,10,2,3,5,10,3,8,5,4,5,8,0,1,9,-1,5,10,2,5,2,4,1,9,2,9,4,2,-1,-1,-1,-1,8,4,5,8,5,3,3,5,1,-1,-1,-1,-1,-1,-1,-1,0,4,5,1,0,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,4,5,8,5,3,9,0,5,0,3,5,-1,-1,-1,-1,9,4,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,11,7,4,9,11,9,10,11,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,7,9,11,7,9,10,11,-1,-1,-1,-1,1,10,11,1,11,
+4,1,4,0,7,4,11,-1,-1,-1,-1,3,1,4,3,4,8,1,10,4,7,4,11,10,11,4,-1,4,11,7,9,11,4,9,2,11,9,1,2,-1,-1,-1,-1,9,7,4,9,11,7,9,1,11,2,11,1,0,8,3,-1,11,7,4,11,4,2,2,4,0,-1,-1,-1,-1,-1,-1,-1,11,7,4,11,4,2,8,3,4,3,2,4,-1,-1,-1,-1,2,9,10,2,7,9,2,3,7,7,4,9,-1,-1,-1,-1,9,10,7,9,7,4,10,2,7,8,7,0,2,0,7,-1,3,7,10,3,10,2,7,4,10,1,10,0,4,0,10,-1,1,10,2,8,7,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,7,1,3,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,0,8,1,8,7,1,-1,-1,-1,-1,4,0,3,7,4,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,8,7,-1,-1,-1,
+-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,11,9,10,-1,-1,-1,-1,-1,-1,-1,0,1,10,0,10,8,8,10,11,-1,-1,-1,-1,-1,-1,-1,3,1,10,11,3,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,11,1,11,9,9,11,8,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,1,2,9,2,11,9,-1,-1,-1,-1,0,2,11,8,0,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,2,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,10,8,9,-1,-1,-1,-1,-1,-1,-1,9,10,2,0,9,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,0,1,8,1,10,8,-1,-1,-1,-1,1,10,
+2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,3,8,9,1,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,9,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,3,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]);THREE.LensFlare=function(a,b,c,d,f){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,f)};THREE.LensFlare.prototype=new THREE.Object3D;THREE.LensFlare.prototype.constructor=THREE.LensFlare;
+THREE.LensFlare.prototype.supr=THREE.Object3D.prototype;THREE.LensFlare.prototype.add=function(a,b,c,d,f,g){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===g&&(g=1);void 0===f&&(f=new THREE.Color(16777215));if(void 0===d)d=THREE.NormalBlending;c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:g,color:f,blending:d})};
+THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,f=2*-this.positionScreen.y;for(a=0;a<b;a++)c=this.lensFlares[a],c.x=this.positionScreen.x+d*c.distance,c.y=this.positionScreen.y+f*c.distance,c.wantedRotation=0.25*c.x*Math.PI,c.rotation+=0.25*(c.wantedRotation-c.rotation)};
+THREE.LensFlarePlugin=function(){function a(a){var c=b.createProgram(),d=b.createShader(b.FRAGMENT_SHADER),e=b.createShader(b.VERTEX_SHADER);b.shaderSource(d,a.fragmentShader);b.shaderSource(e,a.vertexShader);b.compileShader(d);b.compileShader(e);b.attachShader(c,d);b.attachShader(c,e);b.linkProgram(c);return c}var b,c,d,f,g,e,h,i,j,k,q,m,o;this.init=function(p){b=p.context;c=p;d=new Float32Array(16);f=new Uint16Array(6);p=0;d[p++]=-1;d[p++]=-1;d[p++]=0;d[p++]=0;d[p++]=1;d[p++]=-1;d[p++]=1;d[p++]=
+0;d[p++]=1;d[p++]=1;d[p++]=1;d[p++]=1;d[p++]=-1;d[p++]=1;d[p++]=0;d[p++]=1;p=0;f[p++]=0;f[p++]=1;f[p++]=2;f[p++]=0;f[p++]=2;f[p++]=3;g=b.createBuffer();e=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER,d,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,e);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);h=b.createTexture();i=b.createTexture();b.bindTexture(b.TEXTURE_2D,h);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16,0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,
+b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,i);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);
+b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(j=!1,k=a(THREE.ShaderFlares.lensFlare)):(j=!0,k=a(THREE.ShaderFlares.lensFlareVertexTexture));q={};m={};q.vertex=b.getAttribLocation(k,"position");q.uv=b.getAttribLocation(k,"uv");m.renderType=b.getUniformLocation(k,"renderType");m.map=b.getUniformLocation(k,"map");m.occlusionMap=b.getUniformLocation(k,"occlusionMap");m.opacity=b.getUniformLocation(k,"opacity");m.color=b.getUniformLocation(k,
+"color");m.scale=b.getUniformLocation(k,"scale");m.rotation=b.getUniformLocation(k,"rotation");m.screenPosition=b.getUniformLocation(k,"screenPosition");o=!1};this.render=function(a,d,f,s){var a=a.__webglFlares,t=a.length;if(t){var w=new THREE.Vector3,u=s/f,v=0.5*f,A=0.5*s,F=16/s,B=new THREE.Vector2(F*u,F),D=new THREE.Vector3(1,1,0),H=new THREE.Vector2(1,1),I=m,F=q;b.useProgram(k);o||(b.enableVertexAttribArray(q.vertex),b.enableVertexAttribArray(q.uv),o=!0);b.uniform1i(I.occlusionMap,0);b.uniform1i(I.map,
+1);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(F.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(F.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,e);b.disable(b.CULL_FACE);b.depthMask(!1);var Q,P,L,K,O;for(Q=0;Q<t;Q++)if(F=16/s,B.set(F*u,F),K=a[Q],w.set(K.matrixWorld.n14,K.matrixWorld.n24,K.matrixWorld.n34),d.matrixWorldInverse.multiplyVector3(w),d.projectionMatrix.multiplyVector3(w),D.copy(w),H.x=D.x*v+v,H.y=D.y*A+A,j||0<H.x&&H.x<f&&0<H.y&&H.y<s){b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,
+h);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGB,H.x-8,H.y-8,16,16,0);b.uniform1i(I.renderType,0);b.uniform2f(I.scale,B.x,B.y);b.uniform3f(I.screenPosition,D.x,D.y,D.z);b.disable(b.BLEND);b.enable(b.DEPTH_TEST);b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0);b.activeTexture(b.TEXTURE0);b.bindTexture(b.TEXTURE_2D,i);b.copyTexImage2D(b.TEXTURE_2D,0,b.RGBA,H.x-8,H.y-8,16,16,0);b.uniform1i(I.renderType,1);b.disable(b.DEPTH_TEST);b.activeTexture(b.TEXTURE1);b.bindTexture(b.TEXTURE_2D,h);b.drawElements(b.TRIANGLES,
+6,b.UNSIGNED_SHORT,0);K.positionScreen.copy(D);K.customUpdateCallback?K.customUpdateCallback(K):K.updateLensFlares();b.uniform1i(I.renderType,2);b.enable(b.BLEND);for(P=0,L=K.lensFlares.length;P<L;P++)if(O=K.lensFlares[P],0.001<O.opacity&&0.001<O.scale)D.x=O.x,D.y=O.y,D.z=O.z,F=O.size*O.scale/s,B.x=F*u,B.y=F,b.uniform3f(I.screenPosition,D.x,D.y,D.z),b.uniform2f(I.scale,B.x,B.y),b.uniform1f(I.rotation,O.rotation),b.uniform1f(I.opacity,O.opacity),b.uniform3f(I.color,O.color.r,O.color.g,O.color.b),c.setBlending(O.blending),
+c.setTexture(O.texture,1),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0)}b.enable(b.CULL_FACE);b.enable(b.DEPTH_TEST);b.depthMask(!0)}}};
+THREE.ShadowMapPlugin=function(){var a,b,c,d,f=new THREE.Frustum,g=new THREE.Matrix4,e=new THREE.Vector3,h=new THREE.Vector3;this.init=function(e){a=e.context;b=e;var e=THREE.ShaderLib.depthRGBA,f=THREE.UniformsUtils.clone(e.uniforms);c=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f});d=new THREE.ShaderMaterial({fragmentShader:e.fragmentShader,vertexShader:e.vertexShader,uniforms:f,morphTargets:!0});c._shadowPass=!0;d._shadowPass=!0};this.render=function(a,
+c){b.shadowMapEnabled&&b.shadowMapAutoUpdate&&this.update(a,c)};this.update=function(i,j){var k,q,m,o,p,n,r,s,t,w=[];o=0;a.clearColor(1,1,1,1);a.disable(a.BLEND);b.shadowMapCullFrontFaces&&a.cullFace(a.FRONT);b.setDepthTest(!0);for(k=0,q=i.__lights.length;k<q;k++)if(m=i.__lights[k],m.castShadow)if(m instanceof THREE.DirectionalLight&&m.shadowCascade)for(p=0;p<m.shadowCascadeCount;p++){var u;if(m.shadowCascadeArray[p])u=m.shadowCascadeArray[p];else{t=m;r=p;u=new THREE.DirectionalLight;u.isVirtual=
+!0;u.onlyShadow=!0;u.castShadow=!0;u.shadowCameraNear=t.shadowCameraNear;u.shadowCameraFar=t.shadowCameraFar;u.shadowCameraLeft=t.shadowCameraLeft;u.shadowCameraRight=t.shadowCameraRight;u.shadowCameraBottom=t.shadowCameraBottom;u.shadowCameraTop=t.shadowCameraTop;u.shadowCameraVisible=t.shadowCameraVisible;u.shadowDarkness=t.shadowDarkness;u.shadowBias=t.shadowCascadeBias[r];u.shadowMapWidth=t.shadowCascadeWidth[r];u.shadowMapHeight=t.shadowCascadeHeight[r];u.pointsWorld=[];u.pointsFrustum=[];s=
+u.pointsWorld;n=u.pointsFrustum;for(var v=0;8>v;v++)s[v]=new THREE.Vector3,n[v]=new THREE.Vector3;s=t.shadowCascadeNearZ[r];t=t.shadowCascadeFarZ[r];n[0].set(-1,-1,s);n[1].set(1,-1,s);n[2].set(-1,1,s);n[3].set(1,1,s);n[4].set(-1,-1,t);n[5].set(1,-1,t);n[6].set(-1,1,t);n[7].set(1,1,t);u.originalCamera=j;n=new THREE.Gyroscope;n.position=m.shadowCascadeOffset;n.add(u);n.add(u.target);j.add(n);m.shadowCascadeArray[p]=u;console.log("Created virtualLight",u)}r=m;s=p;t=r.shadowCascadeArray[s];t.position.copy(r.position);
+t.target.position.copy(r.target.position);t.lookAt(t.target);t.shadowCameraVisible=r.shadowCameraVisible;t.shadowDarkness=r.shadowDarkness;t.shadowBias=r.shadowCascadeBias[s];n=r.shadowCascadeNearZ[s];r=r.shadowCascadeFarZ[s];t=t.pointsFrustum;t[0].z=n;t[1].z=n;t[2].z=n;t[3].z=n;t[4].z=r;t[5].z=r;t[6].z=r;t[7].z=r;w[o]=u;o++}else w[o]=m,o++;for(k=0,q=w.length;k<q;k++){m=w[k];if(!m.shadowMap)m.shadowMap=new THREE.WebGLRenderTarget(m.shadowMapWidth,m.shadowMapHeight,{minFilter:THREE.LinearFilter,magFilter:THREE.LinearFilter,
+format:THREE.RGBAFormat}),m.shadowMapSize=new THREE.Vector2(m.shadowMapWidth,m.shadowMapHeight),m.shadowMatrix=new THREE.Matrix4;if(!m.shadowCamera){if(m instanceof THREE.SpotLight)m.shadowCamera=new THREE.PerspectiveCamera(m.shadowCameraFov,m.shadowMapWidth/m.shadowMapHeight,m.shadowCameraNear,m.shadowCameraFar);else if(m instanceof THREE.DirectionalLight)m.shadowCamera=new THREE.OrthographicCamera(m.shadowCameraLeft,m.shadowCameraRight,m.shadowCameraTop,m.shadowCameraBottom,m.shadowCameraNear,m.shadowCameraFar);
+else{console.error("Unsupported light type for shadow");continue}i.add(m.shadowCamera);b.autoUpdateScene&&i.updateMatrixWorld()}if(m.shadowCameraVisible&&!m.cameraHelper)m.cameraHelper=new THREE.CameraHelper(m.shadowCamera),m.shadowCamera.add(m.cameraHelper);if(m.isVirtual&&u.originalCamera==j){p=j;o=m.shadowCamera;n=m.pointsFrustum;t=m.pointsWorld;e.set(Infinity,Infinity,Infinity);h.set(-Infinity,-Infinity,-Infinity);for(r=0;8>r;r++){s=t[r];s.copy(n[r]);THREE.ShadowMapPlugin.__projector.unprojectVector(s,
+p);o.matrixWorldInverse.multiplyVector3(s);if(s.x<e.x)e.x=s.x;if(s.x>h.x)h.x=s.x;if(s.y<e.y)e.y=s.y;if(s.y>h.y)h.y=s.y;if(s.z<e.z)e.z=s.z;if(s.z>h.z)h.z=s.z}o.left=e.x;o.right=h.x;o.top=h.y;o.bottom=e.y;o.updateProjectionMatrix()}o=m.shadowMap;n=m.shadowMatrix;p=m.shadowCamera;p.position.copy(m.matrixWorld.getPosition());p.lookAt(m.target.matrixWorld.getPosition());p.updateMatrixWorld();p.matrixWorldInverse.getInverse(p.matrixWorld);if(m.cameraHelper)m.cameraHelper.lines.visible=m.shadowCameraVisible;
+m.shadowCameraVisible&&m.cameraHelper.update(m.shadowCamera);n.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);n.multiplySelf(p.projectionMatrix);n.multiplySelf(p.matrixWorldInverse);if(!p._viewMatrixArray)p._viewMatrixArray=new Float32Array(16);p.matrixWorldInverse.flattenToArray(p._viewMatrixArray);if(!p._projectionMatrixArray)p._projectionMatrixArray=new Float32Array(16);p.projectionMatrix.flattenToArray(p._projectionMatrixArray);g.multiply(p.projectionMatrix,p.matrixWorldInverse);f.setFromMatrix(g);
+b.setRenderTarget(o);b.clear();t=i.__webglObjects;for(m=0,o=t.length;m<o;m++)if(r=t[m],n=r.object,r.render=!1,n.visible&&n.castShadow&&(!(n instanceof THREE.Mesh)||!n.frustumCulled||f.contains(n)))n.matrixWorld.flattenToArray(n._objectMatrixArray),n._modelViewMatrix.multiplyToArray(p.matrixWorldInverse,n.matrixWorld,n._modelViewMatrixArray),r.render=!0;for(m=0,o=t.length;m<o;m++)if(r=t[m],r.render)n=r.object,r=r.buffer,b.setObjectFaces(n),s=n.customDepthMaterial?n.customDepthMaterial:n.geometry.morphTargets.length?
+d:c,r instanceof THREE.BufferGeometry?b.renderBufferDirect(p,i.__lights,null,s,r,n):b.renderBuffer(p,i.__lights,null,s,r,n);t=i.__webglObjectsImmediate;for(m=0,o=t.length;m<o;m++)r=t[m],n=r.object,n.visible&&n.castShadow&&(n.matrixAutoUpdate&&n.matrixWorld.flattenToArray(n._objectMatrixArray),n._modelViewMatrix.multiplyToArray(p.matrixWorldInverse,n.matrixWorld,n._modelViewMatrixArray),b.renderImmediateObject(p,i.__lights,null,c,n))}k=b.getClearColor();q=b.getClearAlpha();a.clearColor(k.r,k.g,k.b,
+q);a.enable(a.BLEND);b.shadowMapCullFrontFaces&&a.cullFace(a.BACK)}};THREE.ShadowMapPlugin.__projector=new THREE.Projector;
+THREE.SpritePlugin=function(){function a(a,b){return b.z-a.z}var b,c,d,f,g,e,h,i,j,k;this.init=function(a){b=a.context;c=a;d=new Float32Array(16);f=new Uint16Array(6);a=0;d[a++]=-1;d[a++]=-1;d[a++]=0;d[a++]=1;d[a++]=1;d[a++]=-1;d[a++]=1;d[a++]=1;d[a++]=1;d[a++]=1;d[a++]=1;d[a++]=0;d[a++]=-1;d[a++]=1;d[a++]=0;a=d[a++]=0;f[a++]=0;f[a++]=1;f[a++]=2;f[a++]=0;f[a++]=2;f[a++]=3;g=b.createBuffer();e=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,g);b.bufferData(b.ARRAY_BUFFER,d,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,
+e);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);var a=THREE.ShaderSprite.sprite,m=b.createProgram(),o=b.createShader(b.FRAGMENT_SHADER),p=b.createShader(b.VERTEX_SHADER);b.shaderSource(o,a.fragmentShader);b.shaderSource(p,a.vertexShader);b.compileShader(o);b.compileShader(p);b.attachShader(m,o);b.attachShader(m,p);b.linkProgram(m);h=m;i={};j={};i.position=b.getAttribLocation(h,"position");i.uv=b.getAttribLocation(h,"uv");j.uvOffset=b.getUniformLocation(h,"uvOffset");j.uvScale=b.getUniformLocation(h,
+"uvScale");j.rotation=b.getUniformLocation(h,"rotation");j.scale=b.getUniformLocation(h,"scale");j.alignment=b.getUniformLocation(h,"alignment");j.color=b.getUniformLocation(h,"color");j.map=b.getUniformLocation(h,"map");j.opacity=b.getUniformLocation(h,"opacity");j.useScreenCoordinates=b.getUniformLocation(h,"useScreenCoordinates");j.affectedByDistance=b.getUniformLocation(h,"affectedByDistance");j.screenPosition=b.getUniformLocation(h,"screenPosition");j.modelViewMatrix=b.getUniformLocation(h,"modelViewMatrix");
+j.projectionMatrix=b.getUniformLocation(h,"projectionMatrix");k=!1};this.render=function(d,f,o,p){var d=d.__webglSprites,n=d.length;if(n){var r=i,s=j,t=p/o,o=0.5*o,w=0.5*p,u=!0;b.useProgram(h);k||(b.enableVertexAttribArray(r.position),b.enableVertexAttribArray(r.uv),k=!0);b.disable(b.CULL_FACE);b.enable(b.BLEND);b.depthMask(!0);b.bindBuffer(b.ARRAY_BUFFER,g);b.vertexAttribPointer(r.position,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(r.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,e);b.uniformMatrix4fv(s.projectionMatrix,
+!1,f._projectionMatrixArray);b.activeTexture(b.TEXTURE0);b.uniform1i(s.map,0);for(var v,A=[],r=0;r<n;r++)if(v=d[r],v.visible&&0!==v.opacity)v.useScreenCoordinates?v.z=-v.position.z:(v._modelViewMatrix.multiplyToArray(f.matrixWorldInverse,v.matrixWorld,v._modelViewMatrixArray),v.z=-v._modelViewMatrix.n34);d.sort(a);for(r=0;r<n;r++)v=d[r],v.visible&&0!==v.opacity&&v.map&&v.map.image&&v.map.image.width&&(v.useScreenCoordinates?(b.uniform1i(s.useScreenCoordinates,1),b.uniform3f(s.screenPosition,(v.position.x-
+o)/o,(w-v.position.y)/w,Math.max(0,Math.min(1,v.position.z)))):(b.uniform1i(s.useScreenCoordinates,0),b.uniform1i(s.affectedByDistance,v.affectedByDistance?1:0),b.uniformMatrix4fv(s.modelViewMatrix,!1,v._modelViewMatrixArray)),f=v.map.image.width/(v.scaleByViewport?p:1),A[0]=f*t*v.scale.x,A[1]=f*v.scale.y,b.uniform2f(s.uvScale,v.uvScale.x,v.uvScale.y),b.uniform2f(s.uvOffset,v.uvOffset.x,v.uvOffset.y),b.uniform2f(s.alignment,v.alignment.x,v.alignment.y),b.uniform1f(s.opacity,v.opacity),b.uniform3f(s.color,
+v.color.r,v.color.g,v.color.b),b.uniform1f(s.rotation,v.rotation),b.uniform2fv(s.scale,A),v.mergeWith3D&&!u?(b.enable(b.DEPTH_TEST),u=!0):!v.mergeWith3D&&u&&(b.disable(b.DEPTH_TEST),u=!1),c.setBlending(v.blending),c.setTexture(v.map,0),b.drawElements(b.TRIANGLES,6,b.UNSIGNED_SHORT,0));b.enable(b.CULL_FACE);b.enable(b.DEPTH_TEST);b.depthMask(!0)}}};
+if(THREE.WebGLRenderer)THREE.AnaglyphWebGLRenderer=function(a){THREE.WebGLRenderer.call(this,a);this.autoUpdateScene=!1;var b=this,c=this.setSize,d=this.render,f=new THREE.PerspectiveCamera,g=new THREE.PerspectiveCamera,e=new THREE.Matrix4,h=new THREE.Matrix4,i,j,k,q;f.matrixAutoUpdate=g.matrixAutoUpdate=!1;var a={minFilter:THREE.LinearFilter,magFilter:THREE.NearestFilter,format:THREE.RGBAFormat},m=new THREE.WebGLRenderTarget(512,512,a),o=new THREE.WebGLRenderTarget(512,512,a),p=new THREE.PerspectiveCamera(53,
+1,1,1E4);p.position.z=2;var a=new THREE.ShaderMaterial({uniforms:{mapLeft:{type:"t",value:0,texture:m},mapRight:{type:"t",value:1,texture:o}},vertexShader:"varying vec2 vUv;\nvoid main() {\nvUv = vec2( uv.x, 1.0 - uv.y );\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D mapLeft;\nuniform sampler2D mapRight;\nvarying vec2 vUv;\nvoid main() {\nvec4 colorL, colorR;\nvec2 uv = vUv;\ncolorL = texture2D( mapLeft, uv );\ncolorR = texture2D( mapRight, uv );\ngl_FragColor = vec4( colorL.g * 0.7 + colorL.b * 0.3, colorR.g, colorR.b, colorL.a + colorR.a ) * 1.1;\n}"}),
+n=new THREE.Scene;n.add(new THREE.Mesh(new THREE.PlaneGeometry(2,2),a));n.add(p);this.setSize=function(a,d){c.call(b,a,d);m.width=a;m.height=d;o.width=a;o.height=d};this.render=function(a,c){a.updateMatrixWorld();if(i!==c.aspect||j!==c.near||k!==c.far||q!==c.fov){i=c.aspect;j=c.near;k=c.far;q=c.fov;var t=c.projectionMatrix.clone(),w=0.5*(125/30),u=w*j/125,v=j*Math.tan(q*Math.PI/360),A;e.n14=w;h.n14=-w;w=-v*i+u;A=v*i+u;t.n11=2*j/(A-w);t.n13=(A+w)/(A-w);f.projectionMatrix.copy(t);w=-v*i-u;A=v*i-u;t.n11=
+2*j/(A-w);t.n13=(A+w)/(A-w);g.projectionMatrix.copy(t)}f.matrixWorld.copy(c.matrixWorld).multiplySelf(h);f.position.copy(c.position);f.near=c.near;f.far=c.far;d.call(b,a,f,m,!0);g.matrixWorld.copy(c.matrixWorld).multiplySelf(e);g.position.copy(c.position);g.near=c.near;g.far=c.far;d.call(b,a,g,o,!0);n.updateMatrixWorld();d.call(b,n,p)}};
+if(THREE.WebGLRenderer)THREE.CrosseyedWebGLRenderer=function(a){THREE.WebGLRenderer.call(this,a);this.autoClear=!1;var b=this,c=this.setSize,d=this.render,f,g,e=new THREE.PerspectiveCamera;e.target=new THREE.Vector3(0,0,0);var h=new THREE.PerspectiveCamera;h.target=new THREE.Vector3(0,0,0);b.separation=10;if(a&&void 0!==a.separation)b.separation=a.separation;this.setSize=function(a,d){c.call(b,a,d);f=a/2;g=d};this.render=function(a,c){this.clear();e.fov=c.fov;e.aspect=0.5*c.aspect;e.near=c.near;e.far=
+c.far;e.updateProjectionMatrix();e.position.copy(c.position);e.target.copy(c.target);e.translateX(b.separation);e.lookAt(e.target);h.projectionMatrix=e.projectionMatrix;h.position.copy(c.position);h.target.copy(c.target);h.translateX(-b.separation);h.lookAt(h.target);this.setViewport(0,0,f,g);d.call(b,a,e);this.setViewport(f,0,f,g);d.call(b,a,h,!1)}};
+THREE.ShaderFlares={lensFlareVertexTexture:{vertexShader:"uniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform int renderType;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.1 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.5 ) ) +\ntexture2D( occlusionMap, vec2( 0.9, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.1, 0.9 ) ) +\ntexture2D( occlusionMap, vec2( 0.1, 0.5 ) ) +\ntexture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility = (       visibility.r / 9.0 ) *\n( 1.0 - visibility.g / 9.0 ) *\n(       visibility.b / 9.0 ) *\n( 1.0 - visibility.a / 9.0 );\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",fragmentShader:"precision mediump float;\nuniform sampler2D map;\nuniform float opacity;\nuniform int renderType;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"},
+lensFlare:{vertexShader:"uniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform int renderType;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",fragmentShader:"precision mediump float;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform int renderType;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a +\ntexture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a +\ntexture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a +\ntexture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}};
+THREE.ShaderSprite={sprite:{vertexShader:"uniform int useScreenCoordinates;\nuniform int affectedByDistance;\nuniform vec3 screenPosition;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 alignment;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = position + alignment;\nvec2 rotatedPosition;\nrotatedPosition.x = ( cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y ) * scale.x;\nrotatedPosition.y = ( sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y ) * scale.y;\nvec4 finalPosition;\nif( useScreenCoordinates != 0 ) {\nfinalPosition = vec4( screenPosition.xy + rotatedPosition, screenPosition.z, 1.0 );\n} else {\nfinalPosition = projectionMatrix * modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition * ( affectedByDistance == 1 ? 1.0 : finalPosition.z );\n}\ngl_Position = finalPosition;\n}",
+fragmentShader:"precision mediump float;\nuniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\n}"}};
diff --git a/js/libs/cube/fb.js b/js/libs/cube/fb.js
new file mode 100644 (file)
index 0000000..a309213
--- /dev/null
@@ -0,0 +1,45 @@
+function fb(o, type) {
+       if (o == undefined) {
+               o = '';
+       }
+       if (type == undefined) {
+               type = 'log';
+       }
+
+       var string = '';
+       string = JSON.stringify(o);
+
+       if (DATAS.phonegap) {
+               try {
+                       if (type == 'log') {
+                               cordova.logger.debug(string);
+                       } else if (type == 'error') {
+                               cordova.logger.error(string);
+                       }
+               } catch (err) {
+
+               }
+       } else {
+               if (window.console != undefined) {
+                       try {
+                               if (type == 'log') {
+                                       window.console.log(o);
+                               } else if (type == 'error') {
+                                       window.console.error(o);
+                               }
+                       } catch (err) {
+
+                       }
+               }
+       }
+       return;
+}
+
+window.onerror = function(errorMsg, url, lineNumber) {
+       fb(errorMsg + ' in ' + url + ' at line ' + lineNumber, 'error');
+};
+
+function is(type, obj) {
+       var clas = Object.prototype.toString.call(obj).slice(8, -1);
+       return obj !== undefined && obj !== null && clas === type;
+}
diff --git a/js/libs/cube/util.js b/js/libs/cube/util.js
new file mode 100644 (file)
index 0000000..8fe8744
--- /dev/null
@@ -0,0 +1,89 @@
+function ucfirst(str) {
+       str += '';
+       var f = str.charAt(0).toUpperCase();
+       return f + str.substr(1);
+}
+
+function arrayRemove(array, element) {
+       var index = array.indexOf(element);
+       if (index == -1) {
+               return;
+       }
+       array.splice(index, 1);
+       return array;
+}
+
+function trim(str, charlist) {
+       // http://kevin.vanzonneveld.net
+       // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+       // +   improved by: mdsjack (http://www.mdsjack.bo.it)
+       // +   improved by: Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev)
+       // +      input by: Erkekjetter
+       // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+       // +      input by: DxGx
+       // +   improved by: Steven Levithan (http://blog.stevenlevithan.com)
+       // +    tweaked by: Jack
+       // +   bugfixed by: Onno Marsman
+       // *     example 1: trim('    Kevin van Zonneveld    ');
+       // *     returns 1: 'Kevin van Zonneveld'
+       // *     example 2: trim('Hello World', 'Hdle');
+       // *     returns 2: 'o Wor'
+       // *     example 3: trim(16, 1);
+       // *     returns 3: 6
+       var whitespace, l = 0,
+                       i = 0;
+       str += '';
+
+       if (!charlist) {
+               // default list
+               whitespace = " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";
+       } else {
+               // preg_quote custom list
+               charlist += '';
+               whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1');
+       }
+
+       l = str.length;
+       for (i = 0; i < l; i++) {
+               if (whitespace.indexOf(str.charAt(i)) === -1) {
+                       str = str.substring(i);
+                       break;
+               }
+       }
+
+       l = str.length;
+       for (i = l - 1; i >= 0; i--) {
+               if (whitespace.indexOf(str.charAt(i)) === -1) {
+                       str = str.substring(0, i + 1);
+                       break;
+               }
+       }
+
+       return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
+}
+
+
+(function() {
+       var lastTime = 0;
+       var vendors = ['ms', 'moz', 'webkit', 'o'];
+       for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
+               window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
+               window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
+                               || window[vendors[x] + 'CancelRequestAnimationFrame'];
+       }
+       if (!window.requestAnimationFrame)
+               window.requestAnimationFrame = function(callback, element) {
+                       var currTime = new Date().getTime();
+                       var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+                       var id = window.setTimeout(function() {
+                               callback(currTime + timeToCall);
+                       },
+                                       timeToCall);
+                       lastTime = currTime + timeToCall;
+                       return id;
+               };
+       if (!window.cancelAnimationFrame)
+               window.cancelAnimationFrame = function(id) {
+                       clearTimeout(id);
+               };
+}());
\ No newline at end of file
diff --git a/js/libs/fix/detect-zoom.js b/js/libs/fix/detect-zoom.js
new file mode 100644 (file)
index 0000000..0142291
--- /dev/null
@@ -0,0 +1,242 @@
+// detect-zoom is dual-licensed under the WTFPL and MIT license,
+// at the recipient's choice.
+// https://github.com/yonran/detect-zoom/
+var DetectZoom = {
+       mediaQueryBinarySearch: function(
+                       property, unit, a, b, maxIter, epsilon) {
+               var matchMedia;
+               var head, style, div
+               if (window.matchMedia) {
+                       matchMedia = window.matchMedia;
+               } else {
+                       head = document.getElementsByTagName('head')[0];
+                       style = document.createElement('style');
+                       div = document.createElement('div');
+                       div.className = 'mediaQueryBinarySearch';
+                       head.appendChild(style);
+                       div.style.display = 'none';
+                       document.body.appendChild(div);
+                       matchMedia = function(query) {
+                               style.sheet.insertRule('@media ' + query +
+                                               '{.mediaQueryBinarySearch ' +
+                                               '{text-decoration: underline} }', 0);
+                               var matched = getComputedStyle(div, null).textDecoration
+                                               == 'underline';
+                               style.sheet.deleteRule(0);
+                               return {matches: matched};
+                       }
+               }
+               var r = binarySearch(a, b, maxIter);
+               if (div) {
+                       head.removeChild(style);
+                       document.body.removeChild(div);
+               }
+               return r;
+
+               function binarySearch(a, b, maxIter) {
+                       var mid = (a + b) / 2;
+                       if (maxIter == 0 || b - a < epsilon)
+                               return mid;
+                       var query = "(" + property + ":" + mid + unit + ")";
+                       if (matchMedia(query).matches) {
+                               return binarySearch(mid, b, maxIter - 1);
+                       } else {
+                               return binarySearch(a, mid, maxIter - 1);
+                       }
+               }
+       },
+       _zoomIe7: function() {
+               // the trick: body's offsetWidth was in CSS pixels, while
+               // getBoundingClientRect() was in system pixels in IE7.
+               // Thanks to http://help.dottoro.com/ljgshbne.php
+               var rect = document.body.getBoundingClientRect();
+               var z = (rect.right - rect.left) / document.body.offsetWidth;
+               z = Math.round(z * 100) / 100;
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       _zoomIe8: function() {
+               // IE 8+: no trick needed!
+               // TODO: MSDN says that logicalXDPI and deviceXDPI existed since IE6
+               // (which didn't even have whole-page zoom). Check to see whether
+               // this method would also work in IE7.
+               var zoom = screen.deviceXDPI / screen.logicalXDPI;
+               return {
+                       zoom: zoom,
+                       devicePxPerCssPx: zoom
+               };
+       },
+       _zoomWebkitMobile: function() {
+               // the trick: window.innerWIdth is in CSS pixels, while
+               // screen.width and screen.height are in system pixels.
+               // And there are no scrollbars to mess up the measurement.
+               var devicePixelRatio = window.devicePixelRatio != null ? window.devicePixelRatio : 1
+                               , deviceWidth;
+               if (Math.abs(window.orientation) == 90) {
+                       deviceWidth = screen.height;
+               } else {
+                       deviceWidth = screen.width;
+               }
+               var z = deviceWidth / window.innerWidth;
+               // return immediately; don't round at the end.
+               return {zoom: z, devicePxPerCssPx: z * devicePixelRatio};
+       },
+       _zoomWebkit: function() {
+               // the trick: an element's clientHeight is in CSS pixels, while you can
+               // set its line-height in system pixels using font-size and
+               // -webkit-text-size-adjust:none.
+               // device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/
+
+               // Previous trick (used before http://trac.webkit.org/changeset/100847):
+               // documentElement.scrollWidth is in CSS pixels, while
+               // document.width was in system pixels. Note that this is the
+               // layout width of the document, which is slightly different from viewport
+               // because document width does not include scrollbars and might be wider
+               // due to big elements.
+
+               var devicePixelRatio = window.devicePixelRatio != null ? window.devicePixelRatio : 1;
+
+               // The container exists so that the div will be laid out in its own flow
+               // while not impacting the layout, viewport size, or display of the
+               // webpage as a whole.
+               var container = document.createElement('div')
+                               , div = document.createElement('div');
+
+               // Add !important and relevant CSS rule resets
+               // so that other rules cannot affect the results.
+               var important = function(str) {
+                       return str.replace(/;/g, " !important;");
+               };
+
+               container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;'));
+               div.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0";
+               div.setAttribute('style', important('font: 100px/1em sans-serif; -webkit-text-size-adjust: none; height: auto; width: 1em; padding: 0; overflow: visible;'));
+
+               container.appendChild(div);
+               document.body.appendChild(container);
+               var z = 1000 / div.clientHeight;
+               z = Math.round(z * 100) / 100;
+               var r = {
+                       zoom: z,
+                       devicePxPerCssPx: devicePixelRatio * z
+               };
+               document.body.removeChild(container);
+               return r;
+       },
+       _zoomFF35: function() {
+               // the trick for FF3.5 ONLY: device-width gives CSS pixels, while
+               // screen.width gave system pixels. Thanks to QuirksMode's widths table,
+               // which called it a bug. http://www.quirksmode.org/m/widths.html
+               var z = screen.width /
+                               this.mediaQueryBinarySearch('min-device-width', 'px', 0, 6000, 20, .0001);
+               z = Math.round(z * 100) / 100;
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       _zoomFF36: function() {
+               // the hack for FF3.6: you can measure scrollbar's width in CSS pixels,
+               // while in system pixels it's 15px (verified in Ubuntu).
+
+               // TODO: verify for every platform that a scrollbar is exactly 15px wide.
+               var container = document.createElement('div')
+                               , outerDiv = document.createElement('div');
+               // The container exists so that the div will be laid out in its own flow
+               // while not impacting the layout, viewport size, or display of the
+               // webpage as a whole.
+               container.setAttribute('style', 'width:0; height:0; overflow:hidden;' +
+                               'visibility:hidden; position: absolute');
+               outerDiv.style.width = outerDiv.style.height = '500px'; // enough for all the scrollbars
+               var div = outerDiv;
+               for (var i = 0; i < 10; ++i) {
+                       var child = document.createElement('div');
+                       child.style.overflowY = 'scroll';
+                       div.appendChild(child);
+                       div = child;
+               }
+               container.appendChild(outerDiv);
+               document.body.appendChild(container);
+               var outerDivWidth = outerDiv.clientWidth;
+               var innerDivWidth = div.clientWidth;
+               var scrollbarWidthCss = (outerDivWidth - innerDivWidth) / 10;
+               document.body.removeChild(container);
+               var scrollbarWidthDevice = 15; // Mac and Linux: scrollbars are 15px wide
+               if (-1 != navigator.platform.indexOf('Win')) {
+                       scrollbarWidthDevice = 17;
+               }
+               var z = scrollbarWidthDevice / scrollbarWidthCss;
+               z = Math.round(z * 100) / 100;
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       _zoomFF4: function() {
+               // no real trick; device-pixel-ratio is the ratio of device dpi / css dpi.
+               // (Note that this is a different interpretation than Webkit's device
+               // pixel ratio, which is the ratio device dpi / system dpi).
+               // TODO: is mozmm vs. mm promising?
+               var z = this.mediaQueryBinarySearch(
+                               'min--moz-device-pixel-ratio',
+                               '', 0, 10, 20, .0001);
+               z = Math.round(z * 100) / 100;
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       _zoomOperaOlder: function() {
+               // 10.00 (or before) to 11.01:
+               // the trick: a div with position:fixed;width:100%'s offsetWidth is the
+               // viewport width in CSS pixels, while window.innerWidth was in system
+               // pixels. Thanks to:
+               // http://virtuelvis.com/2005/05/how-to-detect-zoom-level-in-opera/
+               // TODO: fix bug: when there is a scrollbar, fixed div does NOT
+               // include the scrollbar, while window.outerWidth DOES. This causes the
+               // calculation to be off by a few percent.
+               var fixedDiv = document.createElement('div');
+               fixedDiv.style.position = 'fixed';
+               fixedDiv.style.width = '100%';
+               fixedDiv.style.height = '100%';
+               fixedDiv.style.top = fixedDiv.style.left = '0';
+               fixedDiv.style.visibility = 'hidden';
+               document.body.appendChild(fixedDiv);
+               var z = window.innerWidth / fixedDiv.offsetWidth;
+               document.body.removeChild(fixedDiv);
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       _zoomOpera11: function() {
+               // works starting Opera 11.11
+               // the trick: outerWidth is the viewport width including scrollbars in
+               // system px, while innerWidth is the viewport width including scrollbars
+               // in CSS px;
+               var z = window.outerWidth / window.innerWidth;
+               z = Math.round(z * 100) / 100;
+               return {zoom: z, devicePxPerCssPx: z};
+       },
+       ratios: function() {
+               var r;
+               if (Modernizr.ftouch) {
+                       return this._zoomWebkitMobile();
+               } else if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
+                       return this._zoomIe8();
+               } else if ('ontouchstart' in window && document.body.style.webkitTextSizeAdjust != null) {
+                       return this._zoomWebkitMobile();
+               } else if (document.body.style.webkitTextSizeAdjust != null) { // webkit
+                       return this._zoomWebkit();
+               } else if (-1 != navigator.userAgent.indexOf('Firefox/3.5')) {
+                       return this._zoomFF35();
+               } else if (-1 != navigator.userAgent.indexOf('Firefox/3.6')) {
+                       return this._zoomFF36();
+               } else if (-1 != navigator.appVersion.indexOf("MSIE 7.")) {
+                       return this._zoomIe7();
+               } else if (-1 != navigator.userAgent.indexOf('Opera')) {
+                       var versionIdx = navigator.userAgent.indexOf('Version/');
+                       if (11.01 < parseFloat(navigator.userAgent.substr(versionIdx + 8)))
+                               return this._zoomOpera11();
+                       else
+                               return this._zoomOperaOlder();
+               } else if (0.001 < (r = this._zoomFF4()).zoom) {
+                       return r;
+               } else {
+                       return {zoom: 1, devicePxPerCssPx: 1}
+               }
+       },
+       zoom: function() {
+               return this.ratios().zoom;
+       },
+       device: function() {
+               return this.ratios().devicePxPerCssPx;
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fix/ios-orientation.js b/js/libs/fix/ios-orientation.js
new file mode 100644 (file)
index 0000000..1d5bd27
--- /dev/null
@@ -0,0 +1,56 @@
+(function(w) {
+
+       // This fix addresses an iOS bug, so return early if the UA claims it's something else.
+       var ua = navigator.userAgent;
+       if (!(/iPhone|iPad|iPod/.test(navigator.platform))) {
+               //return;
+       }
+
+       var doc = w.document;
+
+       if (!doc.querySelector) {
+               return;
+       }
+
+       var meta = doc.querySelector("meta[name=viewport]"),
+                       initialContent = meta && meta.getAttribute("content"),
+                       disabledZoom = initialContent + ",maximum-scale=1",
+                       enabledZoom = initialContent + ",maximum-scale=1",
+                       enabled = true,
+                       x, y, z, aig;
+
+       if (!meta) {
+               return;
+       }
+
+       function restoreZoom() {
+               meta.setAttribute("content", enabledZoom);
+               enabled = true;
+       }
+
+       function disableZoom() {
+               meta.setAttribute("content", disabledZoom);
+               enabled = false;
+       }
+
+       function checkTilt(e) {
+               aig = e.accelerationIncludingGravity;
+               x = Math.abs(aig.x);
+               y = Math.abs(aig.y);
+               z = Math.abs(aig.z);
+
+               // If portrait orientation and in one of the danger zones
+               if ((!w.orientation || w.orientation === 180) && (x > 7 || ((z > 6 && y < 8 || z < 8 && y > 6) && x > 5))) {
+                       if (enabled) {
+                               disableZoom();
+                       }
+               }
+               else if (!enabled) {
+                       restoreZoom();
+               }
+       }
+
+       w.addEventListener("orientationchange", restoreZoom, false);
+       w.addEventListener("devicemotion", checkTilt, false);
+
+})(this);
\ No newline at end of file
diff --git a/js/libs/flashdetect.js b/js/libs/flashdetect.js
new file mode 100644 (file)
index 0000000..689a6e3
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+Copyright (c) Copyright (c) 2007, Carl S. Yestrau All rights reserved.
+Code licensed under the BSD License: http://www.featureblend.com/license.txt
+Version: 1.0.4
+*/
+var FlashDetect = new function(){
+    var self = this;
+    self.installed = false;
+    self.raw = "";
+    self.major = -1;
+    self.minor = -1;
+    self.revision = -1;
+    self.revisionStr = "";
+    var activeXDetectRules = [
+        {
+            "name":"ShockwaveFlash.ShockwaveFlash.7",
+            "version":function(obj){
+                return getActiveXVersion(obj);
+            }
+        },
+        {
+            "name":"ShockwaveFlash.ShockwaveFlash.6",
+            "version":function(obj){
+                var version = "6,0,21";
+                try{
+                    obj.AllowScriptAccess = "always";
+                    version = getActiveXVersion(obj);
+                }catch(err){}
+                return version;
+            }
+        },
+        {
+            "name":"ShockwaveFlash.ShockwaveFlash",
+            "version":function(obj){
+                return getActiveXVersion(obj);
+            }
+        }
+    ];
+    /**
+     * Extract the ActiveX version of the plugin.
+     * 
+     * @param {Object} The flash ActiveX object.
+     * @type String
+     */
+    var getActiveXVersion = function(activeXObj){
+        var version = -1;
+        try{
+            version = activeXObj.GetVariable("$version");
+        }catch(err){}
+        return version;
+    };
+    /**
+     * Try and retrieve an ActiveX object having a specified name.
+     * 
+     * @param {String} name The ActiveX object name lookup.
+     * @return One of ActiveX object or a simple object having an attribute of activeXError with a value of true.
+     * @type Object
+     */
+    var getActiveXObject = function(name){
+        var obj = -1;
+        try{
+            obj = new ActiveXObject(name);
+        }catch(err){
+            obj = {activeXError:true};
+        }
+        return obj;
+    };
+    /**
+     * Parse an ActiveX $version string into an object.
+     * 
+     * @param {String} str The ActiveX Object GetVariable($version) return value. 
+     * @return An object having raw, major, minor, revision and revisionStr attributes.
+     * @type Object
+     */
+    var parseActiveXVersion = function(str){
+        var versionArray = str.split(",");//replace with regex
+        return {
+            "raw":str,
+            "major":parseInt(versionArray[0].split(" ")[1], 10),
+            "minor":parseInt(versionArray[1], 10),
+            "revision":parseInt(versionArray[2], 10),
+            "revisionStr":versionArray[2]
+        };
+    };
+    /**
+     * Parse a standard enabledPlugin.description into an object.
+     * 
+     * @param {String} str The enabledPlugin.description value.
+     * @return An object having raw, major, minor, revision and revisionStr attributes.
+     * @type Object
+     */
+    var parseStandardVersion = function(str){
+        var descParts = str.split(/ +/);
+        var majorMinor = descParts[2].split(/\./);
+        var revisionStr = descParts[3];
+        return {
+            "raw":str,
+            "major":parseInt(majorMinor[0], 10),
+            "minor":parseInt(majorMinor[1], 10), 
+            "revisionStr":revisionStr,
+            "revision":parseRevisionStrToInt(revisionStr)
+        };
+    };
+    /**
+     * Parse the plugin revision string into an integer.
+     * 
+     * @param {String} The revision in string format.
+     * @type Number
+     */
+    var parseRevisionStrToInt = function(str){
+        return parseInt(str.replace(/[a-zA-Z]/g, ""), 10) || self.revision;
+    };
+    /**
+     * Is the major version greater than or equal to a specified version.
+     * 
+     * @param {Number} version The minimum required major version.
+     * @type Boolean
+     */
+    self.majorAtLeast = function(version){
+        return self.major >= version;
+    };
+    /**
+     * Is the minor version greater than or equal to a specified version.
+     * 
+     * @param {Number} version The minimum required minor version.
+     * @type Boolean
+     */
+    self.minorAtLeast = function(version){
+        return self.minor >= version;
+    };
+    /**
+     * Is the revision version greater than or equal to a specified version.
+     * 
+     * @param {Number} version The minimum required revision version.
+     * @type Boolean
+     */
+    self.revisionAtLeast = function(version){
+        return self.revision >= version;
+    };
+    /**
+     * Is the version greater than or equal to a specified major, minor and revision.
+     * 
+     * @param {Number} major The minimum required major version.
+     * @param {Number} (Optional) minor The minimum required minor version.
+     * @param {Number} (Optional) revision The minimum required revision version.
+     * @type Boolean
+     */
+    self.versionAtLeast = function(major){
+        var properties = [self.major, self.minor, self.revision];
+        var len = Math.min(properties.length, arguments.length);
+        for(i=0; i<len; i++){
+            if(properties[i]>=arguments[i]){
+                if(i+1<len && properties[i]==arguments[i]){
+                    continue;
+                }else{
+                    return true;
+                }
+            }else{
+                return false;
+            }
+        }
+    };
+    /**
+     * Constructor, sets raw, major, minor, revisionStr, revision and installed public properties.
+     */
+    self.FlashDetect = function(){
+        if(navigator.plugins && navigator.plugins.length>0){
+            var type = 'application/x-shockwave-flash';
+            var mimeTypes = navigator.mimeTypes;
+            if(mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description){
+                var version = mimeTypes[type].enabledPlugin.description;
+                var versionObj = parseStandardVersion(version);
+                self.raw = versionObj.raw;
+                self.major = versionObj.major;
+                self.minor = versionObj.minor; 
+                self.revisionStr = versionObj.revisionStr;
+                self.revision = versionObj.revision;
+                self.installed = true;
+            }
+        }else if(navigator.appVersion.indexOf("Mac")==-1 && window.execScript){
+            var version = -1;
+            for(var i=0; i<activeXDetectRules.length && version==-1; i++){
+                var obj = getActiveXObject(activeXDetectRules[i].name);
+                if(!obj.activeXError){
+                    self.installed = true;
+                    version = activeXDetectRules[i].version(obj);
+                    if(version!=-1){
+                        var versionObj = parseActiveXVersion(version);
+                        self.raw = versionObj.raw;
+                        self.major = versionObj.major;
+                        self.minor = versionObj.minor; 
+                        self.revision = versionObj.revision;
+                        self.revisionStr = versionObj.revisionStr;
+                    }
+                }
+            }
+        }
+    }();
+};
+FlashDetect.JS_RELEASE = "1.0.4";
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.background.js b/js/libs/fluidbook/fluidbook.background.js
new file mode 100644 (file)
index 0000000..c640c00
--- /dev/null
@@ -0,0 +1,58 @@
+function FluidbookBackground(fluidbook) {\r
+       this.fluidbook = fluidbook;\r
+       this.hasLinks = false;\r
+       this.init();\r
+}\r
+\r
+FluidbookBackground.prototype = {\r
+       init: function() {\r
+               $("#main").append('<div id="background"></div>');\r
+               \r
+               fb([Fluidbook.REPEAT,Fluidbook.STRETCH]);\r
+               \r
+               \r
+               if (this.fluidbook.datas.links.background != undefined\r
+                               && this.fluidbook.datas.repeat != Fluidbook.REPEAT\r
+                               && this.fluidbook.datas.repeat != Fluidbook.STRETCH\r
+                               && this.fluidbook.datas.links.background != '') {\r
+                       $("#background").prepend('<div class="links">' + this.fluidbook.datas.links.background + '</div>');\r
+                       hasLinks = true;\r
+               }\r
+       },\r
+       resize: function(w, h) {\r
+               if (!this.hasLinks) {\r
+                       return;\r
+               }\r
+\r
+               var left, top, iw, ih;\r
+               if (this.fluidbook.datas.repeat == Fluidbook.NONE) {\r
+                       iw = this.fluidbook.datas.backgroundImageDimensions.width;\r
+                       ih = this.fluidbook.datas.backgroundImageDimensions.height;\r
+               }\r
+\r
+\r
+\r
+               if (this.fluidbook.datas.backgroundHAlign == Fluidbook.LEFT) {\r
+                       left = 0\r
+               } else if (this.fluidbook.datas.backgroundHAlign == Fluidbook.RIGHT) {\r
+                       left = w - iw;\r
+               } else if (this.fluidbook.datas.backgroundHAlign == Fluidbook.CENTER) {\r
+                       left = (w - iw) / 2;\r
+               }\r
+\r
+\r
+               if (this.fluidbook.datas.backgroundVAlign == Fluidbook.TOP) {\r
+                       top = 0\r
+               } else if (this.fluidbook.datas.backgroundVAlign == Fluidbook.BOTTOM) {\r
+                       top = h - ih;\r
+               } else if (this.fluidbook.datas.backgroundVAlign == Fluidbook.MIDDLE) {\r
+                       top = (h - ih) / 2;\r
+               }\r
+               \r
+               $("#background .links").css({\r
+                       top: top,\r
+                       left: left\r
+               });\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.bookmarks.js b/js/libs/fluidbook/fluidbook.bookmarks.js
new file mode 100644 (file)
index 0000000..dc35c8e
--- /dev/null
@@ -0,0 +1,440 @@
+function FluidbookBookmarks(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.enabled = false;
+       this.bookmarks = [];
+
+       this._pagesToGroup = [];
+       this._groupNames = [];
+       this._groups = 0;
+       this._groupOrder = [];
+
+       this._cornersIndex = [];
+       this._cornersPages = [];
+
+       this.enabled = this.fluidbook.datas.bookmark;
+       this.init();
+}
+
+FluidbookBookmarks.prototype = {
+       init: function() {
+               var $this = this;
+               $(document).on('click', '.bookmark', function() {
+                       $this.toggleBookmark(parseInt($(this).attr('data-page')));
+                       return false;
+               });
+
+               $(document).on('click', '.bookmarkssub a.send', function() {
+                       var subject = '%title%';
+                       if ($this.fluidbook.datas.bookmark_email_title != '') {
+                               subject = $this.fluidbook.datas.bookmark_email_title;
+                       }
+
+
+                       var body = $this.fluidbook.l10n.__('Please see the attached files from "%title%".');
+                       if ($this.fluidbook.datas.bookmark_email_body != '') {
+                               body = $this.fluidbook.datas.bookmark_email_body;
+                       }
+
+                       subject = subject.replace(/\%title\%/gi, $this.fluidbook.datas.title);
+                       body = trim(body.replace(/\%title\%/gi, $this.fluidbook.datas.title), ' .');
+                       body += " : " + $this.getPDF();
+
+                       $this.fluidbook.intentShare(subject, body);
+                       return false;
+               });
+
+               $(document).on('click', '.bookmarkssub a.print', function() {
+                       $this.fluidbook._openFile($this.getPDF(), $(this), 'pdf', $this.getBookmarksCompacted() + '.pdf');
+                       return false;
+               });
+
+               for (var g in this.fluidbook.datas.bookmarkGroups) {
+
+                       var group = this.fluidbook.datas.bookmarkGroups[g];
+                       this.addGroup(group.page, group.nb, group.name);
+               }
+               this.completeGroups();
+               this._groupOrder.sort($.proxy(this.sortGroup, this));
+
+               this.bookmarks = this.getSavedBookmarks();
+               for (var i in this.bookmarks) {
+                       this.addBookmark(this.bookmarks[i], true);
+               }
+       },
+       sortGroup: function(a, b) {
+               var p_a = this.getPagesOfGroup(a)[0];
+               var p_b = this.getPagesOfGroup(b)[0];
+               return p_a - p_b;
+       },
+       sortnumeric: function(a, b) {
+               return a - b;
+       },
+       getPDF: function() {
+               return  'http://workshop.fluidbook.com/s/e/' + this.fluidbook.datas.cid + '/' + this.getBookmarksCompacted();
+       },
+       getBookmarksCompacted: function() {
+               this.bookmarks.sort(this.sortnumeric);
+
+               var g = [];
+               var rs = 0;
+               var re = 0;
+               for (var i = 0; i < this.bookmarks.length; i++) {
+                       var b = this.bookmarks[i];
+                       if (rs == 0) {
+                               rs = re = b;
+                               continue;
+                       }
+                       if (re + 1 == b) {
+                               re = b;
+                               continue;
+                       }
+                       if (rs == re) {
+                               g.push('' + rs);
+                       } else {
+                               g.push(rs + '-' + re);
+                       }
+
+                       rs = re = b;
+               }
+
+               if (rs != 0) {
+                       if (rs == re) {
+                               g.push('' + rs);
+                       } else {
+                               g.push(rs + '-' + re);
+                       }
+               }
+
+               return g.join(',');
+       },
+       addGroup: function(from, nb, name) {
+               var to = Math.min(from + (nb - 1), this.fluidbook.datas.pages);
+               for (var i = from; i <= to; i++)
+               {
+                       this._pagesToGroup[i] = this._groups;
+               }
+               this._groupNames[this._groups] = name;
+               this._groupOrder.push(this._groups);
+               this._groups++;
+       },
+       completeGroups: function() {
+               for (var i = 1; i <= this.fluidbook.datas.pages; i++) {
+                       if (this._pagesToGroup[i] == undefined || this._pagesToGroup[i] == null) {
+                               this._pagesToGroup[i] = this._groups;
+                               this._groupOrder.push(this._groups);
+                               this._groups++;
+                       }
+               }
+       },
+       getPreviousGroup: function(group) {
+               var o = this.getOrderGroup(group);
+               if (o == -1) {
+                       return false;
+               }
+               o--;
+               return this._groupOrder[o];
+       },
+       getNextGroup: function(group) {
+               var o = this.getOrderGroup(group);
+               if (o == -1) {
+                       return false;
+               }
+               o++;
+               return this._groupOrder[o];
+       },
+       getOrderGroup: function(group) {
+               return this._groupOrder.indexOf(group);
+       },
+       getGroupName: function(groupId)
+       {
+               var res = '';
+               if (this._groupNames[groupId] != undefined) {
+                       res = this._groupNames[groupId];
+               }
+               if (res == '') {
+                       var pages = this.getPagesOfGroup(groupId);
+                       res = this.fluidbook.physicalToVirtual(pages[0]);
+                       if (pages.length == 1) {
+                               return res;
+                       }
+                       res += " - " + this.fluidbook.physicalToVirtual(pages[pages.length - 1]);
+               }
+               return res;
+       },
+       getPagesOfGroup: function(groupId)
+       {
+               var res = [];
+               for (var i = 1; i <= this.fluidbook.datas.pages; i++) {
+                       if (this._pagesToGroup[i] == groupId) {
+                               res.push(i);
+                       }
+               }
+               return res;
+       },
+       getPagesNumberInGroup: function(groupId) {
+               return this.getPagesOfGroup(groupId).length;
+       },
+       getBookmarkedGroups: function(onlyBookmarked)
+       {
+               if (onlyBookmarked == undefined) {
+                       onlyBookmarked = true;
+               }
+
+               var res = [];
+               var nb;
+               var groupId;
+               for (var i = 1; i <= this.fluidbook.datas.pages; ) {
+                       if (this.isBookmarked(i) || !onlyBookmarked) {
+                               groupId = this.getGroupOfPage(i);
+                               nb = this.getPagesNumberInGroup(groupId);
+                               res.push({page: i, nb: nb, name: this.getGroupName(groupId)});
+                               i += nb;
+                               continue;
+                       }
+                       i++;
+               }
+               return res;
+       },
+       getOrderedGroups: function() {
+               return this.getBookmarkedGroups(false);
+       },
+       getGroupOfPage: function(page) {
+               return this._pagesToGroup[page];
+       },
+       getNextPageInGroupOfPage: function(page) {
+               var group = this.getLinkedPages(page);
+               var index = group.indexOf(page);
+               if (index == group.length - 1) {
+                       return false;
+               }
+               return group[index + 1];
+       },
+       getPreviousPageInGroupOfPage: function(page) {
+               var group = this.getLinkedPages(page);
+               var index = group.indexOf(page);
+               if (index == 0) {
+                       return false;
+               }
+               return group[index - 1];
+       },
+       getNextGroupCover: function(page) {
+               var group = this.getGroupOfPage(page);
+               group = this.getNextGroup(group);
+               if (group === false) {
+                       return false;
+               }
+               return this.getCoverOfGroup(group);
+       },
+       getPreviousGroupCover: function(page) {
+               var group = this.getGroupOfPage(page);
+               group = this.getPreviousGroup(group);
+               if (group === false) {
+                       return false;
+               }
+               return this.getCoverOfGroup(group);
+       },
+       getCoverOfGroup: function(group) {
+               var pages = this.getPagesOfGroup(group);
+               if (pages.length) {
+                       return pages[0];
+               }
+               return false;
+       },
+       hasNextPageInGroup: function(page) {
+               var group = this.getGroupOfPage(page);
+               var pages = this.getPagesOfGroup(group);
+               var i = pages.indexOf(page);
+               if (i == pages.length - 1) {
+                       return false;
+               }
+               return true;
+       },
+       getLinkedPages: function(page) {
+               var group = this.getGroupOfPage(page);
+               if (group == -1 || isNaN(group)) {
+                       return [];
+               }
+               return this.getPagesOfGroup(group);
+       },
+       addBookmark: function(page, cornersOnly)
+       {
+               if (cornersOnly == undefined) {
+                       cornersOnly = false;
+               }
+               var pages = this.getLinkedPages(page);
+               for (i in pages)
+               {
+                       var page = pages[i];
+                       if (!cornersOnly) {
+                               this.bookmarks.push(page);
+                       }
+               }
+               if (!cornersOnly) {
+                       this.updateBookmarks();
+                       // TODO add stats call
+               }
+       },
+       setCornersEnabled: function(page, enabled) {
+               var bookmarks = $('.bookmark[data-page="' + page + '"]');
+               if (enabled) {
+                       $(bookmarks).attr('data-enabled', 'enabled');
+               } else {
+                       $(bookmarks).attr('data-enabled', null);
+               }
+       },
+       disableCorners: function() {
+               $(".bookmark").attr('data-enabled', null);
+       },
+       toggleBookmark: function(page) {
+
+               var pages = this.getLinkedPages(page);
+               var add = false;
+               for (var i in pages) {
+                       var p = pages[i];
+                       if (this.bookmarks.indexOf(p) > -1) {
+                               add = true;
+                               break;
+                       }
+               }
+               if (add) {
+                       this.removeBookmark(page);
+               } else {
+                       this.addBookmark(page);
+               }
+       },
+       removeBookmark: function(page) {
+               var pages = this.getLinkedPages(page);
+               for (var i in pages) {
+                       this.bookmarks = arrayRemove(this.bookmarks, pages[i]);
+               }
+               this.updateBookmarks();
+       },
+       updateBookmarks: function() {
+               this.saveBookmarks();
+               var $this = this;
+
+               this.disableCorners();
+               $.each(this.bookmarks, function(k, v) {
+                       $this.setCornersEnabled(v, true);
+               });
+       },
+       saveBookmarks: function() {
+               this.fluidbook.cache.set('bookmarks', this.bookmarks);
+       },
+       getSavedBookmarks: function() {
+               if (this.fluidbook.cache.isset('bookmarks')) {
+                       return this.fluidbook.cache.get('bookmarks');
+               }
+               return [];
+       },
+       isBookmarked: function(page) {
+               return this.bookmarks.indexOf(page) > -1;
+       },
+       getBookmarkForPage: function(pageNr, onlyOne, allwaysAtRight) {
+               if (onlyOne == undefined) {
+                       onlyOne = false;
+               }
+               if (allwaysAtRight == undefined) {
+                       allwaysAtRight = false;
+               }
+
+               var to = pageNr;
+               if (!onlyOne) {
+                       to++;
+               }
+
+               var bookmarks = "";
+               for (var i = pageNr; i <= to; i++) {
+                       if (i > 0 && i <= this.fluidbook.datas.pages) {
+                               var side;
+                               if (allwaysAtRight) {
+                                       side = 'right';
+                               } else {
+                                       side = (i % 2 == 0) ? 'left' : 'right';
+                               }
+
+                               bookmarks += "<a href=\"#\" class=\"bookmark " + side + "\" data-page=\"" + i + "\"";
+                               if (this.isBookmarked(i)) {
+                                       bookmarks += " data-enabled=\"enabled\"";
+                               }
+                               bookmarks += '></a>';
+                       }
+               }
+               return bookmarks;
+       },
+       getView: function() {
+               var c = this.getIndex(false);
+               if (c === false) {
+                       return c;
+               }
+               var index = '<div class="bookmarkssub"><div class="caption"><a href="#" class="back miniOnPortrait"><span class="hideOnPortrait">' + this.fluidbook.l10n.__('back') + '</span></a><h2>' + this.fluidbook.l10n.__('bookmarks') + '</h2>';
+               index += '<div class="fonctions">';
+               if (this.fluidbook.datas.friend) {
+                       index += '<a class="send miniOnPortrait" href="#"><span class="hideOnPortrait">' + this.fluidbook.l10n.__('send') + '</span></a>';
+
+               }
+               if (this.fluidbook.datas.print || this.fluidbook.datas.pdf) {
+                       index += '<a class="print miniOnPortrait" href="#"><span class="hideOnPortrait">' + this.fluidbook.l10n.__('download') + '</span></a>';
+               }
+               index += '</div>';
+               index += '</div>';
+               index += '' + c + '</div>';
+               return index;
+       },
+       getIndex: function(all, onlyGroup) {
+               if (all == undefined) {
+                       all = false;
+               }
+               var groups;
+
+               if (all == false) {
+                       groups = this.getBookmarkedGroups();
+               } else {
+                       groups = this.getOrderedGroups();
+               }
+
+               if (groups.length == 0) {
+                       return false;
+               }
+
+               var index = '<div class="content"><div id="indexView" class="bookmarkView">';
+
+               if (onlyGroup == undefined) {
+                       for (var g = 0; g < groups.length; g++) {
+                               var group = groups[g];
+                               var pages = [];
+                               for (var i = 0; i < group.nb; i++) {
+                                       pages.push(group.page + i);
+                               }
+
+                               index += '<div class="doubleThumb simple left" page="' + group.page + '" data-pages="' + pages.join(',') + '">';
+                               index += '<div class="thumb left"><a href="#/page/' + group.page + '"><img src="data/thumbnails/p' + group.page + '.jpg" /></a><span class="number">' + group.name + '</span>';
+                               if (this.fluidbook.bookmarks.enabled) {
+                                       index += this.fluidbook.bookmarks.getBookmarkForPage(group.page, true, true);
+                               }
+                               index += '</div>';
+                               index += '</div>';
+                       }
+               } else {
+                       var group = groups[this.getGroupOfPage(onlyGroup)];
+
+                       var pages = [];
+                       for (var i = 0; i < group.nb; i++) {
+                               pages.push(group.page + i);
+                       }
+
+                       for (i in pages) {
+                               var p = pages[i];
+                               index += '<div class="doubleThumb simple left" page="' + p + '" data-pages="' + p + '">';
+                               index += '<div class="thumb left"><a href="#/page/' + p + '"><img src="data/thumbnails/p' + p + '.jpg" /></a><span class="number">' + this.fluidbook.physicalToVirtual(p) + '</span>';
+                               if (this.fluidbook.bookmarks.enabled) {
+                                       index += this.fluidbook.bookmarks.getBookmarkForPage(p, true, true);
+                               }
+                               index += '</div>';
+                               index += '</div>';
+                       }
+               }
+               index += '</div></div>';
+               return index;
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.cache.js b/js/libs/fluidbook/fluidbook.cache.js
new file mode 100644 (file)
index 0000000..52c2de1
--- /dev/null
@@ -0,0 +1,62 @@
+function FluidbookCache(options) {
+       this._cache = {};
+       this.options = options;
+       this._prefix ='fluidbook.' + this.options.id + '.';
+       this._support = false;
+       this._date = this.options.cacheDate;
+       this._support=Modernizr.localstorage;
+       this.init();
+
+}
+
+FluidbookCache.prototype = {
+       init: function() {
+               if (this._support) {
+                       this.checkValidity();
+               }
+       },
+       clear: function() {
+               if (this._support) {
+                       localStorage.clear();
+               } else {
+                       this._cache = {};
+               }
+       },
+       isset: function(key) {
+               if (this._support) {
+                       var res= localStorage.getItem(this._prefix + key) != null;
+                       return res;
+               } else {
+                       return this._cache[key] != null;
+               }
+       },
+       get: function(key) {
+               var res;
+               if (this._support) {
+                       res = localStorage.getItem(this._prefix + key);
+               } else {
+                       res = this._cache[key];
+               }
+               var f = res.substr(0, 1);
+               if (f == '[' || f == '{') {
+                       res = JSON.parse(res);
+               }
+               return res;
+       },
+       set: function(key, value) {
+               if (typeof value !== "string") {
+                       value = JSON.stringify(value);
+               }
+               if (this._support) {
+                       localStorage.setItem(this._prefix + key, value);
+               } else {
+                       this._cache[key] = value;
+               }
+       },
+       checkValidity: function() {
+               if (!this.isset('validity') || this.get('validity') != this._date) {
+                       this.clear();
+                       this.set('validity', this._date);
+               }
+       }
+}
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.coquillette.js b/js/libs/fluidbook/fluidbook.coquillette.js
new file mode 100644 (file)
index 0000000..12b19d9
--- /dev/null
@@ -0,0 +1,65 @@
+function FluidbookCoquillette(fluidbook) {\r
+       this.fluidbook = fluidbook;\r
+       this.size = 60;\r
+       this.element = $("#coquillette");\r
+       this.rotation = 0;\r
+       this.speed = 1; // 1/2 tours / sec\r
+       this.deg360 = Math.PI * 2;\r
+       this.init();\r
+       this.raf;\r
+       this.start;\r
+}\r
+\r
+FluidbookCoquillette.prototype = {\r
+       init: function() {\r
+               var $this = this;\r
+               this.element.append('<canvas width="' + this.size + '" height="' + this.size + '"></canvas>');\r
+               var canvas = this.element.find('canvas').get(0);\r
+               this.ctx = canvas.getContext('2d');\r
+       },\r
+       show: function() {\r
+               this.element.show();\r
+               this.resume();\r
+       },\r
+       hide: function() {\r
+               this.element.hide();\r
+               this.pause();\r
+       },\r
+       resume: function() {\r
+               var $this = this;\r
+               this.rotation = 0;\r
+               TweenMax.to(this, 1 / this.speed, {rotation: this.deg360, repeat: -1, ease: Linear.easeNone, onUpdate: $.proxy(this.step, this)});\r
+       },\r
+       step: function() {\r
+               var radius = this.size / 2;\r
+\r
+               // Clear the whole canvas\r
+               this.ctx.clearRect(0, 0, this.size, this.size);\r
+               // Set the background\r
+               this.ctx.fillStyle = this.fluidbook.datas.coquilletteBack;\r
+               this.ctx.beginPath();\r
+               this.ctx.arc(radius, radius, radius, 0, this.deg360, false);\r
+               this.ctx.closePath();\r
+               this.ctx.fill();\r
+               // Set stroke style\r
+               this.ctx.strokeStyle = this.fluidbook.datas.coquilletteFront;\r
+               this.ctx.lineWidth = Math.round(this.size * 0.13);\r
+               this.ctx.lineCap = 'round';\r
+               this.ctx.lineJoin = 'mitter';\r
+               this.ctx.beginPath();\r
+               this.ctx.arc(radius, radius, radius * 0.65, this.rotation, this.rotation + Math.PI * 1.4, false);\r
+\r
+               // Apply the stroke\r
+               this.ctx.stroke();\r
+       },\r
+       pause: function() {\r
+               window.cancelAnimationFrame(this.raf);\r
+       },\r
+       resize: function(ww, hh) {\r
+               this.element.css({\r
+                       left: (ww - this.size) / 2,\r
+                       top: (hh - this.size) / 2\r
+               })\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.desktop.js b/js/libs/fluidbook/fluidbook.desktop.js
new file mode 100644 (file)
index 0000000..6ba6aaf
--- /dev/null
@@ -0,0 +1,113 @@
+function FluidbookDesktop(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.updateDesktopScale(1);
+       this.origin = ['50%', '50%'];
+       this.init();
+}
+
+FluidbookDesktop.prototype = {
+       init: function() {
+               var $this = this;
+               $(document).on('click', '#links', function(e) {
+                       $this.clickZoom(e);
+               });
+               $(document).on('click', '#links .link', function(e) {
+                       e.stopPropagation();
+               })
+
+               $("body").mousewheel(function(e, delta, deltaX, deltaY) {
+                       $this.wheelZoom(deltaY);
+               })
+
+               $(document).on('mousemove', 'body', function(e) {
+                       $this.moveZoom(e);
+               });
+       },
+       moveZoom: function(e) {
+               var x = 100 * e.pageX / $(window).width();
+               var y = 100 * e.pageY / $(window).height();
+               this.origin = [x + '%', y + '%'];
+               if (this.desktopScale == 1) {
+                       return;
+               } else {
+
+                       $("#fluidbook").transform({
+                               origin: this.origin
+                       }, {
+                               preserve: true
+                       })
+               }
+       },
+       clickZoom: function(e) {
+               var newScale;
+               if (this.desktopScale == 1) {
+                       newScale = (this.fluidbook.datas.zoom / 100) / this.fluidbook.resize.bookScale;
+               } else {
+                       newScale = 1;
+               }
+               this.updateDesktopScale(newScale);
+               return false;
+       },
+       wheelZoom: function(delta) {
+               if ($("body").hasClass('view')) {
+                       return;
+               }
+               this.updateDesktopScale(this.desktopScale + delta / 3, delta > 0);
+       },
+       updateDesktopScale: function(v, zoomIn) {
+               var $this = this;
+               if (this.fluidbook.viewMode()) {
+                       v = 1;
+               }
+
+               var max = (this.fluidbook.datas.zoomw / 100) / this.fluidbook.resize.bookScale;
+
+               v = Math.max(Math.min(v, max), 1);
+
+               if (zoomIn === true) {
+                       if (v < 1.5) {
+                               v = 2;
+                       }
+               } else if (zoomIn === false) {
+                       if (v < 1.5) {
+                               v = 1;
+                       }
+               }
+
+
+               if (v == this.desktopScale) {
+                       return false;
+               }
+               this.desktopScale = v;
+
+
+               var animation = {
+                       scale: [this.desktopScale * this.fluidbook.resize.bookScale, this.desktopScale * this.fluidbook.resize.bookScale]
+               };
+               if (this.desktopScale == 1) {
+                       animation.origin = ['50%', '50%'];
+               } else {
+                       animation.origin = this.origin;
+               }
+
+               if (this.desktopScale != 1) {
+                       $("header,footer,#interface").addClass('hidden');
+
+               } else {
+                       $("header,footer,#interface").removeClass('hidden');
+               }
+               $("#fluidbook").addClass('animate').transform(animation);
+               setTimeout(function() {
+                       $("#fluidbook").removeClass('animate');
+               }, 1000);
+
+               if (this.desktopScale > 1) {
+                       $("body").addClass('zoomed');
+               } else {
+                       $("body").removeClass('zoomed');
+               }
+
+               return true;
+       }
+
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.help.js b/js/libs/fluidbook/fluidbook.help.js
new file mode 100644 (file)
index 0000000..21db77e
--- /dev/null
@@ -0,0 +1,235 @@
+function FluidbookHelp(fluidbook) {\r
+       this.autoTimeout;\r
+       this.fluidbook = fluidbook;\r
+       this.view = $("#helpView");\r
+       this.initEvents();\r
+       this.interfaceTop;\r
+}\r
+\r
+FluidbookHelp.prototype = {\r
+       init: function() {\r
+               var $this = this;\r
+               var help = '';\r
+\r
+               // Image centrale\r
+               var ext = '';\r
+               if (this.fluidbook.support.SVG) {\r
+                       ext = 'svg';\r
+               } else {\r
+                       ext = 'png';\r
+               }\r
+\r
+               var name = '';\r
+               var width = 100;\r
+               var height = 200;\r
+               var text;\r
+               var zoom = 1;\r
+               if (this.fluidbook.support.isMobile) {\r
+                       width = 400;\r
+                       height = 200;\r
+                       zoom = 2;\r
+                       name = 'fingers';\r
+                       text = this.fluidbook.l10n.__("tap twice or spread your fingers to zoom in");\r
+               } else {\r
+                       name = 'mouse';\r
+                       text = this.fluidbook.l10n.__('click once to zoom in, click again to zoom out') + '<br />' + this.fluidbook.l10n.__('roll the mouse wheel to zoom in/out');\r
+               }\r
+\r
+               help += '<div class="illustration"><img src="data/images/help-' + name + '.' + ext + '" width="' + (width * zoom) + '" height="' + (height * zoom) + '" />';\r
+               help += '<p>' + text + '</p>';\r
+               help += '</div>';\r
+\r
+\r
+               // Icons\r
+               help += '<div id="icons">';\r
+               var scale = $("#nav").transform('scaleX');\r
+               $("#nav").transform({\r
+                       scale: [1, 1]\r
+               }, {\r
+                       preserve: true\r
+               });\r
+               var h = 40 + ($("#nav>a").length - 1) * 25;\r
+               $("nav>a").each(function() {\r
+                       var text = $(this).attr('help');\r
+                       if (text == '') {\r
+                               return;\r
+                       }\r
+                       var offset = $(this).position();\r
+                       var left = 30 + offset.left;\r
+                       help += '<div class="icon" style="padding-top:' + h + 'px;left:' + left + 'px;">' + $this.fluidbook.l10n.__(text) + '</div>';\r
+                       h -= 25;\r
+               });\r
+               $("#nav").transform({\r
+                       scale: [scale, scale]\r
+               }, {\r
+                       preserve: true\r
+               });\r
+               help += '</div>';\r
+\r
+               // Interface\r
+\r
+               var next = this.fluidbook.l10n.__('next double page');\r
+               var previous = this.fluidbook.l10n.__('previous double page');\r
+               if (this.fluidbook.pad.enabled) {\r
+                       next = this.fluidbook.l10n.__('next chapter');\r
+                       previous = this.fluidbook.l10n.__('previous chapter');\r
+               }\r
+\r
+               help += '<div class="interface">';\r
+               help += '<div class="next">' + next + '<hr /></div>';\r
+               help += '<div class="last">' + this.fluidbook.l10n.__('last page') + '<hr /></div>';\r
+               help += '<div class="previous"><hr />' + previous + '</div>';\r
+               help += '<div class="first"><hr />' + this.fluidbook.l10n.__('frontpage') + '</div>';\r
+               help += '</div>';\r
+\r
+               if (this.fluidbook.pad.enabled) {\r
+                       help += '<div class="down">' + this.fluidbook.l10n.__('read more') + '<hr /></div>';\r
+               }\r
+\r
+               this.view.html(help);\r
+               resize();\r
+       },\r
+       initEvents: function() {\r
+               var $this = this;\r
+               if (!this.fluidbook.support.isMobile) {\r
+                       $("#help").hover(function() {\r
+                               $this.show();\r
+                       }, function() {\r
+                               $this.hide();\r
+                       }).click(function() {\r
+                               return false;\r
+                       });\r
+               } else {\r
+                       $("#help").click(function() {\r
+                               $this.toggle();\r
+                               return false;\r
+                       });\r
+               }\r
+       },\r
+       show: function(time) {\r
+               this.clearTimeout();\r
+               if (time == undefined) {\r
+                       time = 0;\r
+               }\r
+\r
+               if (this.view.is(":visible")) {\r
+                       return false;\r
+               }\r
+\r
+               if (this.view.html() == '') {\r
+                       this.init();\r
+               }\r
+\r
+               var $this = this;\r
+\r
+               this.view.show();\r
+               this.fluidbook.showAllButtons();\r
+               if (this.fluidbook.support.isMobile) {\r
+                       $(document).one('click touchend', function() {\r
+                               $this.hide();\r
+                       });\r
+               } else {\r
+                       if (time != 0) {\r
+                               this.autoTimeout = setTimeout(function() {\r
+                                       $this.hide();\r
+                               }, time * 1000);\r
+                       }\r
+               }\r
+               return false;\r
+       },\r
+       hide: function() {\r
+               this.clearTimeout();\r
+               var $this = this;\r
+               if (this.view.is(':visible')) {\r
+                       this.view.hide();\r
+                       this.fluidbook.hideUnnecessaryButtons();\r
+                       if (this.fluidbook.support.isMobile) {\r
+                               $("*").unbind('click', function() {\r
+                                       $this.hide();\r
+                               });\r
+                       }\r
+               }\r
+               return false;\r
+       },\r
+       toggle: function() {\r
+               if (this.view.is(':visible')) {\r
+                       this.hide();\r
+               } else {\r
+                       this.show();\r
+               }\r
+       },\r
+       resize: function(ww, hh, interfaceScale, navScale) {\r
+               this.hide();\r
+               var menuHeightScaled = (this.fluidbook.datas.menuHeight) * navScale\r
+               this.view.css({\r
+                       width: ww,\r
+                       minHeight: hh - menuHeightScaled,\r
+                       top: menuHeightScaled\r
+               });\r
+\r
+\r
+               this.interfaceTop = (hh - 100 * interfaceScale) / 2 + 30 * interfaceScale;\r
+               this.view.find(".interface>div").css({\r
+                       top: this.interfaceTop - menuHeightScaled\r
+               });\r
+\r
+               $("#helpView #icons").transform({\r
+                       scale: [navScale, navScale],\r
+                       origin: ['0%', '0%']\r
+               });\r
+\r
+               $("#helpView #icons").css({\r
+                       fontSize: (16 / navScale) * interfaceScale\r
+               });\r
+\r
+               $("#helpView .illustration").transform({\r
+                       scale: [interfaceScale, interfaceScale],\r
+                       origin: ['50%', '50%']\r
+               });\r
+\r
+               $("#helpView .interface").find('.last,.next,.first,.previous').transform({\r
+                       scale: [interfaceScale, interfaceScale]\r
+               })\r
+\r
+               $("#helpView .interface").find('.last').transform({\r
+                       origin: ['100%', '100%']\r
+               }, {\r
+                       preserve: true\r
+               });\r
+\r
+               $("#helpView .interface").find('.first').transform({\r
+                       origin: ['0%', '100%']\r
+               }, {\r
+                       preserve: true\r
+               });\r
+\r
+               $("#helpView .interface").find('.next').transform({\r
+                       origin: ['100%', '0%']\r
+               }, {\r
+                       preserve: true\r
+               });\r
+\r
+\r
+               $("#helpView .interface").find('.previous').transform({\r
+                       origin: ['0%', '0%']\r
+               }, {\r
+                       preserve: true\r
+               });\r
+\r
+               this.view.find('.illustration').css('margin-top', (this.view.height() - 400 * interfaceScale) / 2);\r
+       },\r
+       clearTimeout: function() {\r
+               clearTimeout(this.autoTimeout);\r
+       },\r
+       displayAtStartup: function() {\r
+               var $this = this;\r
+               if (this.fluidbook.datas.helpStartup) {\r
+\r
+                       $this.show(parseInt($this.fluidbook.datas.helpStartupTime));\r
+                       if ($this.fluidbook.pad.enabled) {\r
+                               $this.fluidbook.pad.displayInterface();\r
+                       }\r
+               }\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.js b/js/libs/fluidbook/fluidbook.js
new file mode 100644 (file)
index 0000000..4433785
--- /dev/null
@@ -0,0 +1,1305 @@
+function Fluidbook(datas) {\r
+       this.init(datas);\r
+}\r
+\r
+// Constantes\r
+// Background dispoition\r
+Fluidbook.NONE = 3;\r
+Fluidbook.STRETCH = 0;\r
+Fluidbook.RATIO = 2;\r
+Fluidbook.REPEAT = 1;\r
+// Horizontal alignments\r
+Fluidbook.CENTER = 4;\r
+Fluidbook.LEFT = 5;\r
+Fluidbook.RIGHT = 6;\r
+// Vertical alignments\r
+Fluidbook.MIDDLE = 7;\r
+Fluidbook.TOP = 8;\r
+Fluidbook.BOTTOM = 9;\r
+\r
+Fluidbook.prototype = {\r
+       init: function(datas) {\r
+               this.datas = datas;\r
+               this.junk = datas.cacheDate;\r
+               this.cache = new FluidbookCache(datas);\r
+               this.service = new FluidbookService(this, datas.id);\r
+               this.support = new FluidbookSupport(this);\r
+               this.loader = new FluidbookLoader(this);\r
+               this.search = new FluidbookSearch(this);\r
+               this.pad = new FluidbookPad(this);\r
+               if (Modernizr.ftouch && this.support.transitions2d && this.datas.mobileTransitions != 'none') {\r
+                       this.touch = new FluidbookTouch(this);\r
+               }\r
+               this.background = new FluidbookBackground(this);\r
+               this.viewport = new FluidbookViewport(this.support)\r
+               this.l10n = new FluidbookL10N(this, $_GET['lang']);\r
+               this.nav = new FluidbookNav(this);\r
+               this.video = new FluidbookVideo(this);\r
+               this.bookmarks = new FluidbookBookmarks(this);\r
+               this.index = new FluidbookIndex(this);\r
+               this.refw = 0;\r
+               this.refh = 0;\r
+               this.zoom = 1;\r
+               this.searchHintXHR = null;\r
+               this.searchString = '';\r
+               this.termsToHighlight = '';\r
+               this.imagesVersion = (this.datas.mobileVersion == 'html5-images' || !this.support.SVG);\r
+               this.vectorTexts = !this.imagesVersion;\r
+               this.displayOnePage = false;\r
+               this.indexHTML = '';\r
+               this.transitionning = false;\r
+\r
+               this.transitionAxis = 'x';\r
+\r
+               if (this.support.isMobile) {\r
+                       $("body").addClass('mobile');\r
+               }\r
+               else {\r
+                       $("body").addClass('desktop');\r
+               }\r
+\r
+               if (this.pad.enabled) {\r
+                       $("body").addClass('pad');\r
+               }\r
+               $('html').addClass(this.datas.mobileLVersion);\r
+\r
+               this.currentPage = -1;\r
+\r
+               this.resize = new FluidbookResize(this);\r
+               this.help = new FluidbookHelp(this);\r
+               this.coquillette = new FluidbookCoquillette(this);\r
+\r
+\r
+               this.stats = new FluidbookStats(this);\r
+               this.stats.track(10);\r
+               if (!this.support.isMobile) {\r
+                       this.desktop = new FluidbookDesktop(this);\r
+               }\r
+\r
+               this.initLoading();\r
+\r
+       },\r
+       initLoading: function() {\r
+               this.displayLoader();\r
+\r
+       },\r
+       hideSplash: function() {\r
+               if ($("#splash").length == 0) {\r
+                       return;\r
+               }\r
+               var $this = this;\r
+               setTimeout(function() {\r
+                       $this._hideSplash();\r
+               }, 3000);\r
+       },\r
+       _hideSplash: function() {\r
+               this.ready();\r
+               $("#main").css('visibility', 'visible');\r
+               this.hideLoader(0, true);\r
+               $("#splash").css('opacity', 0).one(this.support.transitionendevents, function() {\r
+                       $(this).remove();\r
+               });\r
+       },\r
+       ready: function() {\r
+               this.help.displayAtStartup();\r
+       },\r
+       loadPlugins: function() {\r
+               $.each(this.datas.plugins, function(k, plugin) {\r
+                       try {\r
+                               var functionName = plugin.replace(/\./g, '_');\r
+                               eval(functionName + '();');\r
+                       } catch (err) {\r
+                       }\r
+               });\r
+               $.each(this.datas.htmlmultimedia, function(k, code) {\r
+                       try {\r
+                               eval(code);\r
+                       } catch (err) {\r
+                       }\r
+               });\r
+       },\r
+       resetZoom: function() {\r
+               var $this = this;\r
+               if (this.support.iOS) {\r
+               } else if (!this.support.isMobile) {\r
+                       this.desktop.updateDesktopScale(1);\r
+               }\r
+\r
+       },\r
+       setZoom: function(zoom) {\r
+               if (zoom) {\r
+                       $("#pages").addClass('zoom');\r
+               } else {\r
+                       $("#pages").removeClass('zoom');\r
+               }\r
+       },\r
+       initPage: function(pageNr, doublePage, position) {\r
+               if ($("#page_" + pageNr).length > 0) {\r
+                       return;\r
+               }\r
+               $(doublePage).find('.' + position).remove();\r
+\r
+               var page = '<div class="page ' + position + '" id="page_' + pageNr + '"><div class="background" page="' + pageNr + '"></div><div class="clinks"></div><div class="texts" highlight=""></div><div class="shade"></div></div>';\r
+               $(doublePage).append(page);\r
+       },\r
+       hidePage: function(position) {\r
+               $("#pages ." + position).hide();\r
+       },\r
+       initLinks: function(pageNr) {\r
+               if (pageNr == undefined) {\r
+                       pageNr = this.currentPage;\r
+               }\r
+\r
+               var lClass = 'left';\r
+               if (this.displayOnePage && pageNr % 2 == 1) {\r
+                       lClass = 'right';\r
+               }\r
+\r
+               if (pageNr % 2 == 1) {\r
+                       pageNr--;\r
+               }\r
+\r
+               $("#links").removeClass('left').removeClass('right').addClass(lClass).html(this.datas.links[pageNr]).show();\r
+               if (this.datas.bookmark) {\r
+\r
+                       $("#links").append(this.bookmarks.getBookmarkForPage(pageNr));\r
+               }\r
+               $("#links").prepend('<a href="#" class="nonlinkarea"></a>');\r
+\r
+               var $this = this;\r
+               if (this.datas.linkBlinkTime > 0) {\r
+                       //this.animateLinks();\r
+               }\r
+               setTimeout(function() {\r
+                       $this.initVideos();\r
+               }, 1000);\r
+       },\r
+       animateLinks: function() {\r
+               var links = $(".link a.displayArea");\r
+               var bookmarks = $("#links .bookmark:not([data-enabled])");\r
+               if (Modernizr.csstransitions) {\r
+                       $(links).addClass('animating');\r
+                       $(bookmarks).css('opacity', 1).addClass('animating');\r
+                       setTimeout(function() {\r
+                               $(links).css('opacity', 0);\r
+                               $(bookmarks).css('opacity', 0);\r
+                               setTimeout(function() {\r
+                                       $(links).removeClass('animating').css('opacity', 1);\r
+                                       $(bookmarks).removeClass('animating').css('opacity', "");\r
+                               }, 1100);\r
+                       }, 50);\r
+               } else {\r
+                       $(links).addClass('animating').fadeOut(1000, function() {\r
+                               $(links).removeClass('animating').show();\r
+                       }).mouseover(function() {\r
+                               $(links).stop().removeClass('animating').css('opacity', 1).show();\r
+                               return true;\r
+                       });\r
+               }\r
+       },\r
+       initVideos: function() {\r
+               var $this = this;\r
+               $(".videoContainer").each(function() {\r
+                       $this.video.initVideo(this);\r
+               });\r
+       },\r
+       getNextOffset: function() {\r
+               var offset = 2;\r
+               if (this.displayOnePage) {\r
+                       offset = 1;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               return offset;\r
+       },\r
+       goNextPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(this.normalizePage(this.currentPage) + this.getNextOffset());\r
+       },\r
+       goFirstPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(1);\r
+       },\r
+       goPreviousPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(this.normalizePage(this.currentPage) - this.getNextOffset());\r
+       },\r
+       goLastPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(this.datas.pages);\r
+       },\r
+       goNextChapter: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               var next = this.bookmarks.getNextGroupCover(this.currentPage);\r
+               if (next === false) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(this.normalizePage(next));\r
+\r
+       },\r
+       goPreviousChapter: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+               var prev = this.bookmarks.getPreviousGroupCover(this.currentPage);\r
+               if (prev === false) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'x';\r
+               this.setCurrentPage(this.normalizePage(prev));\r
+       },\r
+       goNextChapterPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+\r
+               var next = this.bookmarks.getNextPageInGroupOfPage(this.currentPage);\r
+               if (next === false) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'y';\r
+               this.setCurrentPage(this.normalizePage(next));\r
+       },\r
+       goPreviousChapterPage: function() {\r
+               if (this.transitionning) {\r
+                       return;\r
+               }\r
+\r
+               var prev = this.bookmarks.getPreviousPageInGroupOfPage(this.currentPage);\r
+               if (prev === false) {\r
+                       return;\r
+               }\r
+               this.transitionAxis = 'y';\r
+               this.setCurrentPage(this.normalizePage(prev));\r
+       },\r
+       normalizePage: function(page) {\r
+               page = Math.max(1, Math.min(page, this.datas.pages));\r
+               if (!this.displayOnePage && page % 2 == 1) {\r
+                       page--;\r
+               }\r
+               return page;\r
+       },\r
+       setCurrentPage: function(page) {\r
+               window.location.hash = "#/page/" + this.normalizePage(page);\r
+       },\r
+       changeAddress: function() {\r
+               var $this = this;\r
+               var page;\r
+               var args = window.location.hash.split('/');\r
+               if (args.length <= 1 || args[1] == '' || args[1] == undefined) {\r
+                       return this.setCurrentPage('1');\r
+               } else if (args[1] == 'page') {\r
+                       page = parseInt(args[2]);\r
+                       if (isNaN(page) || page == undefined) {\r
+                               return this.setCurrentPage('1');\r
+                       }\r
+                       if (this.pad.enabled) {\r
+                               this.transitionAxis = this.pad.getTransitionAxis(this.currentPage, page);\r
+                       } else {\r
+                               this.transitionAxis = 'x';\r
+                       }\r
+\r
+                       $($this).trigger('changePage', [page]);\r
+\r
+                       this.closeView(function() {\r
+                               $this.pageTransition(page);\r
+                               $this.resetZoom();\r
+                               $this.stats.track(0, page);\r
+                               $this.hideSplash();\r
+                       }, true);\r
+               }\r
+               else {\r
+                       this.openView(args[1], args[2], args[3], function() {\r
+                               $this.hideSplash();\r
+                       });\r
+                       this.resetZoom();\r
+               }\r
+\r
+               return;\r
+       },\r
+       pageTransition: function(pageNr) {\r
+               if (pageNr == undefined) {\r
+                       pageNr = this.currentPage;\r
+                       if (pageNr == -1) {\r
+                               pageNr = 1;\r
+                       }\r
+               }\r
+               pageNr = this.normalizePage(pageNr);\r
+               if (pageNr == this.normalizePage(this.currentPage) || this.currentPage == -1) {\r
+                       // No page change, just reload\r
+                       this.pageTransition1D(pageNr);\r
+                       return;\r
+               }\r
+               if (!this.displayOnePage && this.datas.mobileTransitions == 'flip') {\r
+                       if (this.support.transitions3d) {\r
+                               this.pageTransition3D(pageNr);\r
+                       } else if (this.support.transitions2d) {\r
+                               this.pageTransition2D(pageNr);\r
+                       } else {\r
+                               this.pageTransition1D(pageNr);\r
+                       }\r
+               } else if ((this.displayOnePage && this.datas.mobileTransitions == 'flip')) {\r
+                       if (this.support.transitions2d) {\r
+                               this.pageTransition2DPortrait(pageNr);\r
+                       } else {\r
+                               this.pageTransition1D(pageNr);\r
+                       }\r
+               } else if (this.datas.mobileTransitions == 'slide') {\r
+                       if (this.support.transitions2d) {\r
+                               this.pageTransition2D(pageNr);\r
+                       } else {\r
+                               this.pageTransition1D(pageNr);\r
+                       }\r
+\r
+\r
+               }\r
+               else {\r
+                       this.pageTransition1D(pageNr);\r
+               }\r
+       },\r
+       pageTransition3D: function(pageNr) {\r
+\r
+               var $this = this;\r
+               if ($("#pages").hasClass('_3dtransition')) {\r
+                       return;\r
+               }\r
+               this.transitionning = true;\r
+               var nextFromClass;\r
+               var $this = this;\r
+               if (pageNr > this.currentPage) {\r
+                       nextFromClass = 'next';\r
+               } else {\r
+                       nextFromClass = 'prev';\r
+               }\r
+\r
+               $("#pages").prepend('<div id="nextDoublePage" class="_3d doublePage ' + nextFromClass + 'start"></div>');\r
+               var doublePage = $("#nextDoublePage");\r
+               var currentDoublePage = $("#currentDoublePage");\r
+\r
+               var currentLeft = this.currentPage - this.currentPage % 2;\r
+               var currentRight = currentLeft + 1;\r
+\r
+               var dir = 1;\r
+               if (pageNr < this.currentPage) {\r
+                       dir = -1;\r
+               }\r
+\r
+\r
+               var preload = [pageNr, pageNr + 1];\r
+\r
+               this.displayLoader();\r
+\r
+               this.loader.preloadPagesBeforeTransition(preload, function() {\r
+                       var pages;\r
+                       $("#pages").addClass('_3dtransition');\r
+                       // Set contents of flat part\r
+                       if (dir == 1) {\r
+                               pages = [currentLeft, pageNr + 1];\r
+                       } else {\r
+                               pages = [pageNr, currentRight];\r
+                       }\r
+                       $this.loader.setContentsInDoublePage(currentDoublePage, pages, true, function() {\r
+                               // Set the contents of fliping part\r
+                               if (dir == 1) {\r
+                                       pages = [pageNr, currentRight];\r
+                               } else {\r
+                                       pages = [currentLeft, pageNr + 1];\r
+                               }\r
+\r
+                               $this.loader.setContentsInDoublePage(doublePage, pages, true, function() {\r
+                                       $this.beforeTransition(pageNr);\r
+                                       // Do the transition\r
+\r
+                                       $(doublePage).addClass(nextFromClass + 'end').one($this.support.transitionendevents, function() {\r
+                                               if ($("#nextDoublePage").length == 0) {\r
+                                                       $("#pages").removeClass('_3dtransition');\r
+                                                       this.transitionning = false;\r
+                                                       return;\r
+                                               }\r
+                                               $(this).off($this.support.transitionendevents);\r
+                                               // Set the flat contents with the new page\r
+                                               $this.loader.setContentsInDoublePage(doublePage, [pageNr, pageNr + 1], false, function() {\r
+                                                       $(doublePage).removeClass('_3d').removeClass(nextFromClass + 'start').removeClass(nextFromClass + 'end');\r
+                                                       // Remove former part\r
+                                                       $("#currentDoublePage").remove();\r
+                                                       $(doublePage).attr('id', 'currentDoublePage');\r
+\r
+                                                       $("#pages").removeClass('_3dtransition');\r
+                                                       $this.afterTransition(pageNr);\r
+\r
+                                               });\r
+\r
+                                       });\r
+                               });\r
+                       });\r
+               });\r
+       },\r
+       reloadCurrentPage: function() {\r
+               this.pageTransition(this.currentPage);\r
+       },\r
+       readingPage: function(side) {\r
+               if (!this.displayOnePage) {\r
+                       var page = this.currentPage;\r
+                       var change = false;\r
+                       if (side == 'left' && page % 2 == 1) {\r
+                               page--;\r
+                               change = true;\r
+                       } else if (side == 'right' && page % 2 == 0) {\r
+                               page++;\r
+                               change = true;\r
+                       }\r
+                       if (change) {\r
+                               window.location.hash = "/page/" + page;\r
+                       }\r
+               }\r
+       },\r
+       hideUnnecessaryButtons: function(page) {\r
+               var speed = 500;\r
+               if (page == undefined) {\r
+                       page = this.currentPage;\r
+                       speed = 0;\r
+               }\r
+\r
+               $("#previous,#next").removeClass('help');\r
+               if (Modernizr.csstransitions) {\r
+                       if (page <= 1) {\r
+                               $("#previous").addClass('hidden');\r
+                       } else {\r
+                               $("#previous").removeClass('hidden');\r
+                       }\r
+\r
+                       if (page >= this.datas.pages) {\r
+                               $("#next").addClass('hidden');\r
+                       } else {\r
+                               $("#next").removeClass('hidden');\r
+                       }\r
+\r
+               } else {\r
+                       $("#previous,#next").removeClass('hidden');\r
+\r
+                       if (page <= 1) {\r
+                               $("#previous:visible").fadeOut(speed);\r
+                       } else {\r
+                               $("#previous:hidden").fadeIn(speed);\r
+                       }\r
+\r
+                       if (page >= this.datas.pages) {\r
+                               $("#next:visible").fadeOut(speed);\r
+                       } else {\r
+                               $("#next:hidden").fadeIn(speed);\r
+                       }\r
+               }\r
+\r
+               if (page <= 1) {\r
+                       $("#shadow").removeClass('double');\r
+                       $("#shadow").removeClass('left');\r
+                       $("#shadow").addClass('right');\r
+                       $("#shadow").addClass('single');\r
+               } else if (page >= this.datas.pages) {\r
+                       $("#shadow").removeClass('double');\r
+                       $("#shadow").removeClass('right');\r
+                       $("#shadow").addClass('left');\r
+                       $("#shadow").addClass('single');\r
+               }\r
+               else {\r
+                       $("#shadow").removeClass('single');\r
+                       $("#shadow").addClass('double');\r
+               }\r
+\r
+       },\r
+       showAllButtons: function() {\r
+               $("#next,#previous").addClass('help').show();\r
+       },\r
+       pageTransition2D: function(pageNr) {\r
+               this.transitionning = true;\r
+               var currentFromClass, currentToClass;\r
+               var $this = this;\r
+               if (pageNr > this.currentPage) {\r
+                       currentToClass = 'prev';\r
+                       nextFromClass = 'next';\r
+               }\r
+               else {\r
+                       currentToClass = 'next';\r
+                       nextFromClass = 'prev';\r
+               }\r
+\r
+\r
+               $("#pages").append('<div id="nextDoublePage" class="doublePage _2d axis_' + this.transitionAxis + ' ' + nextFromClass + '"></div>');\r
+               var doublePage = $("#nextDoublePage");\r
+               this.displayLoader();\r
+               this.loader.preloadPagesBeforeTransition([pageNr, pageNr + 1], function() {\r
+                       $this.loader.setContentsInDoublePage(doublePage, [pageNr, pageNr + 1], true, function() {\r
+                               $this.beforeTransition(pageNr);\r
+                               $("#currentDoublePage").addClass('_2d').addClass('axis_' + $this.transitionAxis).addClass(currentToClass);\r
+                               $(doublePage).removeClass(nextFromClass).one($this.support.transitionendevents, function(event) {\r
+                                       $("#currentDoublePage").remove();\r
+                                       $("#nextDoublePage").attr('id', 'currentDoublePage');\r
+                                       $this.afterTransition(pageNr);\r
+                                       $(this).off($this.support.transitionendevents);\r
+                               });\r
+                       });\r
+               });\r
+       },\r
+       pageTransition2DPortrait: function(pageNr) {\r
+               this.transitionning = true;\r
+               var currentFromClass, currentToClass;\r
+               var $this = this;\r
+               if (pageNr > this.currentPage) {\r
+                       currentToClass = 'prev';\r
+                       nextFromClass = 'next';\r
+               }\r
+               else {\r
+                       currentToClass = 'next';\r
+                       nextFromClass = 'prev';\r
+               }\r
+\r
+\r
+               $("#pages").append('<div id="nextDoublePage" class="doublePage _2d axis_' + this.transitionAxis + ' ' + nextFromClass + '"></div>');\r
+               var doublePage = $("#nextDoublePage");\r
+\r
+               if (this.displayOnePage) {\r
+                       this.hidePage('right');\r
+               }\r
+\r
+               this.displayLoader();\r
+               this.loader.preloadPagesBeforeTransition([pageNr, pageNr + 1], function() {\r
+                       $this.loader.setContentsInDoublePage(doublePage, [pageNr, pageNr + 1], true, function() {\r
+                               $this.beforeTransition(pageNr);\r
+                               $("#currentDoublePage").addClass('axis_' + $this.transitionAxis).addClass('_2d').addClass(currentToClass);\r
+                               $(doublePage).removeClass(nextFromClass).one($this.support.transitionendevents, function() {\r
+                                       $("#currentDoublePage").remove();\r
+                                       $("#nextDoublePage").attr('id', 'currentDoublePage');\r
+                                       $this.afterTransition(pageNr);\r
+                                       $(this).off($this.support.transitionendevents);\r
+                               });\r
+                       });\r
+               });\r
+       },\r
+       pageTransition1D: function(pageNr) {\r
+               var page = pageNr;\r
+               var doublePage = $("#currentDoublePage");\r
+               var $this = this;\r
+\r
+               if (this.displayOnePage) {\r
+                       this.hidePage('right');\r
+               }\r
+               this.beforeTransition(pageNr);\r
+               this.loader.setContentsInDoublePage(doublePage, [page, page + 1], true, function() {\r
+                       $this.afterTransition(page);\r
+               });\r
+\r
+       },\r
+       beforeTransition: function(page) {\r
+               $(".axis_y").removeClass('axis_y');\r
+               $(".axis_x").removeClass('axis_x');\r
+               $("#links").hide();\r
+               this.hideLoader();\r
+               this.hideUnnecessaryButtons(page);\r
+       },\r
+       afterTransition: function(page) {\r
+               if (this.transitionning === false) {\r
+                       //return;\r
+               }\r
+               var $this = this;\r
+               this.currentPage = page;\r
+\r
+               this.setPageNumbers();\r
+               setTimeout(function() {\r
+                       $this.loader.preloadAround(page);\r
+               }, 1000);\r
+               this.initLinks();\r
+               this.hideLoader();\r
+\r
+               // Clean messy stuffs\r
+               $("#pages").removeClass('_3dtransition');\r
+               if ($("#nextDoublePage").length > 0) {\r
+                       $("#currentDoublePage").remove();\r
+                       $("#nextDoublePage").attr('id', 'currentDoublePage');\r
+               }\r
+               if ($("#currentDoublePage").length > 1) {\r
+                       $("#currentDoublePage:gt(0)").remove();\r
+               }\r
+               this.transitionning = false;\r
+\r
+               if (this.pad.enabled) {\r
+                       if (this.currentPage == this.datas.pages) {\r
+                               $("#down").css('opacity', 0);\r
+                       } else {\r
+                               $("#down").css('opacity', 1);\r
+                               if (!this.bookmarks.hasNextPageInGroup(this.currentPage)) {\r
+                                       $("#down").addClass('right');\r
+                               } else {\r
+                                       $("#down").removeClass('right');\r
+                               }\r
+                       }\r
+               } else {\r
+                       $("#down").css('opacity', 0);\r
+               }\r
+\r
+       },\r
+       setPageNumbers: function() {\r
+               var page = this.currentPage;\r
+               if (page > 0) {\r
+                       $("#pagesnumbers .left").html(this.physicalToVirtual(page));\r
+               } else {\r
+                       $("#pagesnumbers .left").html('');\r
+               }\r
+\r
+               if (!this.displayOnePage) {\r
+                       page++;\r
+                       if (page <= this.datas.pages) {\r
+                               $("#pagesnumbers .right").html(this.physicalToVirtual(page));\r
+                               $("#pagesnumbers .right").show();\r
+                       } else {\r
+                               $("#pagesnumbers .right").html('');\r
+                               $("#pagesnumbers .right").hide();\r
+                       }\r
+               }\r
+       },\r
+       clickLogo: function() {\r
+               if (this.datas.url_link == '' || this.datas.url_link == 'http://') {\r
+                       return;\r
+               }\r
+               this.wopen(this.datas.url_link, '_blank');\r
+       },\r
+       viewMode: function() {\r
+               return $("#view .mview").length > 0;\r
+       },\r
+       openView: function(view, param1, param2, callback) {\r
+               var $this = this;\r
+\r
+               this.displayLoader();\r
+\r
+               setTimeout(function() {\r
+                       $this._openView(view, param1, param2, callback);\r
+               }, 20);\r
+       },\r
+       _openView: function(view, param1, param2, callback) {\r
+               var $this = this;\r
+               var camelView = view.charAt(0).toUpperCase() + view.substr(1);\r
+\r
+               /*if ($('.mview:visible').length > 0) {\r
+                this.closeView(function() {\r
+                $this._openView(view, param1, param2, callback);\r
+                });\r
+                return;\r
+                }*/\r
+               var cb = function() {\r
+                       $this.openingView(callback);\r
+               };\r
+\r
+               if (view == 'index') {\r
+                       this.openIndex(this.l10n.__('overview'), undefined, true, cb);\r
+               } else if (view == 'search') {\r
+                       this.searchString = param1;\r
+                       var group = param2;\r
+                       $("#q").val(param1);\r
+                       this.displayResults(this.search.find(param1), group, cb);\r
+                       if (group == undefined) {\r
+                               this.stats.track(1, 0, param1);\r
+                       }\r
+               } else if (view == 'video') {\r
+                       this.openVideo(param1, cb);\r
+               } else if (view == 'webvideo') {\r
+                       this.openWebVideo(param1, param2, cb);\r
+               } else if (view == 'chapters') {\r
+                       this.openChapters(cb);\r
+               } else if (view == 'archives') {\r
+                       this.openArchives(this.l10n.__($("#nav #archives").attr('help')), cb);\r
+               } else {\r
+                       this['open' + camelView](param1, param2, cb);\r
+               }\r
+       },\r
+       openingView: function(callback) {\r
+               var $this = this;\r
+               this.resize.resizeView();\r
+\r
+               var mview = $('#view .mview:last');\r
+\r
+               if (this.support.transitions2d) {\r
+                       var vertFrom = {\r
+                               translateY: $(window).height() + 'px'\r
+                       };\r
+                       var vertTo = {\r
+                               translateY: '0px'\r
+                       };\r
+                       var horiFrom = {\r
+                               translateX: $(window).width() + 'px'\r
+                       };\r
+                       var horiTo = {\r
+                               translateX: '0px'\r
+                       };\r
+                       var from = vertFrom;\r
+                       var to = vertTo;\r
+                       if ($(mview).hasClass('hori')) {\r
+                               from = horiFrom;\r
+                               to = horiTo;\r
+                       }\r
+\r
+                       $(mview).show().removeClass('animate').transform(from);\r
+\r
+                       setTimeout(function() {\r
+                               $(mview).one($this.support.transitionendevents, function() {\r
+                                       $("#main").hide();\r
+                                       $('body').addClass('view');\r
+                                       $(mview).removeClass('animate');\r
+                                       callback();\r
+                                       $this.hideLoader();\r
+                                       resize();\r
+                               }).addClass('animate').transform(to);\r
+                       }, 50);\r
+\r
+               } else {\r
+                       $("#main").hide();\r
+                       $('body').addClass('view');\r
+                       $(mview).show();\r
+                       callback();\r
+                       this.hideLoader();\r
+                       resize();\r
+               }\r
+       },\r
+       displayResults: function(data, group, callback) {\r
+               var $this = this;\r
+               var results = data.results;\r
+               var hideNoResults = !this.datas.searchShowNoResultsPages;\r
+               if (data.total <= 0) {\r
+                       alert(this.l10n.__('no result found'));\r
+                       window.location = "#/page/" + this.currentPage;\r
+                       return;\r
+               }\r
+\r
+               this.openIndex(this.l10n.__('search results for') + ' &laquo; ' + this.searchString + " &raquo;", group, false, function() {\r
+                       var hits = [];\r
+                       for (var i = 0; i <= $this.datas.pages; i++) {\r
+                               hits[i] = 0;\r
+                       }\r
+\r
+                       $.each(results, function(k, v) {\r
+                               hits[k] += v;\r
+                       });\r
+\r
+                       var e = encodeURIComponent($this.searchString);\r
+\r
+                       $(".doubleThumb").each(function() {\r
+                               var pages = $(this).data('pages').toString().split(',');\r
+                               var hitsp = 0;\r
+                               var pagesWithHits = 0;\r
+                               for (var i in pages) {\r
+                                       var n = parseInt(pages[i]);\r
+                                       if (hits[n] > 0) {\r
+                                               hitsp += hits[n];\r
+                                               pagesWithHits++;\r
+                                       }\r
+                               }\r
+\r
+                               if ($(this).find('.hits').length > 0) {\r
+                                       return;\r
+                               }\r
+\r
+                               if (hitsp == 0) {\r
+                                       if (hideNoResults) {\r
+                                               $(this).remove();\r
+                                               return;\r
+                                       }\r
+                                       $(this).append('<div class="overlay"></div>');\r
+                                       $(this).append('<div class="hits no">' + $this.l10n.__('no result found') + '</div>');\r
+                               } else {\r
+                                       $(this).append('<div class="hits yes">' + hitsp + ' ' + $this.l10n.__('hit(s)') + '</div>');\r
+                                       if (pagesWithHits <= 1) {\r
+                                               $(this).find('a').attr('href', '#/page/' + $(this).attr('page'));\r
+                                       } else {\r
+                                               $(this).find('a').attr('href', '#/search/' + e + '/' + $(this).attr('page'));\r
+                                       }\r
+                               }\r
+                       });\r
+\r
+                       $this.termsToHighlight = data.terms;\r
+\r
+                       if (callback != undefined) {\r
+                               callback();\r
+                       }\r
+               });\r
+       },\r
+       openVideo: function(video, callback) {\r
+               var a = $('a[href="#/video/' + video + '"]');\r
+               var markup = decodeURIComponent($(a).attr('data-video'));\r
+\r
+               var view = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a></div>';\r
+               view += '<div class="content">';\r
+               view += markup;\r
+               view += '</div>';\r
+\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+\r
+               this.stats.track(11);\r
+\r
+               this.initVideos();\r
+               var $this = this;\r
+               var times = [250, 500, 750, 1000, 1250];\r
+               $.each(times, function(k, v) {\r
+                       setTimeout(function() {\r
+                               $this.resize.resizePopupVideos();\r
+                       }, v);\r
+               });\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openWebVideo: function(service, video, callback) {\r
+\r
+               var view = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a></div>';\r
+               view += '<div class="content">';\r
+               if (service == 'youtube') {\r
+                       view += '<iframe class="webvideo" type="text/html" width="100%" height="407" src="http://www.youtube.com/embed/' + video + '?autoplay=1&modestbranding=1&rel=0&html5=1" frameborder="0"></iframe>';\r
+               } else if (service == 'dailymotion') {\r
+                       view += '<iframe class="webvideo" type="text/html" width="100%" height="407" src="http://www.dailymotion.com/embed/video/' + video + '?autoplay=1&logo=0&related=0&html5=1" width="100%" frameborder="0"></iframe>'\r
+               }\r
+               view += '</div>';\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+\r
+               $("#view .mview:last iframe").each(function() {\r
+                       $(this).attr('height', ($(this).width() * 9) / 16);\r
+               });\r
+               this.stats.track(11);\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openLocales: function(p1, p2, callback) {\r
+               var view = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a><h2>Select language</h2></div>';\r
+               view += '<div class="content">';\r
+               view += '<ul class="chapters localesList">';\r
+               var $this = this;\r
+               $.each(this.l10n.multilang, function(k, v) {\r
+                       var url = v.url;\r
+                       if (url.substr(0, 3) == '../' && !$this.datas.standalone) {\r
+                               url = '../' + url;\r
+                       }\r
+                       view += '<li data-level="0"><a href="' + url + '" class="level0"><img src="images/flags/' + v.flag + '.png" alt="' + v.name + '" />' + v.name + '</a></li>';\r
+               });\r
+               view += '</ul>';\r
+               view += '</div>';\r
+\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openShare: function(p1, p2, callback) {\r
+               var view = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a><h2>' + this.l10n.__('share') + '</h2></div>';\r
+               view += '<div class="content">';\r
+               view += '<ul class="chapters shareList">';\r
+               var $this = this;\r
+               if (this.datas.friend) {\r
+                       view += '<li data-level="0"><a href="#" data-service="email" class="share level0"><img height="25" src="data/images/share-email.svg" /> E-mail</a></li>';\r
+               }\r
+               if (this.datas.facebook) {\r
+                       view += '<li data-level="0"><a href="#" data-service="facebook" class="share level0"><img height="25" src="data/images/share-facebook.svg" /> Facebook</a></li>';\r
+               }\r
+               if (this.datas.twitter) {\r
+                       view += '<li data-level="0"><a href="#" data-service="twitter" class="share level0"><img height="25" src="data/images/share-twitter.svg" /> Twitter</a></li>';\r
+               }\r
+               if (this.datas.googleplus) {\r
+                       view += '<li data-level="0"><a href="#" data-service="googleplus" class="share level0"><img height="25" src="data/images/share-googleplus.svg" /> Google+</a></li>';\r
+               }\r
+               if (this.datas.linkedin) {\r
+                       view += '<li data-level="0"><a href="#" data-service="linkedin" class="share level0"><img height="25" src="data/images/share-linkedin.svg" /> LinkedIn</a></li>';\r
+               }\r
+               if (this.datas.viadeo) {\r
+                       view += '<li data-level="0"><a href="#" data-service="viadeo" class="share level0"><img height="25" src="data/images/share-viadeo.svg" /> Viadeo</a></li>';\r
+               }\r
+               view += '</ul>';\r
+               view += '</div>';\r
+\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openBookmark: function(p1, p2, callback) {\r
+               var view = this.bookmarks.getView();\r
+               if (view !== false) {\r
+                       $("#view").append('<div class="mview">' + view + '</div>');\r
+                       if (callback != undefined) {\r
+                               callback();\r
+                       }\r
+               } else {\r
+                       window.alert(this.l10n.__("you don't have any bookmarks"));\r
+                       window.history.back();\r
+                       this.hideLoader();\r
+               }\r
+       },\r
+       openChapters: function(callback) {\r
+               if (this.chapters == undefined) {\r
+                       this.chapters = new FluidbookChapters(this, this.datas.chapters);\r
+               }\r
+\r
+               var view = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a><h2>' + this.l10n.__('chapters') + '</h2></div>';\r
+               view += '<div class="content">';\r
+               view += this.chapters.getView();\r
+               view += '</div>';\r
+\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openIndex: function(title, group, closeAll, callback) {\r
+               var c = !closeAll ? ' one' : '';\r
+               var index = '<div class="caption"><a href="#" class="back' + c + '">' + this.l10n.__('back') + '</a><h2>' + title + '</h2></div>';\r
+               index += this.index.getView(group);\r
+               $("#view").append('<div class="mview">' + index + '</div>');\r
+\r
+               this.bookmarks.updateBookmarks();\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       openArchives: function(title, callback) {\r
+               var archives = '<div class="caption"><a href="#" class="back">' + this.l10n.__('back') + '</a><h2>' + title + '</h2></div>';\r
+               archives += '<div class="image" id="archivesview"><img src="data/images/' + this.datas.externalArchives + '" /><div class="links">' + this.datas.links.archives + '</div></div>';\r
+               $("#view").append('<div class="mview archives">' + archives + '</div>');\r
+               if (callback != undefined) {\r
+                       callback();\r
+               }\r
+       },\r
+       physicalToVirtual: function(page) {\r
+               return this.datas.numerotation[page - 1];\r
+       },\r
+       virtualToPhysical: function(page) {\r
+               return this.datas.numerotation.indexOf(page) + 1;\r
+       },\r
+       closeView: function(callback, all, animate) {\r
+               var $this = this;\r
+               if (all == undefined) {\r
+                       all = false;\r
+               }\r
+               if (animate == undefined) {\r
+                       animate = true;\r
+               }\r
+               if ($('.mview').scrollTop() > 0) {\r
+                       $('.mview').scrollTo(0, 500, function() {\r
+                               $this.closeView(callback, all, animate);\r
+                       });\r
+                       return;\r
+               }\r
+\r
+               all = all || ($("#view .mview").length <= 1);\r
+               if (!this.viewMode()) {\r
+                       callback();\r
+                       return;\r
+               }\r
+\r
+               var mview = $("#view .mview:last");\r
+               if (all) {\r
+                       $("#view .mview:not(:last)").remove();\r
+               }\r
+\r
+               var to = {\r
+                       translateY: $(window).height() + 'px'\r
+               };\r
+\r
+               if ($(mview).hasClass('hori')) {\r
+                       to = {translateX: $(window).width() + 'px'}\r
+               }\r
+\r
+               if (animate && this.support.transitions2d) {\r
+                       setTimeout(function() {\r
+                               $(mview).one($this.support.transitionendevents, function() {\r
+                                       $(this).remove();\r
+                                       callback();\r
+                               }).addClass('animate').transform(to);\r
+                       }, 50);\r
+\r
+               } else {\r
+                       $(mview).remove()\r
+                       callback();\r
+               }\r
+               if (all) {\r
+                       $("#main").show();\r
+                       $('body').removeClass('view');\r
+               }\r
+               resize();\r
+       },\r
+       getSearchHints: function(q) {\r
+               this.killLastSearchHint();\r
+               this.displaySearchHints(this.search.getHints(q));\r
+       },\r
+       displaySearchHints: function(hints) {\r
+\r
+               this.hideSearchHints();\r
+               if (hints.length == 0) {\r
+                       return;\r
+               }\r
+               $.each(hints, function(k, v) {\r
+                       $("#searchHints").append('<a class="hint" term="' + v[0] + '" href="#/search/' + v[0] + '">' + v[0] + ' <em>(' + v[1] + ')</em></a>');\r
+               });\r
+               $("#searchHints").show();\r
+       },\r
+       killLastSearchHint: function() {\r
+               this.search.kill();\r
+       },\r
+       hideSearchHints: function() {\r
+               this.killLastSearchHint();\r
+               $("#searchHints").html('');\r
+               $("#searchHints").hide();\r
+       },\r
+       getLocationToShare: function() {\r
+               if (this.datas.phonegap) {\r
+                       return this.datas.offlineLink;\r
+               } else {\r
+                       var l = window.location.toString();\r
+                       var e = l.split("#");\r
+                       return e[0];\r
+               }\r
+       },\r
+       sendEmail: function() {\r
+               window.location = 'mailto:?subject=' + this.datas.title + '&body=' + this.datas.title + ' : ' + this.getLocationToShare();\r
+               this.stats.track(5);\r
+       },\r
+       sendTwitter: function() {\r
+               this.service.open('twitterShare', {\r
+                       url: this.getLocationToShare(),\r
+                       post: this.datas.twitter_description.replace('%title%', this.datas.title)\r
+               });\r
+               this.stats.track(13);\r
+       },\r
+       sendFacebook: function() {\r
+               this.service.open('facebookShare', {\r
+                       url: this.getLocationToShare()\r
+               });\r
+               this.stats.track(12);\r
+       },\r
+       sendGoogleplus: function() {\r
+               this.service.open('googleplusShare', {\r
+                       url: this.getLocationToShare()\r
+               });\r
+               this.stats.track(12);\r
+       },\r
+       sendLinkedin: function() {\r
+               this.service.open('linkedinShare', {\r
+                       url: this.getLocationToShare()\r
+               });\r
+               this.stats.track(12);\r
+       },\r
+       sendViadeo: function() {\r
+               this.service.open('viadeoShare', {\r
+                       url: this.getLocationToShare()\r
+               });\r
+               this.stats.track(12);\r
+       },\r
+       print: function() {\r
+               var pdf = getBaseURL() + '/data/' + this.datas.pdfName;\r
+               this._openFile(pdf, $("#print"), 'pdf', this.datas.pdfName);\r
+       },\r
+       _openFile: function(url, e, type, localname) {\r
+               var $this = this;\r
+\r
+               if (this.datas.phonegap != false) {\r
+                       if (type == undefined) {\r
+                               var e = url.split('.');\r
+                               type = e.pop();\r
+                       }\r
+\r
+                       if (url.indexOf('http') == 0) {\r
+                               return this._downloadFilePhonegap(url, localname, LocalFileSystem.TEMPORARY, this._openFilePhonegap, [url, e, type]);\r
+                       } else {\r
+                               if (this._openFilePhonegap(url, e, type)) {\r
+                                       return;\r
+                               }\r
+                       }\r
+\r
+               }\r
+               this.wopen(url);\r
+       },\r
+       _downloadFilePhonegap: function(url, localname, fs, callback, callbackArgs) {\r
+               var $this = this;\r
+               if (fs == undefined) {\r
+                       fs = LocalFileSystem.PERSISTENT;\r
+               }\r
+\r
+               window.requestFileSystem(fs, 0, function(fileSystem) {\r
+                       fileSystem.root.getFile("dummy.html", {create: true, exclusive: false}, function(fileEntry) {\r
+                               var filePath = fileEntry.fullPath.replace("dummy.html", "") + localname;\r
+                               var fileTransfer = new FileTransfer();\r
+                               var uri = encodeURI(url);\r
+                               fileTransfer.download(\r
+                                               uri,\r
+                                               filePath,\r
+                                               function(entry) {\r
+                                                       console.log("download complete: " + entry.fullPath);\r
+                                                       if (callback != undefined) {\r
+                                                               if (callbackArgs == undefined) {\r
+                                                                       callbackArgs = [];\r
+                                                               }\r
+                                                               callbackArgs[0] = entry.toURL();\r
+                                                               callback.apply($this, callbackArgs);\r
+                                                       }\r
+                                               },\r
+                                               function(error) {\r
+                                                       console.log("download error source " + error.source);\r
+                                                       console.log("download error target " + error.target);\r
+                                                       console.log("upload error code" + error.code);\r
+                                               }\r
+                               );\r
+                       });\r
+               }, function() {\r
+\r
+               });\r
+       },\r
+       _openFilePhonegap: function(url, e, type) {\r
+               var $this = this;\r
+               var types_ios = {pdf: 'com.adobe.pdf'};\r
+               var types_android = {pdf: 'application/pdf'};\r
+               if (this.datas.phonegap == 'ios') {\r
+                       this.displayLoader();\r
+                       if (types_ios[type] != undefined) {\r
+                               var offset = $(e).offset();\r
+                               offset.left += ($(e).width() / 2);\r
+                               offset.top += ($(e).height());\r
+                               ExternalFileUtil.openWith(url, types_ios[type], function() {\r
+                                       $this.hideLoader();\r
+                               }, function() {\r
+                                       $this.wopen(url, "_blank", 'location=no');\r
+                                       $this.hideLoader();\r
+                               }, offset);\r
+                               return true;\r
+                       }\r
+               }\r
+               if (this.datas.phonegap == 'android') {\r
+                       if (types_android[type] != undefined) {\r
+                               this.displayLoader();\r
+                               setTimeout(function() {\r
+                                       window.webintent.startActivity({\r
+                                               action: WebIntent.ACTION_VIEW,\r
+                                               type: types_android[type],\r
+                                               url: url\r
+                                       }, function(args) {\r
+                                               $this.hideLoader(5);\r
+                                       }, function(args) {\r
+                                               $this.hideLoader(5);\r
+                                       });\r
+                               }, 100);\r
+\r
+                       }\r
+                       return true;\r
+\r
+               }\r
+               return false;\r
+       },\r
+       highlightSearchTerms: function(pageNr) {\r
+               return;\r
+       },\r
+       touchOffset: function(offset) {\r
+               offset *= $("#currentDoublePage").width();\r
+               $("#currentDoublePage").addClass('sliding');\r
+               $("#currentDoublePage").css({\r
+                       translateX: offset\r
+               });\r
+       },\r
+       displayLoader: function() {\r
+               if (this.support.isMobile) {\r
+                       this.coquillette.show();\r
+               } else {\r
+                       this.coquillette.show();\r
+                       $('body').addClass('loading');\r
+               }\r
+       },\r
+       hideLoader: function(delay, force) {\r
+               if (force == undefined) {\r
+                       force = false;\r
+               }\r
+               if (delay == undefined) {\r
+                       delay = 0;\r
+               }\r
+               var $this = this;\r
+               if (delay == 0) {\r
+                       return this._hideLoader(force);\r
+               }\r
+               setTimeout(function() {\r
+                       $this._hideLoader(force);\r
+               }, delay * 1000);\r
+       },\r
+       _hideLoader: function(force) {\r
+               if (force == undefined) {\r
+                       force = false;\r
+               }\r
+               if (!force && $('#splash').css('visibility') == 'visible') {\r
+                       return;\r
+               }\r
+               if (this.support.isMobile) {\r
+                       this.coquillette.hide();\r
+               } else {\r
+                       this.coquillette.hide();\r
+                       $('body').removeClass('loading');\r
+               }\r
+       },\r
+       pollZoom: function() {\r
+               var z = this.support.getZoomLevel();\r
+               //console.log(z);\r
+               $('html').attr('data-zoom', z);\r
+               if (z <= 1) {\r
+                       $("html").removeClass('pan');\r
+               } else {\r
+                       $("html").addClass('pan');\r
+               }\r
+       },\r
+       intentShare: function(subject, body) {\r
+               if (subject == undefined) {\r
+                       subject = this.datas.title;\r
+               }\r
+               if (body == undefined) {\r
+                       body = this.datas.title + ' : ' + this.getLocationToShare();\r
+               }\r
+\r
+               if (this.datas.phonegap == 'android') {\r
+                       var extras = {};\r
+                       extras[WebIntent.EXTRA_SUBJECT] = subject;\r
+                       extras[WebIntent.EXTRA_TEXT] = body;\r
+                       window.webintent.startActivity({\r
+                               action: WebIntent.ACTION_SEND,\r
+                               type: 'text/plain',\r
+                               extras: extras\r
+                       }, function(args) {\r
+                       }, function(args) {\r
+                       });\r
+               } else {\r
+                       window.location = 'mailto:?subject=' + subject + '&body=' + body;\r
+               }\r
+               this.stats.track(5);\r
+       },\r
+       wopen: function(url, target, options) {\r
+               if (target == undefined) {\r
+                       target = '_self';\r
+               }\r
+               if (options == undefined) {\r
+                       options = '';\r
+               }\r
+\r
+               var locationdefault = 'yes';\r
+               if (this.datas.phonegap) {\r
+                       locationdefault = 'no';\r
+               }\r
+\r
+               if (options == '') {\r
+                       options = 'location=' + locationdefault;\r
+               } else if (options.indexOf('location=') == -1) {\r
+                       options += ',location=' + locationdefault;\r
+               }\r
+               window.open(url, target, options);\r
+       }\r
+}\r
diff --git a/js/libs/fluidbook/fluidbook.l10n.js b/js/libs/fluidbook/fluidbook.l10n.js
new file mode 100644 (file)
index 0000000..09da0a8
--- /dev/null
@@ -0,0 +1,65 @@
+function FluidbookL10N(fluidbook, lang) {
+       this.translations = {};
+       this.multilang = {};
+       this.multilangEnabled = false;
+       this.fluidbook = fluidbook;
+
+       this.load(lang);
+       this.initMultilang();
+}
+
+FluidbookL10N.prototype = {
+       load: function(lang) {
+               if (lang == undefined || lang == null || lang == '') {
+                       lang = 'default';
+               }
+               this.lang = lang;
+
+               this.translations = this.fluidbook.datas.l10n[lang];
+               this.updateTranslations();
+       },
+       getActiveLang: function() {
+               if (this.lang != 'default') {
+                       return this.lang;
+               }
+               return this.fluidbook.datas.defaultLang;
+       },
+       initMultilang: function() {
+               if (this.fluidbook.datas.multilang == '') {
+                       return;
+               }
+               this.multilangEnabled = true;
+               var $this = this;
+               var ml = this.fluidbook.datas.multilang.replace(/\r/g, "\n").replace(/\n+/g, "\n");
+
+               var e = ml.split("\n");
+               $.each(e, function(k, v) {
+                       var l = v.split(',');
+                       var o = {lang: l[0], flag: l[1], url: l[2], name: l[3]};
+                       $this.multilang[l[0]] = o;
+               });
+       },
+       updateTranslations: function() {
+               var $this = this;
+               $("#q").attr('placeholder', this.__('search'));
+               $("i.l10n").each(function() {
+                       var t = $this.fluidbook.l10n.__($(this).attr('str'));
+                       $(this).replaceWith(t);
+               });
+       },
+       __: function(str, markupIfNonAvailable) {
+               if (str.substr(0, 1) == '!') {
+                       return str.substr(1);
+               }
+
+
+               if (this.translations[str] == undefined || this.translations[str] == null || this.translations[str] == '') {
+                       if (markupIfNonAvailable == undefined || markupIfNonAvailable) {
+                               return '<i class="l10n" str="' + str + '">~ ' + str + ' ~</i>';
+                       } else {
+                               return str;
+                       }
+               }
+               return this.translations[str];
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.loader.js b/js/libs/fluidbook/fluidbook.loader.js
new file mode 100644 (file)
index 0000000..3859afb
--- /dev/null
@@ -0,0 +1,247 @@
+function FluidbookLoader(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.texts = [];
+       this.backgrounds = [];
+       this.links = [];
+       this.toPreload = [];
+       this.numPreload = 6;
+       if (this.fluidbook.imagesVersion) {
+               this.numPreload += 6;
+       }
+}
+
+FluidbookLoader.prototype = {
+       preloadPagesBeforeTransition: function(pages, callback) {
+               var $this = this;
+               if (pages.length == 0) {
+                       callback();
+                       return;
+               }
+               var $pages = pages;
+               var $callback = callback;
+               var $page = pages.shift();
+               if ($page > this.fluidbook.datas.pages || $page < 1) {
+                       $this.preloadPagesBeforeTransition($pages, $callback);
+                       return;
+               }
+               this._loadBackground($page, function() {
+                       if ($this.fluidbook.vectorsVersion) {
+                               $this._loadTexts($page, function() {
+                                       $this.preloadPagesBeforeTransition($pages, $callback);
+                               });
+                       } else {
+                               $this.preloadPagesBeforeTransition($pages, $callback);
+                       }
+               })
+       },
+       preloadPages: function() {
+               if (this.toPreload.length == 0) {
+                       return;
+               }
+
+               var $this = this;
+               var preloadingPage = this.toPreload.shift();
+
+               if (this.backgrounds[preloadingPage] != undefined) {
+                       $this.preloadPages();
+                       return;
+               }
+
+               var imgback = new Image();
+               $(imgback).one('load', function() {
+                       if ($this.fluidbook.vectorTexts) {
+                               $this._loadTexts(preloadingPage, function() {
+                                       $this.preloadPages();
+                               });
+                       } else {
+                               $this.preloadPages();
+                       }
+               });
+               imgback.src = this.getBackgroundURL(preloadingPage);
+               this.backgrounds[preloadingPage] = imgback;
+       },
+       preloadAround: function(page) {
+               var min = Math.max(1, page - 1);
+               var max = Math.min(min + this.numPreload, this.fluidbook.datas.pages);
+               min = max - (this.numPreload);
+               this.toPreload = [];
+               for (var i = min; i <= max; i++) {
+                       this.toPreload.push(i);
+               }
+
+               this.cleanPreloaded();
+               this.preloadPages();
+       },
+       cleanPreloaded: function() {
+               for (var i = 1; i <= this.fluidbook.datas.pages; i++) {
+                       if (this.backgrounds[i] != undefined && this.toPreload.indexOf(i) == -1) {
+                               this.deletePage(i);
+                       }
+               }
+       },
+       deletePage: function(page) {
+               delete this.backgrounds[page];
+               delete this.texts[page];
+               delete this.links[page];
+       },
+       setContentsInDoublePage: function(doublePage, pages, immediate, callback) {
+               var $this = this;
+
+               var leftPage = pages[0];
+               var rightPage = pages[1];
+
+               if (!immediate) {
+                       this.loadLeftPage(leftPage, $(doublePage), function() {
+                               $this.loadRightPage(rightPage, $(doublePage), callback);
+                       })
+
+               } else {
+                       this.loadLeftPage(leftPage, $(doublePage), function() {
+                       })
+                       this.loadRightPage(rightPage, $(doublePage), function() {
+                       });
+                       callback();
+               }
+       },
+       loadPage: function(pageNr, doublePage, position, callback) {
+               // Si une page de gauche existe déjà dans la double page, on la retire
+               $(doublePage).find('.' + position).each(function() {
+                       if ($(this).attr('id') != 'page_' + pageNr || pageNr == 0) {
+                               $(this).remove();
+                       }
+               })
+
+               var page;
+               var shade;
+               // Si la page existe déjà, on la place à la bonne position et on l'affiche
+               if ($("#page_" + pageNr).length > 0) {
+                       page = $("#page_" + pageNr);
+                       if ($(doublePage).find("#page_" + pageNr).length == 0) {
+                               $(doublePage).append(page);
+                       }
+                       if (!$(page).hasClass(position)) {
+                               if (position == 'left') {
+                                       $(page).removeClass('right');
+                               }
+                               else {
+                                       $(page).removeClass('left');
+                               }
+                               $(page).addClass(position);
+                       }
+                       if (!$(page).is(':visible')) {
+                               $(page).show();
+                       }
+                       shade = 'shade' + position;
+                       if (this.fluidbook.datas.pageReflection) {
+                               shade += '-reflet';
+                       }
+                       shade += '.png';
+
+                       $(page).children(".shade").html('<img src="images/' + shade + '" width="' + (this.fluidbook.datas.width / 4) + '" height="' + this.fluidbook.datas.height + '" />');
+                       $(page).children('.clinks').html(this.fluidbook.datas.clinks[pageNr]);
+                       this.fluidbook.highlightSearchTerms(pageNr);
+                       callback();
+                       return;
+               }
+
+               this.fluidbook.initPage(pageNr, doublePage, position);
+               page = $("#page_" + pageNr);
+               $(doublePage).append(page);
+               $(page).show();
+               $(page).addClass(position);
+               var back = $(page).children(".background")[0];
+               this.loadDatas(pageNr, callback);
+               $(page).addClass(position);
+
+               shade = 'shade' + position;
+               if (this.fluidbook.datas.pageReflection) {
+                       shade += '-reflet';
+               }
+               shade += '.png';
+               $(page).children('.clinks').html(this.fluidbook.datas.clinks[pageNr]);
+               $(page).children(".shade").html('<img src="images/' + shade + '" width="' + (this.fluidbook.datas.width / 4) + '" height="' + this.fluidbook.datas.height + '" />');
+},
+       loadLeftPage: function(page, doublePage, callback) {
+               if (page > 0) {
+                       this.loadPage(page, doublePage, 'left', callback);
+               } else {
+                       $(doublePage).find('.left').remove();
+                       callback();
+               }
+       },
+       loadRightPage: function(page, doublePage, callback) {
+               if (!this.fluidbook.displayOnePage && page <= this.fluidbook.datas.pages) {
+                       this.loadPage(page, doublePage, 'right', callback);
+               } else {
+                       $(doublePage).find('.right').remove();
+                       callback();
+               }
+},
+       getBackgroundURL: function(page) {
+               var prefix = 'p';
+               if (this.fluidbook.imagesVersion) {
+                       prefix = 't';
+               }
+
+               return 'data/background/150/' + prefix + page + '.jpg';
+       },
+       getTextsURL: function(page) {
+               return 'data/contents/p' + page + '.svg';
+       },
+       setBackground: function(page, callback) {
+               var $this = this;
+               var back = $("#page_" + page + ' .background');
+               this._loadBackground(page, function() {
+                       $(back).addClass('r150');
+                       $(back).append($this.backgrounds[page]);
+               });
+       },
+       _loadBackground: function(page, callback) {
+               if (this.backgrounds[page] != undefined) {
+                       callback();
+               } else {
+                       var img = new Image();
+                       $(img).one('load', function() {
+                               callback();
+                       });
+                       img.src = this.getBackgroundURL(page);
+                       this.backgrounds[page] = img;
+               }
+       },
+       loadTexts: function(pageNr, callback) {
+               if (this.fluidbook.imagesVersion) {
+                       callback();
+                       return;
+               }
+
+               if (this.texts[pageNr] != undefined) {
+                       $("#page_" + pageNr + ' .texts').append(this.texts[pageNr]);
+                       callback();
+               } else {
+                       this._loadTexts(pageNr, function() {
+                               var content;
+                               content = this;
+                               $("#page_" + pageNr + ' .texts').append(content);
+                               callback();
+                       });
+               }
+       },
+       _loadTexts: function(pageNr, callback) {
+               var w = this.fluidbook.datas.width / 0.75;
+               var h = this.fluidbook.datas.height / 0.75;
+
+               var img = new Image();
+               img.width = w * 2;
+               img.height = h * 2;
+               img.type = 'image/svg+xml';
+               $(img).one('load', callback);
+               img.src = this.getTextsURL(pageNr);
+               this.texts[pageNr] = img;
+       },
+       loadDatas: function(pageNr, callback) {
+               var $this = this;
+               this.loadTexts(pageNr, function() {
+                       $this.setBackground(pageNr, callback);
+               });
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.nav.js b/js/libs/fluidbook/fluidbook.nav.js
new file mode 100644 (file)
index 0000000..17b3ac6
--- /dev/null
@@ -0,0 +1,186 @@
+function FluidbookNav(fluidbook) {
+       this.fluidbook = fluidbook;
+       this._dimensions = this.fluidbook.datas.iconsDimensions;
+
+       this.setNav();
+}
+
+FluidbookNav.prototype = {
+       getIcon: function(name) {
+               var src = 'data/images/' + name + '.';
+               if (this.fluidbook.support.SVG) {
+                       src += 'svg';
+               } else {
+                       src += 'png';
+               }
+               if (this._dimensions[name] == undefined) {
+                       return '';
+               }
+
+               return '<img src="' + src + '" height="' + this._dimensions[name][1] + '" width="' + this._dimensions[name][0] + '" />';
+       },
+       addLink: function(name, href, id, help, before, c) {
+               if ($("#nav").find('#' + id).length > 0) {
+                       return;
+               }
+               var l = this.getLink(name, href, id, help, c);
+               if (before == undefined) {
+                       $("#nav").append(l);
+               } else {
+                       $("#nav #" + before).before(l);
+               }
+       },
+       getLink: function(name, href, id, help, className) {
+               var res = '<a href="' + href + '"';
+               if (id != undefined) {
+                       res += ' id="' + id + '"';
+               }
+               if (className != undefined) {
+                       res += ' class="' + className + '"';
+               }
+               res += ' help="' + help + '"';
+               res += '>';
+               res += this.getIcon(name);
+               res += '</a>';
+               return res;
+       },
+       setNav: function() {
+               /*
+                * __('overview')
+                * __('chapters')
+                * __('tell a friend')
+                * __('share on facebook') 
+                * __('share on twitter')
+                * __('home')
+                */
+               var $this = this;
+               // index, chapters, print, friend, bookmark, pdf, archives, basket, fullscreen, sound, 3d, help
+               for (var e in this.fluidbook.datas.navOrder) {
+                       var icon = this.fluidbook.datas.navOrder[e];
+                       if (icon == 'home') {
+                               if (this.fluidbook.datas.home != '') {
+                                       this.addLink('nav-home', this.fluidbook.datas.home, 'home', 'home');
+                               }
+                       } else if (icon == 'index') {
+                               this.addLink('nav-index', '#/index', 'index', 'overview');
+                       } else if (icon == 'chapters') {
+                               if (this.fluidbook.datas.displayChaptersIcon) {
+                                       if (this.fluidbook.datas.chaptersPage != '') {
+                                               this.addLink('nav-sommaire', '#/page/' + this.fluidbook.datas.chaptersPage, 'chapters', 'chapters');
+                                       } else if (this.fluidbook.datas.chapters.length > 0) {
+                                               this.addLink('nav-sommaire', '#/chapters', 'chapters', 'chapters');
+                                       }
+                               }
+                       } else if (icon == 'friend') {
+                               if (this.fluidbook.datas.share) {
+                                       this.addLink('nav-friend', '#/share', 'share', 'share');
+                                       $("#share").click(function() {
+                                               if ($this.fluidbook.datas.phonegap != 'android') {
+                                                       return true;
+                                               }
+                                               $this.fluidbook.intentShare();
+                                               return false;
+                                       });
+                               }
+                       } else if (icon == 'bookmark') {
+                               if (this.fluidbook.datas.bookmark) {
+                                       this.addLink('nav-bookmark', '#/bookmark', 'bookmarks', 'bookmarks');
+                               }
+                       } else if (icon == 'pdf' || icon == 'print') {
+                               if (this.fluidbook.datas.print || this.fluidbook.datas.pdf) {
+                                       this.addLink('nav-print', '#', 'print', '!' + this.fluidbook.l10n.__('print') + ' | ' + this.fluidbook.l10n.__('download pdf'));
+                                       $("#print").click(function() {
+                                               $this.fluidbook.print();
+                                               return false;
+                                       });
+                               }
+                       } else if (icon == 'lang') {
+                               if (this.fluidbook.l10n.multilangEnabled) {
+                                       this.addMultilangLink();
+                               }
+                       } else if (icon == 'archives') {
+                               if (this.fluidbook.datas.archivesLink != '') {
+                                       this.addLink('nav-archives', this.fluidbook.datas.archivesLink, 'archives', '!' + this.fluidbook.datas.archivesLabel);
+                               } else if (this.fluidbook.datas.externalArchives != '') {
+                                       this.addLink('nav-archives', '#/archives', 'archives', '!' + this.fluidbook.datas.archivesLabel);
+                               }
+                       } else if (icon == 'help') {
+                               this.addLink('nav-help', '#', 'help', '');
+                       }
+               }
+
+               if (this.fluidbook.datas.search) {
+                       this.setSearch();
+               }
+               if (this.fluidbook.datas.afterSearch != '') {
+                       this.setAfterSearch();
+               }
+               this.setInterface();
+       },
+       addMultilangLink: function(langs) {
+               var l = '<a id="locales" help="!Select language" href="#/locales"></a>';
+
+               var flag = this.fluidbook.l10n.multilang[this.fluidbook.l10n.getActiveLang()].flag;
+
+               $("#nav").append(l);
+               $("#nav #locales").css('background-image', 'url("images/flags/' + flag + '.png")');
+       },
+       setSearch: function() {
+               var $this = this;
+
+               var res = '<form action="#" id="searchForm" method="post">';
+               res += '<input type="text" id="q" name="q" type="search" value="" placeholder="' + this.fluidbook.l10n.__('search') + '" autocorrect="off" autocomplete="off" autocapitalize="off" />';
+               res += this.getLink('interface-search', '#', 'submitSearch');
+               res += '<div id="searchHints"></div>';
+               res += '</form>';
+
+               $("#search").append(res);
+
+               $("#submitSearch").click(function() {
+                       $("#searchForm").submit();
+                       return false;
+               })
+
+               // Search form  
+               $("#searchForm").submit(function() {
+                       var q = $("#q").val();
+                       if (q == '') {
+                               return false;
+                       }
+                       window.location.hash = '/search/' + q;
+                       return false;
+               });
+
+               $("#q").keyup(searchHints);
+
+               $(document).on('click', ".hint", function() {
+                       var e = $("#q").val().split(' ');
+                       e.pop();
+                       e.push($(this).attr('term'));
+                       $("#q").val(e.join(' '));
+                       $("#searchForm").submit();
+                       return false;
+               })
+
+               $("#q").blur(function(e) {
+                       setTimeout(function() {
+                               $this.fluidbook.hideSearchHints();
+                       }, 250);
+               });
+
+               $("#nav").append($("#search"));
+       },
+       setAfterSearch: function() {
+               $("#nav").append('<div id="afterSearch"><div class="c"><img src="data/images/' + this.fluidbook.datas.afterSearch + '" /></div><div class="links">' + this.fluidbook.datas.links.aftersearch + '</div></div>');
+       },
+       setInterface: function() {
+
+               var res = this.getLink('interface-previous', '#', 'previous', '', 'hidden');
+               res += this.getLink('interface-next', '#', 'next');
+
+               $('#interface').append(res);
+
+               $(document).on('click', '#next', goNextPage);
+               $(document).on('click', '#previous', goPreviousPage);
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.pad.js b/js/libs/fluidbook/fluidbook.pad.js
new file mode 100644 (file)
index 0000000..ac134ba
--- /dev/null
@@ -0,0 +1,73 @@
+function FluidbookPad(fluidbook) {\r
+       this.fluidbook = fluidbook;\r
+       this.enabled = this.fluidbook.datas.mobileNavigationType == 'tab';\r
+       this.tapHoldTimeout;\r
+       this.visibleTimeout;\r
+       this.visibleTime = 5000;\r
+       this.interfaceVisible = false;\r
+       if (this.enabled) {\r
+               this.init();\r
+       }\r
+}\r
+\r
+FluidbookPad.prototype = {\r
+       init: function() {\r
+               this.initEvents();\r
+\r
+       },\r
+       initEvents: function() {\r
+               var $this = this;\r
+               $(document).on('click', '#down', function() {\r
+                       if ($(this).hasClass('right')) {\r
+                               $this.fluidbook.goNextChapter();\r
+                       } else {\r
+                               $this.fluidbook.goNextChapterPage();\r
+                       }\r
+                       return false;\r
+               });\r
+\r
+               $(document).on('click', '.nonlinkarea', function() {\r
+                       $this.toggleInterface();\r
+                       return false;\r
+               });\r
+       },\r
+       toggleInterface: function() {\r
+               if (this.interfaceVisible) {\r
+                       return this.hideInterface();\r
+               } else {\r
+                       return this.displayInterface();\r
+               }\r
+       },\r
+       displayInterface: function() {\r
+               this.interfaceVisible = true;\r
+               $("header,#interface").css({visibility: 'visible', opacity: 1});\r
+               this.resetTimeout();\r
+       },\r
+       resetTimeout: function() {\r
+               var $this = this;\r
+               this.clearTimeout();\r
+               this.visibleTimeout = setTimeout(function() {\r
+                       $this.hideInterface();\r
+               }, this.visibleTime);\r
+       },\r
+       hideInterface: function() {\r
+               this.interfaceVisible = false;\r
+               if ($("#helpView").is(':visible') || document.activeElement.tagName.toLowerCase() === 'input') {\r
+                       this.resetTimeout();\r
+                       return;\r
+               }\r
+               $("header,#interface").css({opacity: 0}).delay(1100).css('visibility', 'hidden');\r
+               this.clearTimeout();\r
+       },\r
+       clearTimeout: function() {\r
+               clearTimeout(this.visibleTimeout);\r
+       },\r
+       getTransitionAxis: function(currentPage, nextPage) {\r
+               var linkedPages = this.fluidbook.bookmarks.getLinkedPages(currentPage);\r
+               if (linkedPages.indexOf(nextPage) == -1) {\r
+                       return 'x';\r
+               }\r
+               return 'y';\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.resize.js b/js/libs/fluidbook/fluidbook.resize.js
new file mode 100644 (file)
index 0000000..026bc9a
--- /dev/null
@@ -0,0 +1,269 @@
+function FluidbookResize(fluidbook) {\r
+       this.fluidbook = fluidbook;\r
+       this.marginw = 50;\r
+       this.marginh = 20;\r
+       this.corr = 0.8;\r
+       this.referenceWidthLandscape = 1024;\r
+       this.referenceWidthPortrait = 600;\r
+       this.referenceHeight = 600;\r
+       this.orientation = '';\r
+       this.textScale = 2;\r
+       this.bookScale = 1;\r
+       this.ww = $(window).width();\r
+       this.hh = $(window).height();\r
+       this.init();\r
+       this.navresizeTimeout = 0;\r
+}\r
+\r
+FluidbookResize.prototype = {\r
+       init: function() {\r
+               $("#nav").transform({\r
+                       origin: ['0%', '0%']\r
+               });\r
+\r
+               $("#logo").transform({\r
+                       origin: ['100%', '0%']\r
+               });\r
+\r
+               $("#footer").transform({\r
+                       origin: ['100%', '100%']\r
+               });\r
+\r
+               $("#next").transform({\r
+                       origin: ['100%', '50%']\r
+               });\r
+\r
+               $("#previous").transform({\r
+                       origin: ['0%', '50%']\r
+               });\r
+       },\r
+       resize: function(init) {\r
+               if (init == undefined || init == null) {\r
+                       init = false;\r
+               }\r
+\r
+               var $this = this;\r
+               this.updateWindow();\r
+               this.handleOrientation();\r
+\r
+               var interfaceScale;\r
+               if (this.orientation == 'landscape') {\r
+                       interfaceScale = Math.min(1, this.ww / this.referenceWidthLandscape, this.hh / this.referenceHeight);\r
+               } else if (this.orientation == 'portrait') {\r
+                       interfaceScale = Math.min(1, this.ww / this.referenceWidthPortrait, this.hh / this.referenceHeight);\r
+               }\r
+               var navScale = interfaceScale * parseInt(this.fluidbook.datas.mobileNavScale) / 100;\r
+               var cssInterfaceScale = [interfaceScale, interfaceScale];\r
+               var cssNavScale = [navScale, navScale];\r
+\r
+\r
+               $("#main").css({\r
+                       width: this.ww,\r
+                       height: this.hh\r
+               });\r
+\r
+               this.resizeView();\r
+\r
+               $("#next").css({\r
+                       right: 0\r
+               });\r
+\r
+               var marginY, marginX, marginTop, marginBottom, marginLeft, marginRight;\r
+\r
+               if (this.fluidbook.pad.enabled) {\r
+                       marginY = 0;\r
+                       marginX = 0;\r
+                       extraX = 0;\r
+                       marginTop = 0;\r
+                       marginBottom = 0;\r
+                       marginLeft = 0;\r
+                       marginRight = 0;\r
+               } else {\r
+                       marginX = 50;\r
+                       marginY = 20;\r
+\r
+                       var extraX = parseInt(this.fluidbook.datas.mobileExtraXSpace);\r
+                       if (isNaN(extraX)) {\r
+                               extraX = 0;\r
+                       }\r
+\r
+                       marginTop = (this.fluidbook.datas.menuHeight + marginY) * interfaceScale;\r
+                       marginBottom = (10 + marginY) * interfaceScale;\r
+                       marginLeft = (marginX + extraX) * interfaceScale;\r
+                       marginRight = marginLeft;\r
+               }\r
+\r
+               var aw = this.ww - marginLeft - marginRight;\r
+               var ah = this.hh - marginTop - marginBottom;\r
+               var fhh = this.fluidbook.datas.height;\r
+               var fww = this.fluidbook.datas.width;\r
+               if (this.orientation == 'landscape') {\r
+                       fww *= 2;\r
+               }\r
+\r
+               this.bookScale = Math.min(aw / fww, ah / fhh);\r
+               var fw = this.bookScale * fww;\r
+               var fh = this.bookScale * fhh;\r
+               $("#fluidbook").transform({\r
+                       scale: [this.bookScale, this.bookScale],\r
+                       origin: ['50%', '50%']\r
+               });\r
+               $("#fluidbook").css({\r
+                       top: marginTop + (ah - fhh) / 2,\r
+                       left: marginLeft + (aw - fww) / 2,\r
+                       width: fww,\r
+                       height: fhh\r
+               });\r
+\r
+\r
+               $("#next,#previous").transform({\r
+                       scale: cssInterfaceScale\r
+               });\r
+\r
+               $("#nav,#logo,footer").transform({\r
+                       scale: navScale\r
+               });\r
+\r
+               var headerHeight = this.fluidbook.datas.menuHeight * navScale;\r
+               $('header').css({\r
+                       height: headerHeight,\r
+                       backgroundSize: '100% ' + headerHeight + 'px'\r
+               });\r
+\r
+               this.refw = fw;\r
+               this.refh = fh;\r
+\r
+               this.fluidbook.help.resize(this.ww, this.hh, interfaceScale, navScale);\r
+               this.fluidbook.coquillette.resize(this.ww, this.hh);\r
+               this.fluidbook.background.resize(this.ww, this.hh);\r
+\r
+               var timeout = 0;\r
+               if (this.fluidbook.support.android) {\r
+                       timeout = 1000;\r
+               }\r
+\r
+               if (timeout > 0) {\r
+                       $("#next,#previous").hide();\r
+                       clearTimeout(this.navresizeTimeout);\r
+                       this.navresizeTimeout = setTimeout(function() {\r
+                               $this.resizeNav(interfaceScale)\r
+                       }, timeout);\r
+               } else {\r
+                       this.resizeNav(interfaceScale);\r
+               }\r
+\r
+               this.resizePopupVideos();\r
+               this.resizeSplash();\r
+       },\r
+       resizeNav: function(interfaceScale) {\r
+               var topNext = (this.hh - 100 * interfaceScale) / 2;\r
+               $("#next,#previous").css({\r
+                       top: topNext\r
+               });\r
+               $("#next,#previous").show();\r
+       },\r
+       resizePopupVideos: function() {\r
+               var maxh = this.hh - 80;\r
+               $(".mview .videoContainer video").each(function() {\r
+                       var w = $(window).width() - 40;\r
+\r
+                       var ratio = parseInt($(this).attr('data-width')) / parseInt($(this).attr('data-height'));\r
+                       var h = w / ratio;\r
+                       $(this).css({\r
+                               height: h,\r
+                               maxHeight: maxh\r
+                       });\r
+               });\r
+       },\r
+       resizeSplash: function() {\r
+               $("#splash").css({\r
+                       width: this.ww,\r
+                       height: this.hh\r
+               });\r
+\r
+               if ($("#splash").css('opacity') == 0) {\r
+                       $("#splash").css('opacity', 1);\r
+               }\r
+\r
+               var lw = $("#splash .logo").width();\r
+               var lh = $("#splash .logo").height();\r
+\r
+               $("#splash .logo").css({\r
+                       top: (this.hh / 2) - 30 - lh - 10,\r
+                       left: (this.ww - lw) / 2\r
+               });\r
+       },\r
+       updateWindow: function() {\r
+               this.ww = $(window).width();\r
+               this.hh = $(window).height();\r
+       },\r
+       resizeView: function() {\r
+               var $this = this;\r
+               this.updateWindow();\r
+\r
+               $(".mview").css({\r
+                       width: this.ww,\r
+                       minHeight: this.hh,\r
+                       maxHeight: this.hh,\r
+                       height: this.hh\r
+               });\r
+\r
+               $(".mview").find('.caption,.content').css({\r
+                       width: this.ww\r
+               });\r
+\r
+\r
+               $(".mview .caption h2").each(function() {\r
+                       var wavailable = $this.ww;\r
+                       $(this).parent().find('a.back').each(function() {\r
+                               wavailable -= ($(this).outerWidth() + 10) * 2;\r
+                       });\r
+                       $(this).css('max-width', wavailable);\r
+               });\r
+\r
+               if ($("#archivesview").length == 1) {\r
+                       var w = this.fluidbook.datas.filesInfos.archives.width;\r
+                       var ratio = $("#archivesview img").width() / w;\r
+                       $("#archivesview .links").transform({scale: [ratio]});\r
+               }\r
+\r
+               $(".bookmarkView").each(function() {\r
+                       var w = $(this).parent().width();\r
+                       var perCol = Math.floor(w / 120);\r
+\r
+                       var uw = perCol * 120;\r
+                       var m = (w - uw) / 2;\r
+                       $(this).css({\r
+                               width: uw,\r
+                               margin: '0 auto'\r
+                       })\r
+               });\r
+       },\r
+       handleOrientation: function() {\r
+               var changeOrientation = this.orientation != '';\r
+               var o = this.fluidbook.support.getOrientation();\r
+               var newo;\r
+               if (o == 0 || o == 180) {\r
+                       newo = 'portrait';\r
+                       $('body').removeClass('landscape');\r
+               } else {\r
+                       newo = 'landscape';\r
+                       $('body').removeClass('portrait');\r
+               }\r
+\r
+               if (this.orientation == newo) {\r
+                       return;\r
+               }\r
+               this.orientation = newo;\r
+\r
+               $('body').addClass(this.orientation);\r
+\r
+               this.fluidbook.displayOnePage = (this.orientation == 'portrait');\r
+\r
+               if (changeOrientation) {\r
+                       this.fluidbook.resetZoom();\r
+                       this.fluidbook.pageTransition();\r
+               }\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.search.js b/js/libs/fluidbook/fluidbook.search.js
new file mode 100644 (file)
index 0000000..8b50d20
--- /dev/null
@@ -0,0 +1,109 @@
+function FluidbookSearch() {\r
+}\r
+\r
+FluidbookSearch.prototype = {\r
+       getHints: function(q) {\r
+               var words = this.normalizeQuery(q);\r
+               q = words.pop();\r
+               var res = [];\r
+\r
+               if (q.length < 3) {\r
+                       return res;\r
+               }\r
+\r
+               var v;\r
+               for (var k in INDEX) {\r
+                       v = INDEX[k];\r
+                       if (k.indexOf(q) != 0) {\r
+                               continue;\r
+                       }\r
+                       res.push([k, v.t]);\r
+               }\r
+\r
+               res.sort(this.sortHints);\r
+               return res.slice(0, 12);\r
+       },\r
+       find: function(q) {\r
+               var words = this.normalizeQuery(q);\r
+\r
+               var res = {};\r
+               var terms = [];\r
+               var total=0;\r
+\r
+               var q, v, k, kk, word, wordata, page, occurences;\r
+               for (kk in words) {\r
+                       q = words[kk];\r
+\r
+                       for (k in INDEX) {\r
+                               v = INDEX[k];\r
+                               if (k.indexOf(q) != 0) {\r
+                                       continue;\r
+                               }\r
+                               for (word in v.w) {\r
+                                       wordata = v.w[word];\r
+                                       terms.push(word);\r
+                                       for (page in wordata.p) {\r
+\r
+                                               occurences = wordata.p[page];\r
+\r
+                                               page = parseInt(page);\r
+\r
+\r
+                                               if (res[page] == undefined) {\r
+                                                       res[page] = 0;\r
+                                               }\r
+                                               res[page] += occurences;\r
+                                               total+=occurences;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return {\r
+                       total:total,\r
+                       results: res,\r
+                       terms: terms.join(' ')\r
+               };\r
+       },\r
+       sortHints: function(a, b) {\r
+               return b[1] - a[1];\r
+       },\r
+       kill: function() {\r
+\r
+       },\r
+       normalizeQuery: function(q) {\r
+               q = this.noAccents(q);\r
+               q = q.toLowerCase();\r
+               return q.split(' ');\r
+       },\r
+       noAccents: function(source) {\r
+               source = source.replace(/[àáâãäå]/g, "a");\r
+               source = source.replace(/[ÀÁÂÃÄÅ]/g, "A");\r
+               source = source.replace(/[èéêë]/g, "e");\r
+               source = source.replace(/[ËÉÊÈ]/g, "E");\r
+               source = source.replace(/[ìíîï]/g, "i");\r
+               source = source.replace(/[ÌÍÎÏ]/g, "I");\r
+               source = source.replace(/[ðòóôõöø]/g, "o");\r
+               source = source.replace(/[ÐÒÓÔÕÖØ]/g, "O");\r
+               source = source.replace(/[ùúûü]/g, "u");\r
+               source = source.replace(/[ÙÚÛÜ]/g, "U");\r
+               source = source.replace(/[ýýÿ]/g, "y");\r
+               source = source.replace(/[ÝÝŸ]/g, "Y");\r
+               source = source.replace(/[ç]/g, "c");\r
+               source = source.replace(/[Ç]/g, "C");\r
+               source = source.replace(/[ñ]/g, "n");\r
+               source = source.replace(/[Ñ]/g, "N");\r
+               source = source.replace(/[š]/g, "s");\r
+               source = source.replace(/[Š]/g, "S");\r
+               source = source.replace(/[ž]/g, "z");\r
+               source = source.replace(/[Ž]/g, "Z");\r
+               source = source.replace(/[æ]/g, "ae");\r
+               source = source.replace(/[Æ]/g, "AE");\r
+               source = source.replace(/[œ]/g, "oe");\r
+               source = source.replace(/[Œ]/g, "OE");\r
+               return source;\r
+\r
+       }\r
+};\r
+\r
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.service.js b/js/libs/fluidbook/fluidbook.service.js
new file mode 100644 (file)
index 0000000..ce53aa6
--- /dev/null
@@ -0,0 +1,30 @@
+function FluidbookService(fluidbook, id) {
+       this.fluidbook = fluidbook;
+       this.baseURL = 'http://workshop.fluidbook.com/services/';
+       this.id = id;
+}
+
+FluidbookService.prototype = {
+       call: function(func, datas, handler, context) {
+               datas['id'] = this.id;
+               return $.ajax({
+                       url: this.baseURL + func,
+                       context: context,
+                       format: 'xml',
+                       crossDomain: true,
+                       data: datas,
+                       success: function(data) {
+                               handler.call(this, data)
+                       }
+               });
+       },
+       open: function(func, datas) {
+               datas['id'] = this.id;
+               var u = [];
+               $.each(datas, function(k, v) {
+                       u.push(k + '=' + encodeURIComponent(v));
+               });
+               var url = this.baseURL + func + '?' + u.join('&');
+               this.fluidbook.wopen(url, '_blank');
+       }
+}
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.stats.js b/js/libs/fluidbook/fluidbook.stats.js
new file mode 100644 (file)
index 0000000..7cb5b8f
--- /dev/null
@@ -0,0 +1,66 @@
+function FluidbookStats(fluidbook) {\r
+       this.fluidbook = fluidbook;\r
+       this.id = this.fluidbook.datas.id;\r
+       this.init();\r
+}\r
+\r
+FluidbookStats.prototype = {\r
+       init: function() {\r
+               var $this = this;\r
+               $(document).on('click', 'a[data-track]', function() {\r
+                       $this.track(6, 0, $(this).attr('data-track'));\r
+                       return true;\r
+               });\r
+       },\r
+       trackPageChange: function() {\r
+               if (!this.fluidbook.support.hasNetwork()) {\r
+                       return;\r
+               }\r
+               try {\r
+                       if (_gaq == undefined) {\r
+                               return;\r
+                       }\r
+                       var page = location.pathname + location.search + location.hash;\r
+                       if (_gatrackers != undefined) {\r
+                               $.each(_gatrackers, function(k, v) {\r
+                                       _gaq.push([v + '._trackPageview', page]);\r
+                               });\r
+                       } else {\r
+                               _gaq.push(['_trackPageview', page]);\r
+                       }\r
+               } catch (err) {\r
+\r
+               }\r
+       },\r
+       track: function(type, page, extra) {\r
+               if (!this.fluidbook.support.hasNetwork()) {\r
+                       return;\r
+               }\r
+\r
+               if (page == undefined) {\r
+                       page = 0;\r
+               }\r
+               if (extra == undefined) {\r
+                       extra = '';\r
+               }\r
+\r
+               $.ajax({\r
+                       url: 'http://stats.fluidbook.com/stats2.php',\r
+                       type: 'GET',\r
+                       data: {\r
+                               id: this.id,\r
+                               type: type,\r
+                               page: page,\r
+                               str: extra,\r
+                               time: new Date().getTime()\r
+                       },\r
+                       success: function() {\r
+\r
+                       },\r
+                       error: function() {\r
+\r
+                       }\r
+               });\r
+       }\r
+};\r
+\r
diff --git a/js/libs/fluidbook/fluidbook.support.js b/js/libs/fluidbook/fluidbook.support.js
new file mode 100644 (file)
index 0000000..cb4189a
--- /dev/null
@@ -0,0 +1,130 @@
+function FluidbookSupport(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.userAgent = navigator.userAgent;
+       this.android = this.fitScreenAtZero = this.userAgent.search(/android/i) > -1 || this.userAgent.search(/galaxy/i) > -1;
+       this.android3 = this.android && this.userAgent.search(/android 3/i) > -1;
+       this.iOS = this.userAgent.search(/ipad/i) > -1 || this.userAgent.search(/iphone/i) > -1 || this.userAgent.search(/ipod/i) > -1;
+
+       this.transitions3d = Modernizr.csstransforms3d && Modernizr.csstransitions && Modernizr.csstransformspreserve3d;
+       this.transitions2d = Modernizr.csstransforms && Modernizr.csstransitions;
+       this.transitionendevents = ['transitionEnd', 'transitionend', 'mozTransitionEnd', 'webkitTransitionEnd', 'oTransitionEnd', 'msTransitionEnd'].join(' ');
+
+       this.initialResolution = 150;
+       
+       this.isMobile = isMobile();
+       this.SVG = Modernizr.svg && this.fluidbook.datas.mobileIconVector;
+
+       this._orientation = this.getOrientation();
+       this.initialZoomPortrait = 0;
+       this.initialZoomLandscape = 0;
+       var z = DetectZoom.zoom();
+       if (this._orientation == 0) {
+               this.initialZoomPortrait = z;
+       } else {
+               this.initialZoomLandscape = z;
+       }
+       this.initEvents();
+}
+
+FluidbookSupport.prototype = {
+       hasNetwork: function() {
+               if (navigator.onLine != undefined) {
+                       return navigator.onLine;
+               } else {
+                       return networkState() != 'none';
+               }
+       },
+       networkState: function() {
+               var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {
+                       type: 'unknown'
+               };
+               var t = connetion.type;
+
+               if (t == undefined) {
+                       t = 'unknown';
+               } else if (t == 0) {
+                       t = 'unknown';
+               } else if (t == 1) {
+                       t = 'ethernet';
+               } else if (t == 2) {
+                       t = 'wifi';
+               } else if (t == 3) {
+                       t = '2g';
+               } else if (t == 4) {
+                       t = '3g';
+               } else if (t == 5) {
+                       t = '4g';
+               } else {
+                       t = 'none';
+               }
+               return t;
+       },
+       initEvents: function() {
+
+               if (!this.isMobile) {
+                       $(window).resize(function() {
+                               resize();
+                       });
+                       return;
+               }
+
+               if ("onorientationchange" in window) {
+                       window.addEventListener('orientationchange', function() {
+                               if (this.iOS) {
+                                       resize();
+                               } else {
+                                       resize();
+                                       setTimeout(function() {
+                                               resize();
+                                       }, 750);
+                               }
+                       }, false);
+               } else {
+                       var $this = this;
+                       setInterval(function() {
+                               $this.checkOrientation();
+                       }, 100);
+               }
+
+       },
+       checkOrientation: function() {
+               var o = this.getOrientation();
+               if (o != this._orientation) {
+                       this._orientation = o;
+                       resize();
+               }
+       },
+       getOrientation: function() {
+               try {
+                       var mql = window.matchMedia("(orientation: portrait)");
+                       if (mql.matches) {
+                               return 0;
+                       } else {
+                               return 90;
+                       }
+               } catch (err) {
+
+               }
+               if ($("#op").is(':visible')) {
+                       return 0;
+               } else {
+                       return 90;
+               }
+       },
+       getZoomLevel: function() {
+               var tzoom = DetectZoom.zoom();
+               var iz;
+               if (this._orientation == 0) {
+                       iz=this.initialZoomPortrait;
+                       if(iz==0){
+                               iz=this.initialZoomPortrait=tzoom;
+                       }
+               }else{
+                       iz=this.initialZoomLandscape;
+                       if(iz==0){
+                               iz=this.initialZoomLandscape=tzoom;
+                       }
+               }
+               return tzoom / iz;
+       }
+}
diff --git a/js/libs/fluidbook/fluidbook.touch.js b/js/libs/fluidbook/fluidbook.touch.js
new file mode 100644 (file)
index 0000000..6140428
--- /dev/null
@@ -0,0 +1,219 @@
+function FluidbookTouch(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.scale = 1;
+
+       this.startX = 0;
+       this.startY = 0;
+       this.offsetX = 0;
+       this.offsetY = 0;
+
+       this.triggerOffset = 0.05;
+       this.triggered = false;
+       this.gesturing = false;
+
+       this.init();
+}
+
+FluidbookTouch.prototype = {
+       init: function() {
+               this.reset();
+
+               $(document).on('touchstart', $.proxy(this.start, this));
+               $(document).on('touchend', $.proxy(this.end, this));
+               $(document).on('touchmove', $.proxy(this.move, this));
+               $(document).on('touchcancel', $.proxy(this.cancel, this));
+               $(document).on('gesturestart', $.proxy(this.gesturestart, this));
+               $(document).on('gesturechange', $.proxy(this.gesturechange, this));
+               $(document).on('gestureend', $.proxy(this.gestureend, this));
+
+               $(document).on('MSPointerDown', $.proxy(this.msdown, this));
+               $(document).on('MSPointerUp', $.proxy(this.msup, this));
+               $(document).on('MSPointerMove', $.proxy(this.msmove, this));
+       },
+       msdown: function(event) {
+               var e = event.originalEvent;
+               if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) {
+                       return true;
+               }
+               this._start(e.screenX, e.screenY);
+               return true;
+       },
+       msup: function(event) {
+               var e = event.originalEvent;
+               if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) {
+                       return true;
+               }
+               this._end();
+       },
+       msmove: function(event) {
+               var e = event.originalEvent;
+               if (e.pointerType != e.MSPOINTER_TYPE_TOUCH) {
+                       return true;
+               }
+               return this._move(e.screenX, e.screenY);
+       },
+       allowMove: function() {
+               return !(this.fluidbook.support.getZoomLevel() <= 1 && !this.fluidbook.viewMode());
+       },
+       allowSlide: function() {
+               return !(this.gesturing || this.fluidbook.support.getZoomLevel() > 1 || this.fluidbook.viewMode());
+       },
+       reset: function() {
+               this.startX = 0;
+               this.startY = 0;
+               this.offsetX = 0;
+               this.offsetY = 0;
+               this.triggered = false;
+       },
+       gesturestart: function(event) {
+               if (this.fluidbook.pad.enabled) {
+                       return false;
+               }
+               var e = event.originalEvent;
+               this.enableUserScale();
+               this.gesturing = true;
+               return true;
+       },
+       gesturechange: function(event) {
+               if (this.fluidbook.pad.enabled) {
+                       return false;
+               }
+               var e = event.originalEvent;
+               this.gesturing = true;
+               return true;
+       },
+       gestureend: function(event) {
+               if (this.fluidbook.pad.enabled) {
+                       return false;
+               }
+
+               var e = event.originalEvent;
+               this.gesturing = false;
+
+               if (DetectZoom.zoom() > 1) {
+                       $('html').addClass('nopan');
+               } else {
+                       $('html').removeClass('nopan');
+               }
+               return true;
+       },
+       start: function(event) {
+               var e = event.originalEvent;
+               var touches = e.touches;
+
+               if (touches.length > 1) {
+                       this.enableUserScale();
+                       return true;
+               }
+
+               this._start(touches[0].pageX, touches[0].pageY);
+               return true;
+       },
+       end: function(event) {
+               var e = event.originalEvent;
+               var touches = e.touches;
+
+               if (touches.length == 0) {
+                       this._end();
+               }
+               return true;
+       },
+       testOffset: function() {
+               if (this.triggered) {
+                       return false;
+               }
+               if (this.allowMove()) {
+                       return false;
+               }
+               if (!this.fluidbook.pad.enabled) {
+                       if (Math.abs(this.offsetX) < Math.abs(this.offsetY)) {
+                               return false;
+                       }
+                       if (this.allowSlide()) {
+                               if (this.offsetX < -this.triggerOffset) {
+                                       this.fluidbook.goNextPage();
+                                       return true;
+                               } else if (this.offsetX > this.triggerOffset) {
+                                       this.fluidbook.goPreviousPage();
+                                       return true;
+                               }
+                       }
+               } else {
+                       // Mode mag pad
+                       if (this.allowSlide()) {
+                               var offset = this.offsetX;
+                               var way = 'x';
+                               if (Math.abs(this.offsetX) < Math.abs(this.offsetY)) {
+                                       offset = this.offsetY;
+                                       way = 'y';
+                               }
+
+                               if (Math.abs(offset) < this.triggerOffset) {
+                                       return false;
+                               }
+
+                               if (offset < -this.triggerOffset) {
+                                       if (way == 'x') {
+                                               this.fluidbook.goNextChapter();
+                                       } else {
+                                               this.fluidbook.goNextChapterPage();
+                                       }
+                               } else {
+                                       if (way == 'x') {
+                                               this.fluidbook.goPreviousChapter();
+                                       } else {
+                                               this.fluidbook.goPreviousChapterPage();
+                                       }
+                               }
+                               return true;
+                       }
+               }
+               return false;
+       },
+       cancel: function(event) {
+               this.end(event);
+               return true;
+       },
+       move: function(event) {
+               var e = event.originalEvent;
+
+               var touches = e.touches;
+
+               if (touches.length > 1) {
+                       return true;
+               }
+
+               return this._move(touches[0].pageX, touches[0].pageY);
+       },
+       _start: function(x, y) {
+               this.startX = x;
+               this.startY = y;
+       },
+       _move: function(x, y) {
+               if (!isNaN(this.startX)) {
+                       this.offsetX = (x - this.startX) / $(window).width();
+               }
+
+               if (!isNaN(this.startY)) {
+                       this.offsetY = (y - this.startY) / $(window).height();
+               }
+
+               this.testOffset();
+               return this.allowMove();
+       },
+       _end: function() {
+               this.testOffset();
+               this.reset();
+       },
+       enableUserScale: function() {
+               if (this.fluidbook.pad.enabled) {
+                       this.fluidbook.viewport.maxScale = 1;
+                       this.fluidbook.viewport.userScalable = false;
+               } else {
+                       this.fluidbook.viewport.maxScale = 8;
+                       this.fluidbook.viewport.userScalable = true;
+               }
+               this.fluidbook.viewport.updateViewport();
+       }
+};
+
diff --git a/js/libs/fluidbook/fluidbook.utils.js b/js/libs/fluidbook/fluidbook.utils.js
new file mode 100644 (file)
index 0000000..aa19a5d
--- /dev/null
@@ -0,0 +1,40 @@
+function isMobile() {
+       var ua = navigator.userAgent;
+       var devices = ['iphone', 'ipad', 'ipod', 'droid', 'blackberry', 'mobile', 'htc', 'samsung', 'nokia', 'archos', 'galaxy', 'motorola', 'pad', 'tab', 'slate', 'motorola', 'symbian', 'phone', 'nintendo', 'playstation', 'touch', 'webos', 'ericsson'];
+       var pattern;
+
+       if (Modernizr.ftouch) {
+               return true;
+       }
+
+       for (i = 0; i < devices.length; i++) {
+               pattern = new RegExp(devices[i], 'i');
+               if (ua.search(pattern) > -1) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+function parseGet() {
+       var couples = window.location.search.substr(1).split('&');
+       var res = new Array();
+       var couple = new Array();
+       for (var i = 0; i < couples.length; i++) {
+               couple = couples[i].split('=');
+               res[couple[0]] = couple[1];
+       }
+       return res;
+}
+
+function getBaseURL() {
+       var l = window.location.toString();
+       var e = l.split("#");
+       var l = e[0];
+       if (l.indexOf('.') != -1) {
+               e = l.split('/');
+               e.pop();
+               l=e.join('/');
+       }
+       return l;
+}
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.video.js b/js/libs/fluidbook/fluidbook.video.js
new file mode 100644 (file)
index 0000000..b89b4d6
--- /dev/null
@@ -0,0 +1,163 @@
+function FluidbookVideo(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.flash = FlashDetect.installed && FlashDetect.major >= 9;
+       this.video = (Modernizr.video && (Modernizr.video.h264 || Modernizr.video.webm || Modernizr.video.ogg)) != false;
+
+       this.videoFormats = [];
+
+       var probably = [];
+       var maybe = [];
+       var not = [];
+       if (Modernizr.ftouch) {
+               if (this.flash) {
+                       probably.push('flv');
+               }
+       }
+
+       if (this.video) {
+               var formats = this.fluidbook.datas.videoFormats;
+               for (var i = 0; i < formats.length; i++) {
+                       var f = formats[i];
+                       if (f == 'mp4') {
+                               f = 'h264';
+                       }
+                       if (f == 'ogv') {
+                               f = 'ogg';
+                       }
+                       var support = Modernizr.video[f];
+                       if (f == 'ogg') {
+                               f = 'ogv';
+                       }
+                       if (f == 'h264') {
+                               f = 'mp4';
+                       }
+                       if (support == 'probably') {
+                               probably.push(f);
+                       } else if (support == 'maybe') {
+                               maybe.push(f);
+                       } else {
+                               not.push(f);
+                       }
+               }
+       }
+       if (!Modernizr.ftouch) {
+               if (this.flash) {
+                       probably.push('flv');
+               }
+       }
+
+
+       this.videoFormats = $.merge(probably, maybe, not);
+       this.preferedFormat = this.videoFormats[0];
+       //fb("Video prefered format : " + this.preferedFormat+" ("+this.videoFormats.join(', ')+")");
+}
+
+FluidbookVideo.prototype = {
+       initVideo: function(e) {
+               if ($(e).html() != '') {
+                       return;
+               }
+               var width = parseFloat($(e).attr('data-width'));
+               var height = parseFloat($(e).attr('data-height'));
+               var name = $(e).attr('data-name');
+               var controls = $(e).attr('data-controls');
+               var loop = $(e).attr('data-loop');
+               var sound = $(e).attr('data-sound');
+               var autoplay = $(e).attr('data-autoplay');
+
+               var path;
+               if (fluidbook.datas.mobileVideosPath == '') {
+                       path = "data/links/" + name;
+               } else {
+                       path = fluidbook.datas.mobileVideosPath + name;
+                       if (!fluidbook.datas.standalone && path.substr(0, 3) == '../') {
+                               path = '../' + path;
+                       }
+               }
+               var poster = path + '.jpg';
+
+               if (this.preferedFormat == 'flv') {
+                       var fv = {};
+                       fv.video = '../' + path + '.flv';
+                       fv.poster = '../' + poster;
+                       fv.controls = controls;
+                       fv.autoPlay = autoplay;
+                       fv.loop = loop;
+                       fv.soundOn = sound;
+                       var flashvars = [];
+                       $.each(fv, function(k, v) {
+                               flashvars.push(k + '=' + encodeURIComponent(v));
+                       });
+
+                       if (isNaN(width)) {
+                               width = '100%';
+                       }
+                       if (isNaN(height)) {
+                               height = '100%';
+                       }
+
+                       html = '<object data="swf/video.swf" ';
+                       html += 'width="' + width + '" ';
+                       html += 'height="' + height + '" ';
+                       html += 'type="application/x-shockwave-flash">';
+                       html += '<param name="allowScriptAccess" value="always"/>';
+                       html += '<param name="movie" value="swf/video.swf"/>';
+                       html += '<param name="quality" value="high"/>';
+                       html += '<param name="scale" value="noscale"/>';
+                       html += '<param name="wmode" value="transparent"/>';
+                       html += '<param name="allowFullScreen" value="true"/>';
+                       html += '<param name="flashvars" value="' + flashvars.join('&amp;') + '"/>';
+                       html += '</object>';
+               } else if (this.preferedFormat != 'img') {
+                       html = '<video poster="' + poster + '" ';
+                       if (!isNaN(width)) {
+                               html += 'data-width="' + width + '" ';
+                               html += 'width="' + width + '" ';
+                       }
+                       if (!isNaN(height)) {
+                               html += 'data-height="' + height + '" ';
+                               html += 'height="' + height + '" ';
+                       }
+                       html += 'controls="controls" ';
+                       //html += 'onclick="this.play();" ';
+                       if (controls == '0') {
+                               html += 'onplay="this.removeAttribute(\'controls\')" ';
+                       }
+                       if (loop == '1') {
+                               html += 'onended="this.play()" ';
+                       }
+                       if (autoplay == '1') {
+                               html += 'autoplay="autoplay" ';
+                       }
+                       if (sound == '0') {
+                               html += 'muted="muted" ';
+                       }
+                       html += 'src="' + path + '.' + this.preferedFormat + '"></video>';
+               } else {
+                       html = '<a href="' + path + '.mp4" target="_blank">';
+                       html += '<img src="' + poster + '" width="' + width + '" height="' + height + '" />';
+                       html += '</a>';
+               }
+
+               $(e).html(html);
+       },
+       initCache: function() {
+               var $this = this;
+               $('body').append('<iframe id="videoframe" marginheight="0" marginwidth="0" scrolling="no" width="1" height="1" src="data/links/video.' + this.preferedFormat + '.html" frameborder="0"></iframe>');
+               $("#videoframe").load(function() {
+                       var w = this.contentWindow;
+                       var cache = w.applicationCache;
+                       cache.addEventListener('downloading', $this.logCacheEvent, false);
+                       cache.addEventListener('checking', $this.logCacheEvent, false);
+                       cache.addEventListener('cached', $this.logCacheEvent, false);
+                       cache.addEventListener('downloading', $this.logCacheEvent, false);
+                       cache.addEventListener('noupdate', $this.logCacheEvent, false);
+                       cache.addEventListener('updateready', $this.logCacheEvent, false);
+                       cache.addEventListener('error', $this.logCacheEvent, false);
+                       $(this).hide();
+               });
+       },
+       logCacheEvent: function(e) {
+               fb('video :' + e.type);
+       }
+};
\ No newline at end of file
diff --git a/js/libs/fluidbook/fluidbook.viewport.js b/js/libs/fluidbook/fluidbook.viewport.js
new file mode 100644 (file)
index 0000000..33657a0
--- /dev/null
@@ -0,0 +1,27 @@
+function FluidbookViewport(support){
+       this.support=support;
+       this.width=null;
+       this.height=null;
+       this.minScale=1;
+       this.maxScale=10;
+       this.initialScale=1;
+       this.userScalable=false;
+       this.meta=$('meta[name="viewport"]');
+}
+
+FluidbookViewport.prototype={
+       updateViewport:function(){
+               var w='';
+               if(this.width!=null){
+                       w='width='+this.width+', ';
+               }
+               var h='';
+               if(this.height!=null){
+                       h='height='+this.height+', ';
+               }
+               var us=this.userScalable==true?'yes':'no';
+               
+               var value=w+h+'initial-scale='+this.initialScale+', minimum-scale='+Math.max(0.25,this.minScale)+', maximum-scale='+Math.min(10,this.maxScale)+', user-scalable='+us;
+               this.meta.attr('content',value);
+       }
+}
\ No newline at end of file
diff --git a/js/libs/fluidbook/views/fluidbook.chapters.js b/js/libs/fluidbook/views/fluidbook.chapters.js
new file mode 100644 (file)
index 0000000..21ef909
--- /dev/null
@@ -0,0 +1,95 @@
+function FluidbookChapters(fluidbook, chapters) {\r
+       this.fluidbook = fluidbook;\r
+       this.chapters = chapters;\r
+       this.html = '';\r
+       this.lastColor;\r
+}\r
+\r
+FluidbookChapters.prototype = {\r
+       getView: function() {\r
+               if (this.html == '') {\r
+                       this.makeView();\r
+               }\r
+               return this.html;\r
+       },\r
+       makeView: function() {\r
+               this.makeClassicMenu();\r
+               if (this.fluidbook.datas.chaptersCascade) {\r
+                       this.makeCascadeMenu();\r
+               }\r
+       },\r
+       makeCascadeMenu: function() {\r
+               var h = $(this.html);\r
+\r
+               for (var i = 3; i >= 0; i--) {\r
+                       $(h).find('li[data-level=' + i + ']').each(function() {\r
+                               var siblings = $(this).nextUntil('li[data-level!=' + (i + 1) + ']', 'li[data-level=' + (i + 1) + ']');\r
+                               if (siblings.length > 0) {\r
+                                       $(this).append('<ul></ul>');\r
+                                       var nav = $(this).find('ul');\r
+                                       $(nav).append(siblings);\r
+                                       $(nav).hide();\r
+                               }\r
+                       });\r
+               }\r
+               this.html = $(h).get(0).outerHTML;\r
+\r
+               $(document).on('click', 'ul.chapters a', function() {\r
+                       var li = $(this).parent();\r
+                       var subnav = $(li).children('ul');\r
+                       if ($(subnav).length) {\r
+                               $(subnav).slideToggle();\r
+                               return false;\r
+                       } else {\r
+                               return true;\r
+                       }\r
+               });\r
+       },\r
+       makeClassicMenu: function() {\r
+               var $this = this;\r
+               this.html = '<ul class="chapters">';\r
+               $.each(this.chapters, function(k, v) {\r
+                       $this.html += $this.addItem(v);\r
+               });\r
+               this.html += '</ul>';\r
+       },\r
+       addItem: function(chapter) {\r
+               if (chapter.label == '--' || chapter.label == '++') {\r
+                       return "";\r
+\r
+               }\r
+               var color = chapter.color;\r
+               if (color == '') {\r
+                       if (this.lastColor != undefined) {\r
+                               color = this.lastColor;\r
+                       }\r
+               }\r
+               if (color != '') {\r
+                       this.lastColor = color;\r
+               }\r
+\r
+\r
+               if (chapter.label.substr(0, 3) == '!!!') {\r
+                       chapter.label = chapter.label.substring(3);\r
+                       chapter.level='-1';\r
+               }\r
+\r
+\r
+\r
+               var res = '<li data-level="' + chapter.level + '"><a href="#/page/' + (this.fluidbook.virtualToPhysical(chapter.page)) + '" class="level' + chapter.level + '">';\r
+               res += chapter.label;\r
+               res += '<div class="right">';\r
+               if (color == '') {\r
+                       res += chapter.page;\r
+               } else {\r
+                       res += '<div class="puce" style="background-color:#' + color + ';"></div>';\r
+               }\r
+               res += '</div>'\r
+               res += '</a></li>';\r
+\r
+               return res;\r
+       }\r
+\r
+\r
+};\r
+\r
diff --git a/js/libs/fluidbook/views/fluidbook.index.js b/js/libs/fluidbook/views/fluidbook.index.js
new file mode 100644 (file)
index 0000000..8255d3f
--- /dev/null
@@ -0,0 +1,67 @@
+function FluidbookIndex(fluidbook) {
+       this.fluidbook = fluidbook;
+       this.init();
+}
+
+FluidbookIndex.prototype = {
+       init: function() {
+               this.normalHTML = '';
+               this.padHTML = '';
+       },
+       getView: function(group) {
+               if (this.fluidbook.pad.enabled) {
+                       return this.getPadView(group);
+               } else {
+                       return this.getNormalView();
+               }
+       },
+       getPadView: function(group) {
+               return this.fluidbook.bookmarks.getIndex(true, group);
+       },
+       getNormalView: function() {
+
+               if (this.normalHTML == '') {
+                       this.normalHTML += '<div class="content"><div id="indexView">';
+                       var j = 0;
+                       var ix = '';
+                       var c = '';
+
+                       for (var i = 0; i <= this.fluidbook.datas.pages; i += 2) {
+                               var pages = [];
+                               j = i + 1;
+                               ix = '';
+                               c = '';
+                               if (i > 0) {
+                                       ix += '<div class="thumb left"><a href="#/page/' + i + '"><img src="data/thumbnails/p' + i + '.jpg" /></a><span class="number">' + this.fluidbook.physicalToVirtual(i) + '</span>';
+                                       if (this.fluidbook.bookmarks.enabled) {
+                                               ix += this.fluidbook.bookmarks.getBookmarkForPage(i, true);
+                                       }
+                                       pages.push(i);
+                                       ix += '</div>';
+
+                               } else {
+                                       c = ' simple right';
+                               }
+                               if (j < this.fluidbook.datas.pages) {
+                                       ix += '<div class="thumb right"><a href="#/page/' + j + '"><img src="data/thumbnails/p' + j + '.jpg" /></a><span class="number">' + this.fluidbook.physicalToVirtual(j) + '</span>';
+                                       if (this.fluidbook.bookmarks.enabled) {
+                                               ix += this.fluidbook.bookmarks.getBookmarkForPage(j, true);
+                                       }
+                                       ix += '</div>';
+                                       pages.push(j);
+                               } else {
+                                       c = ' simple left';
+                               }
+
+                               this.normalHTML += '<div class="doubleThumb' + c + '" page="' + i + '" data-pages="' + pages.join(',') + '">' + ix;
+                               this.normalHTML += '</div>';
+                       }
+                       for (i = 0; i < 5; i++) {
+                               this.normalHTML += '<div class="padding"></div>';
+                       }
+                       this.normalHTML += '</div></div>';
+               }
+
+               return this.normalHTML;
+       }
+}
diff --git a/js/libs/gsap/TimelineLite.js b/js/libs/gsap/TimelineLite.js
new file mode 100644 (file)
index 0000000..1128f44
--- /dev/null
@@ -0,0 +1,611 @@
+/*!
+ * VERSION: beta 1.9.8
+ * DATE: 2013-06-05
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+       
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
+               
+               var TimelineLite = function(vars) {
+                               SimpleTimeline.call(this, vars);
+                               this._labels = {};
+                               this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
+                               this.smoothChildTiming = (this.vars.smoothChildTiming === true);
+                               this._sortChildren = true;
+                               this._onUpdate = this.vars.onUpdate;
+                               var v = this.vars,
+                                       i = _paramProps.length,
+                                       j, a;
+                               while (--i > -1) {
+                                       a = v[_paramProps[i]];
+                                       if (a) {
+                                               j = a.length;
+                                               while (--j > -1) {
+                                                       if (a[j] === "{self}") {
+                                                               a = v[_paramProps[i]] = a.concat(); //copy the array in case the user referenced the same array in multiple timelines/tweens (each {self} should be unique)
+                                                               a[j] = this;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (v.tweens instanceof Array) {
+                                       this.add(v.tweens, 0, v.align, v.stagger);
+                               }
+                       },
+                       _paramProps = ["onStartParams","onUpdateParams","onCompleteParams","onReverseCompleteParams","onRepeatParams"],
+                       _blankArray = [],
+                       _copy = function(vars) {
+                               var copy = {}, p;
+                               for (p in vars) {
+                                       copy[p] = vars[p];
+                               }
+                               return copy;
+                       },
+                       _slice = _blankArray.slice,
+                       p = TimelineLite.prototype = new SimpleTimeline();
+
+               TimelineLite.version = "1.9.8";
+               p.constructor = TimelineLite;
+               p.kill()._gc = false;
+               
+               p.to = function(target, duration, vars, position) {
+                       return duration ? this.add( new TweenLite(target, duration, vars), position) : this.set(target, vars, position);
+               };
+               
+               p.from = function(target, duration, vars, position) {
+                       return this.add( TweenLite.from(target, duration, vars), position);
+               };
+               
+               p.fromTo = function(target, duration, fromVars, toVars, position) {
+                       return duration ? this.add( TweenLite.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
+               };
+               
+               p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope}),
+                               i;
+                       if (typeof(targets) === "string") {
+                               targets = TweenLite.selector(targets) || targets;
+                       }
+                       if (!(targets instanceof Array) && targets.length && targets[0] && targets[0].nodeType && targets[0].style) { //senses if the targets object is a selector. If it is, we should translate it into an array.
+                               targets = _slice.call(targets, 0);
+                       }
+                       stagger = stagger || 0;
+                       for (i = 0; i < targets.length; i++) {
+                               if (vars.startAt) {
+                                       vars.startAt = _copy(vars.startAt);
+                               }
+                               tl.to(targets[i], duration, _copy(vars), i * stagger);
+                       }
+                       return this.add(tl, position);
+               };
+               
+               p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       vars.immediateRender = (vars.immediateRender != false);
+                       vars.runBackwards = true;
+                       return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+               
+               p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+               
+               p.call = function(callback, params, scope, position) {
+                       return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
+               };
+               
+               p.set = function(target, vars, position) {
+                       position = this._parseTimeOrLabel(position, 0, true);
+                       if (vars.immediateRender == null) {
+                               vars.immediateRender = (position === this._time && !this._paused);
+                       }
+                       return this.add( new TweenLite(target, 0, vars), position);
+               };
+               
+               TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
+                       vars = vars || {};
+                       if (vars.smoothChildTiming == null) {
+                               vars.smoothChildTiming = true;
+                       }
+                       var tl = new TimelineLite(vars),
+                               root = tl._timeline,
+                               tween, next;
+                       if (ignoreDelayedCalls == null) {
+                               ignoreDelayedCalls = true;
+                       }
+                       root._remove(tl, true);
+                       tl._startTime = 0;
+                       tl._rawPrevTime = tl._time = tl._totalTime = root._time;
+                       tween = root._first;
+                       while (tween) {
+                               next = tween._next;
+                               if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
+                                       tl.add(tween, tween._startTime - tween._delay);
+                               }
+                               tween = next;
+                       }
+                       root.add(tl, 0);
+                       return tl;
+               };
+
+               p.add = function(value, position, align, stagger) {
+                       var curTime, l, i, child, tl;
+                       if (typeof(position) !== "number") {
+                               position = this._parseTimeOrLabel(position, 0, true, value);
+                       }
+                       if (!(value instanceof Animation)) {
+                               if (value instanceof Array) {
+                                       align = align || "normal";
+                                       stagger = stagger || 0;
+                                       curTime = position;
+                                       l = value.length;
+                                       for (i = 0; i < l; i++) {
+                                               if ((child = value[i]) instanceof Array) {
+                                                       child = new TimelineLite({tweens:child});
+                                               }
+                                               this.add(child, curTime);
+                                               if (typeof(child) !== "string" && typeof(child) !== "function") {
+                                                       if (align === "sequence") {
+                                                               curTime = child._startTime + (child.totalDuration() / child._timeScale);
+                                                       } else if (align === "start") {
+                                                               child._startTime -= child.delay();
+                                                       }
+                                               }
+                                               curTime += stagger;
+                                       }
+                                       return this._uncache(true);
+                               } else if (typeof(value) === "string") {
+                                       return this.addLabel(value, position);
+                               } else if (typeof(value) === "function") {
+                                       value = TweenLite.delayedCall(0, value);
+                               } else {
+                                       throw("Cannot add " + value + " into the timeline; it is neither a tween, timeline, function, nor a string.");
+                               }
+                       }
+
+                       SimpleTimeline.prototype.add.call(this, value, position);
+
+                       //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly.
+                       if (this._gc) if (!this._paused) if (this._time === this._duration) if (this._time < this.duration()) {
+                               //in case any of the anscestors had completed but should now be enabled...
+                               tl = this;
+                               while (tl._gc && tl._timeline) {
+                                       if (tl._timeline.smoothChildTiming) {
+                                               tl.totalTime(tl._totalTime, true); //also enables them
+                                       } else {
+                                               tl._enabled(true, false);
+                                       }
+                                       tl = tl._timeline;
+                               }
+                       }
+
+                       return this;
+               };
+
+               p.remove = function(value) {
+                       if (value instanceof Animation) {
+                               return this._remove(value, false);
+                       } else if (value instanceof Array) {
+                               var i = value.length;
+                               while (--i > -1) {
+                                       this.remove(value[i]);
+                               }
+                               return this;
+                       } else if (typeof(value) === "string") {
+                               return this.removeLabel(value);
+                       }
+                       return this.kill(null, value);
+               };
+
+               p._remove = function(tween, skipDisable) {
+                       SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
+                       if (!this._last) {
+                               this._time = this._totalTime = 0;
+                       } else if (this._time > this._last._startTime) {
+                               this._time = this.duration();
+                               this._totalTime = this._totalDuration;
+                       }
+                       return this;
+               };
+               
+               p.append = function(value, offsetOrLabel) {
+                       return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
+               };
+
+               p.insert = p.insertMultiple = function(value, position, align, stagger) {
+                       return this.add(value, position || 0, align, stagger);
+               };
+               
+               p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
+                       return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
+               };
+               
+               p.addLabel = function(label, position) {
+                       this._labels[label] = this._parseTimeOrLabel(position);
+                       return this;
+               };
+       
+               p.removeLabel = function(label) {
+                       delete this._labels[label];
+                       return this;
+               };
+               
+               p.getLabelTime = function(label) {
+                       return (this._labels[label] != null) ? this._labels[label] : -1;
+               };
+               
+               p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
+                       var i;
+                       //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
+                       if (ignore instanceof Animation && ignore.timeline === this) {
+                               this.remove(ignore);
+                       } else if (ignore instanceof Array) {
+                               i = ignore.length;
+                               while (--i > -1) {
+                                       if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
+                                               this.remove(ignore[i]);
+                                       }
+                               }
+                       }
+                       if (typeof(offsetOrLabel) === "string") {
+                               return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
+                       }
+                       offsetOrLabel = offsetOrLabel || 0;
+                       if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
+                               i = timeOrLabel.indexOf("=");
+                               if (i === -1) {
+                                       if (this._labels[timeOrLabel] == null) {
+                                               return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
+                                       }
+                                       return this._labels[timeOrLabel] + offsetOrLabel;
+                               }
+                               offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
+                               timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
+                       } else if (timeOrLabel == null) {
+                               timeOrLabel = this.duration();
+                       }
+                       return Number(timeOrLabel) + offsetOrLabel;
+               };
+               
+               p.seek = function(position, suppressEvents) {
+                       return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
+               };
+               
+               p.stop = function() {
+                       return this.paused(true);
+               };
+       
+               p.gotoAndPlay = function(position, suppressEvents) {
+                       return this.play(position, suppressEvents);
+               };
+               
+               p.gotoAndStop = function(position, suppressEvents) {
+                       return this.pause(position, suppressEvents);
+               };
+               
+               p.render = function(time, suppressEvents, force) {
+                       if (this._gc) {
+                               this._enabled(true, false);
+                       }
+                       this._active = !this._paused;
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 
+                               prevTime = this._time, 
+                               prevStart = this._startTime, 
+                               prevTimeScale = this._timeScale, 
+                               prevPaused = this._paused,
+                               tween, isComplete, next, callback, internalForce;
+                       if (time >= totalDur) {
+                               this._totalTime = this._time = totalDur;
+                               if (!this._reversed) if (!this._hasPausedChild()) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                                       if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time && this._first) { //In order to accommodate zero-duration timelines, we must discern the momentum/direction of time in order to render values properly when the "playhead" goes past 0 in the forward direction or lands directly on it, and also when it moves past it in the backward direction (from a postitive time to a negative time).
+                                               internalForce = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                               }
+                                       }
+                               }
+                               this._rawPrevTime = time;
+                               time = totalDur + 0.000001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off)
+
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = 0;
+                               if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               internalForce = true;
+                                       }
+                               } else if (!this._initted) {
+                                       internalForce = true;
+                               }
+                               this._rawPrevTime = time;
+                               time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
+
+                       } else {
+                               this._totalTime = this._time = this._rawPrevTime = time;
+                       }
+                       if ((this._time === prevTime || !this._first) && !force && !internalForce) {
+                               return;
+                       } else if (!this._initted) {
+                               this._initted = true;
+                       }
+                       if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
+                               this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                       }
+                       
+                       if (this._time >= prevTime) {
+                               tween = this._first;
+                               while (tween) {
+                                       next = tween._next; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
+                                               
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+                                               
+                                       }
+                                       tween = next;
+                               }
+                       } else {
+                               tween = this._last;
+                               while (tween) {
+                                       next = tween._prev; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
+                                               
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+                                               
+                                       }
+                                       tween = next;
+                               }
+                       }
+                       
+                       if (this._onUpdate) if (!suppressEvents) {
+                               this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                       }
+                       
+                       if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+               
+               p._hasPausedChild = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
+                                       return true;
+                               }
+                               tween = tween._next;
+                       }
+                       return false;
+               };
+               
+               p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || -9999999999;
+                       var a = [], 
+                               tween = this._first, 
+                               cnt = 0;
+                       while (tween) {
+                               if (tween._startTime < ignoreBeforeTime) {
+                                       //do nothing
+                               } else if (tween instanceof TweenLite) {
+                                       if (tweens !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                               } else {
+                                       if (timelines !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                                       if (nested !== false) {
+                                               a = a.concat(tween.getChildren(true, tweens, timelines));
+                                               cnt = a.length;
+                                       }
+                               }
+                               tween = tween._next;
+                       }
+                       return a;
+               };
+               
+               p.getTweensOf = function(target, nested) {
+                       var tweens = TweenLite.getTweensOf(target), 
+                               i = tweens.length, 
+                               a = [], 
+                               cnt = 0;
+                       while (--i > -1) {
+                               if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
+                                       a[cnt++] = tweens[i];
+                               }
+                       }
+                       return a;
+               };
+               
+               p._contains = function(tween) {
+                       var tl = tween.timeline;
+                       while (tl) {
+                               if (tl === this) {
+                                       return true;
+                               }
+                               tl = tl.timeline;
+                       }
+                       return false;
+               };
+               
+               p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || 0;
+                       var tween = this._first,
+                               labels = this._labels,
+                               p;
+                       while (tween) {
+                               if (tween._startTime >= ignoreBeforeTime) {
+                                       tween._startTime += amount;
+                               }
+                               tween = tween._next;
+                       }
+                       if (adjustLabels) {
+                               for (p in labels) {
+                                       if (labels[p] >= ignoreBeforeTime) {
+                                               labels[p] += amount;
+                                       }
+                               }
+                       }
+                       return this._uncache(true);
+               };
+               
+               p._kill = function(vars, target) {
+                       if (!vars && !target) {
+                               return this._enabled(false, false);
+                       }
+                       var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
+                               i = tweens.length, 
+                               changed = false;
+                       while (--i > -1) {
+                               if (tweens[i]._kill(vars, target)) {
+                                       changed = true;
+                               }
+                       }
+                       return changed;
+               };
+               
+               p.clear = function(labels) {
+                       var tweens = this.getChildren(false, true, true),
+                               i = tweens.length;
+                       this._time = this._totalTime = 0;
+                       while (--i > -1) {
+                               tweens[i]._enabled(false, false);
+                       }
+                       if (labels !== false) {
+                               this._labels = {};
+                       }
+                       return this._uncache(true);
+               };
+               
+               p.invalidate = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               tween.invalidate();
+                               tween = tween._next;
+                       }
+                       return this;
+               };
+               
+               p._enabled = function(enabled, ignoreTimeline) {
+                       if (enabled === this._gc) {
+                               var tween = this._first;
+                               while (tween) {
+                                       tween._enabled(enabled, true);
+                                       tween = tween._next;
+                               }
+                       }
+                       return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
+               };
+               
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, false);
+               };
+               
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       this.totalDuration(); //just triggers recalculation
+                               }
+                               return this._duration;
+                       }
+                       if (this.duration() !== 0 && value !== 0) {
+                               this.timeScale(this._duration / value);
+                       }
+                       return this;
+               };
+               
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       var max = 0,
+                                               tween = this._last,
+                                               prevStart = 999999999999,
+                                               prev, end;
+                                       while (tween) {
+                                               prev = tween._prev; //record it here in case the tween changes position in the sequence...
+                                               if (tween._dirty) {
+                                                       tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
+                                               }
+                                               if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
+                                                       this.add(tween, tween._startTime - tween._delay);
+                                               } else {
+                                                       prevStart = tween._startTime;
+                                               }
+                                               if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
+                                                       max -= tween._startTime;
+                                                       if (this._timeline.smoothChildTiming) {
+                                                               this._startTime += tween._startTime / this._timeScale;
+                                                       }
+                                                       this.shiftChildren(-tween._startTime, false, -9999999999);
+                                                       prevStart = 0;
+                                               }
+                                               end = tween._startTime + (tween._totalDuration / tween._timeScale);
+                                               if (end > max) {
+                                                       max = end;
+                                               }
+                                               tween = prev;
+                                       }
+                                       this._duration = this._totalDuration = max;
+                                       this._dirty = false;
+                               }
+                               return this._totalDuration;
+                       }
+                       if (this.totalDuration() !== 0) if (value !== 0) {
+                               this.timeScale(this._totalDuration / value);
+                       }
+                       return this;
+               };
+               
+               p.usesFrames = function() {
+                       var tl = this._timeline;
+                       while (tl._timeline) {
+                               tl = tl._timeline;
+                       }
+                       return (tl === Animation._rootFramesTimeline);
+               };
+               
+               p.rawTime = function() {
+                       return (this._paused || (this._totalTime !== 0 && this._totalTime !== this._totalDuration)) ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
+               };
+               
+               return TimelineLite;
+               
+       }, true);
+
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/TimelineMax.js b/js/libs/gsap/TimelineMax.js
new file mode 100644 (file)
index 0000000..9c20e67
--- /dev/null
@@ -0,0 +1,1045 @@
+/*!
+ * VERSION: beta 1.9.8
+ * DATE: 2013-06-05
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+       
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
+               
+               var TimelineMax = function(vars) {
+                               TimelineLite.call(this, vars);
+                               this._repeat = this.vars.repeat || 0;
+                               this._repeatDelay = this.vars.repeatDelay || 0;
+                               this._cycle = 0;
+                               this._yoyo = (this.vars.yoyo === true);
+                               this._dirty = true;
+                       },
+                       _blankArray = [],
+                       _easeNone = new Ease(null, null, 1, 0),
+                       _getGlobalPaused = function(tween) {
+                               while (tween) {
+                                       if (tween._paused) {
+                                               return true;
+                                       }
+                                       tween = tween._timeline;
+                               }
+                               return false;
+                       },
+                       p = TimelineMax.prototype = new TimelineLite();
+                       
+               p.constructor = TimelineMax;
+               p.kill()._gc = false;
+               TimelineMax.version = "1.9.8";
+               
+               p.invalidate = function() {
+                       this._yoyo = (this.vars.yoyo === true);
+                       this._repeat = this.vars.repeat || 0;
+                       this._repeatDelay = this.vars.repeatDelay || 0;
+                       this._uncache(true);
+                       return TimelineLite.prototype.invalidate.call(this);
+               };
+               
+               p.addCallback = function(callback, position, params, scope) {
+                       return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
+               };
+               
+               p.removeCallback = function(callback, position) {
+                       if (callback) {
+                               if (position == null) {
+                                       this._kill(null, callback);
+                               } else {
+                                       var a = this.getTweensOf(callback, false),
+                                               i = a.length,
+                                               time = this._parseTimeOrLabel(position);
+                                       while (--i > -1) {
+                                               if (a[i]._startTime === time) {
+                                                       a[i]._enabled(false, false);
+                                               }
+                                       }
+                               }
+                       }
+                       return this;
+               };
+               
+               p.tweenTo = function(position, vars) {
+                       vars = vars || {};
+                       var copy = {ease:_easeNone, overwrite:2, useFrames:this.usesFrames(), immediateRender:false}, p, t;
+                       for (p in vars) {
+                               copy[p] = vars[p];
+                       }
+                       copy.time = this._parseTimeOrLabel(position);
+                       t = new TweenLite(this, (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001, copy);
+                       copy.onStart = function() {
+                               t.target.paused(true);
+                               if (t.vars.time !== t.target.time()) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all.
+                                       t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
+                               }
+                               if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
+                                       vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
+                               }
+                       };
+                       return t;
+               };
+               
+               p.tweenFromTo = function(fromPosition, toPosition, vars) {
+                       vars = vars || {};
+                       fromPosition = this._parseTimeOrLabel(fromPosition);
+                       vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
+                       vars.immediateRender = (vars.immediateRender !== false);
+                       var t = this.tweenTo(toPosition, vars);
+                       return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
+               };
+               
+               p.render = function(time, suppressEvents, force) {
+                       if (this._gc) {
+                               this._enabled(true, false);
+                       }
+                       this._active = !this._paused;
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
+                               dur = this._duration,
+                               prevTime = this._time, 
+                               prevTotalTime = this._totalTime, 
+                               prevStart = this._startTime, 
+                               prevTimeScale = this._timeScale, 
+                               prevRawPrevTime = this._rawPrevTime,
+                               prevPaused = this._paused, 
+                               prevCycle = this._cycle, 
+                               tween, isComplete, next, callback, internalForce, cycleDuration;
+                       if (time >= totalDur) {
+                               if (!this._locked) {
+                                       this._totalTime = totalDur;
+                                       this._cycle = this._repeat;
+                               }
+                               if (!this._reversed) if (!this._hasPausedChild()) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                                       if (dur === 0) if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time && this._first) { //In order to accommodate zero-duration timelines, we must discern the momentum/direction of time in order to render values properly when the "playhead" goes past 0 in the forward direction or lands directly on it, and also when it moves past it in the backward direction (from a postitive time to a negative time).
+                                               internalForce = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                               }
+                                       }
+                               }
+                               this._rawPrevTime = time;
+                               if (this._yoyo && (this._cycle & 1) !== 0) {
+                                       this._time = time = 0;
+                               } else {
+                                       this._time = dur;
+                                       time = dur + 0.000001; //to avoid occasional floating point rounding errors
+                               }
+                               
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               if (!this._locked) {
+                                       this._totalTime = this._cycle = 0;
+                               }
+                               this._time = 0;
+                               if (prevTime !== 0 || (dur === 0 && this._rawPrevTime > 0 && !this._locked)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (dur === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               internalForce = true;
+                                       }
+                               } else if (!this._initted) {
+                                       internalForce = true;
+                               }
+                               this._rawPrevTime = time;
+                               time = 0;  //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
+                               
+                       } else {
+                               this._time = this._rawPrevTime = time;
+                               if (!this._locked) {
+                                       this._totalTime = time;
+                                       if (this._repeat !== 0) {
+                                               cycleDuration = dur + this._repeatDelay;
+                                               this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!)
+                                               if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
+                                                       this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
+                                               }
+                                               this._time = this._totalTime - (this._cycle * cycleDuration);
+                                               if (this._yoyo) if ((this._cycle & 1) !== 0) {
+                                                       this._time = dur - this._time;
+                                               }
+                                               if (this._time > dur) {
+                                                       this._time = dur;
+                                                       time = dur + 0.000001; //to avoid occasional floating point rounding error
+                                               } else if (this._time < 0) {
+                                                       this._time = time = 0;
+                                               } else {
+                                                       time = this._time;
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       if (this._cycle !== prevCycle) if (!this._locked) {
+                               /*
+                               make sure children at the end/beginning of the timeline are rendered properly. If, for example, 
+                               a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
+                               would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
+                               could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So 
+                               we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
+                               ensure that zero-duration tweens at the very beginning or end of the TimelineMax work. 
+                               */
+                               var backwards = (this._yoyo && (prevCycle & 1) !== 0),
+                                       wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
+                                       recTotalTime = this._totalTime,
+                                       recCycle = this._cycle,
+                                       recRawPrevTime = this._rawPrevTime,
+                                       recTime = this._time;
+                               
+                               this._totalTime = prevCycle * dur;
+                               if (this._cycle < prevCycle) {
+                                       backwards = !backwards;
+                               } else {
+                                       this._totalTime += dur;
+                               }
+                               this._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method.
+                               
+                               this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.00001 : prevRawPrevTime;
+                               this._cycle = prevCycle;
+                               this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
+                               prevTime = (backwards) ? 0 : dur;
+                               this.render(prevTime, suppressEvents, (dur === 0));
+                               if (!suppressEvents) if (!this._gc) {
+                                       if (this.vars.onRepeat) {
+                                               this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
+                                       }
+                               }
+                               if (wrap) {
+                                       prevTime = (backwards) ? dur + 0.000001 : -0.000001;
+                                       this.render(prevTime, true, false);
+                               }
+                               this._locked = false;
+                               if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
+                                       return;
+                               }
+                               this._time = recTime;
+                               this._totalTime = recTotalTime;
+                               this._cycle = recCycle;
+                               this._rawPrevTime = recRawPrevTime;
+                       }
+
+                       if ((this._time === prevTime || !this._first) && !force && !internalForce) {
+                               if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                               return;
+                       } else if (!this._initted) {
+                               this._initted = true;
+                       }
+                       
+                       if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
+                               this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                       }
+
+                       if (this._time >= prevTime) {
+                               tween = this._first;
+                               while (tween) {
+                                       next = tween._next; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+                                               
+                                       }
+                                       tween = next;
+                               }
+                       } else {
+                               tween = this._last;
+                               while (tween) {
+                                       next = tween._prev; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+                                               
+                                       }
+                                       tween = next;
+                               }
+                       }
+                       
+                       if (this._onUpdate) if (!suppressEvents) {
+                               this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                       }
+                       if (callback) if (!this._locked) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+               
+               p.getActive = function(nested, tweens, timelines) {
+                       if (nested == null) {
+                               nested = true;
+                       }
+                       if (tweens == null) {
+                               tweens = true;
+                       }
+                       if (timelines == null) {
+                               timelines = false;
+                       }
+                       var a = [], 
+                               all = this.getChildren(nested, tweens, timelines), 
+                               cnt = 0, 
+                               l = all.length,
+                               i, tween;
+                       for (i = 0; i < l; i++) {
+                               tween = all[i];
+                               //note: we cannot just check tween.active because timelines that contain paused children will continue to have "active" set to true even after the playhead passes their end point (technically a timeline can only be considered complete after all of its children have completed too, but paused tweens are...well...just waiting and until they're unpaused we don't know where their end point will be).
+                               if (!tween._paused) if (tween._timeline._time >= tween._startTime) if (tween._timeline._time < tween._startTime + tween._totalDuration / tween._timeScale) if (!_getGlobalPaused(tween._timeline)) {
+                                       a[cnt++] = tween;
+                               }
+                       }
+                       return a;
+               };
+               
+               
+               p.getLabelAfter = function(time) {
+                       if (!time) if (time !== 0) { //faster than isNan()
+                               time = this._time;
+                       }
+                       var labels = this.getLabelsArray(),
+                               l = labels.length,
+                               i;
+                       for (i = 0; i < l; i++) {
+                               if (labels[i].time > time) {
+                                       return labels[i].name;
+                               }
+                       }
+                       return null;
+               };
+               
+               p.getLabelBefore = function(time) {
+                       if (time == null) {
+                               time = this._time;
+                       }
+                       var labels = this.getLabelsArray(),
+                               i = labels.length;
+                       while (--i > -1) {
+                               if (labels[i].time < time) {
+                                       return labels[i].name;
+                               }
+                       }
+                       return null;
+               };
+               
+               p.getLabelsArray = function() {
+                       var a = [],
+                               cnt = 0,
+                               p;
+                       for (p in this._labels) {
+                               a[cnt++] = {time:this._labels[p], name:p};
+                       }
+                       a.sort(function(a,b) {
+                               return a.time - b.time;
+                       });
+                       return a;
+               };
+               
+               
+//---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
+               
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
+               };
+               
+               p.totalProgress = function(value) {
+                       return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
+               };
+
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       TimelineLite.prototype.totalDuration.call(this); //just forces refresh
+                                       //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
+                                       this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
+                               }
+                               return this._totalDuration;
+                       }
+                       return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
+               };
+               
+               p.time = function(value, suppressEvents) {
+                       if (!arguments.length) {
+                               return this._time;
+                       }
+                       if (this._dirty) {
+                               this.totalDuration();
+                       }
+                       if (value > this._duration) {
+                               value = this._duration;
+                       }
+                       if (this._yoyo && (this._cycle & 1) !== 0) {
+                               value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
+                       } else if (this._repeat !== 0) {
+                               value += this._cycle * (this._duration + this._repeatDelay);
+                       }
+                       return this.totalTime(value, suppressEvents);
+               };
+               
+               p.repeat = function(value) {
+                       if (!arguments.length) {
+                               return this._repeat;
+                       }
+                       this._repeat = value;
+                       return this._uncache(true);
+               };
+               
+               p.repeatDelay = function(value) {
+                       if (!arguments.length) {
+                               return this._repeatDelay;
+                       }
+                       this._repeatDelay = value;
+                       return this._uncache(true);
+               };
+               
+               p.yoyo = function(value) {
+                       if (!arguments.length) {
+                               return this._yoyo;
+                       }
+                       this._yoyo = value;
+                       return this;
+               };
+               
+               p.currentLabel = function(value) {
+                       if (!arguments.length) {
+                               return this.getLabelBefore(this._time + 0.00000001);
+                       }
+                       return this.seek(value, true);
+               };
+               
+               return TimelineMax;
+               
+       }, true);
+
+
+
+
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * TimelineLite
+ * ----------------------------------------------------------------
+ */
+
+       window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
+
+               var TimelineLite = function(vars) {
+                               SimpleTimeline.call(this, vars);
+                               this._labels = {};
+                               this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
+                               this.smoothChildTiming = (this.vars.smoothChildTiming === true);
+                               this._sortChildren = true;
+                               this._onUpdate = this.vars.onUpdate;
+                               var v = this.vars,
+                                       i = _paramProps.length,
+                                       j, a;
+                               while (--i > -1) {
+                                       a = v[_paramProps[i]];
+                                       if (a) {
+                                               j = a.length;
+                                               while (--j > -1) {
+                                                       if (a[j] === "{self}") {
+                                                               a = v[_paramProps[i]] = a.concat(); //copy the array in case the user referenced the same array in multiple timelines/tweens (each {self} should be unique)
+                                                               a[j] = this;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (v.tweens instanceof Array) {
+                                       this.add(v.tweens, 0, v.align, v.stagger);
+                               }
+                       },
+                       _paramProps = ["onStartParams","onUpdateParams","onCompleteParams","onReverseCompleteParams","onRepeatParams"],
+                       _blankArray = [],
+                       _copy = function(vars) {
+                               var copy = {}, p;
+                               for (p in vars) {
+                                       copy[p] = vars[p];
+                               }
+                               return copy;
+                       },
+                       _slice = _blankArray.slice,
+                       p = TimelineLite.prototype = new SimpleTimeline();
+
+               TimelineLite.version = "1.9.8";
+               p.constructor = TimelineLite;
+               p.kill()._gc = false;
+
+               p.to = function(target, duration, vars, position) {
+                       return duration ? this.add( new TweenLite(target, duration, vars), position) : this.set(target, vars, position);
+               };
+
+               p.from = function(target, duration, vars, position) {
+                       return this.add( TweenLite.from(target, duration, vars), position);
+               };
+
+               p.fromTo = function(target, duration, fromVars, toVars, position) {
+                       return duration ? this.add( TweenLite.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
+               };
+
+               p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope}),
+                               i;
+                       if (typeof(targets) === "string") {
+                               targets = TweenLite.selector(targets) || targets;
+                       }
+                       if (!(targets instanceof Array) && targets.length && targets[0] && targets[0].nodeType && targets[0].style) { //senses if the targets object is a selector. If it is, we should translate it into an array.
+                               targets = _slice.call(targets, 0);
+                       }
+                       stagger = stagger || 0;
+                       for (i = 0; i < targets.length; i++) {
+                               if (vars.startAt) {
+                                       vars.startAt = _copy(vars.startAt);
+                               }
+                               tl.to(targets[i], duration, _copy(vars), i * stagger);
+                       }
+                       return this.add(tl, position);
+               };
+
+               p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       vars.immediateRender = (vars.immediateRender != false);
+                       vars.runBackwards = true;
+                       return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+
+               p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+
+               p.call = function(callback, params, scope, position) {
+                       return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
+               };
+
+               p.set = function(target, vars, position) {
+                       position = this._parseTimeOrLabel(position, 0, true);
+                       if (vars.immediateRender == null) {
+                               vars.immediateRender = (position === this._time && !this._paused);
+                       }
+                       return this.add( new TweenLite(target, 0, vars), position);
+               };
+
+               TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
+                       vars = vars || {};
+                       if (vars.smoothChildTiming == null) {
+                               vars.smoothChildTiming = true;
+                       }
+                       var tl = new TimelineLite(vars),
+                               root = tl._timeline,
+                               tween, next;
+                       if (ignoreDelayedCalls == null) {
+                               ignoreDelayedCalls = true;
+                       }
+                       root._remove(tl, true);
+                       tl._startTime = 0;
+                       tl._rawPrevTime = tl._time = tl._totalTime = root._time;
+                       tween = root._first;
+                       while (tween) {
+                               next = tween._next;
+                               if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
+                                       tl.add(tween, tween._startTime - tween._delay);
+                               }
+                               tween = next;
+                       }
+                       root.add(tl, 0);
+                       return tl;
+               };
+
+               p.add = function(value, position, align, stagger) {
+                       var curTime, l, i, child, tl;
+                       if (typeof(position) !== "number") {
+                               position = this._parseTimeOrLabel(position, 0, true, value);
+                       }
+                       if (!(value instanceof Animation)) {
+                               if (value instanceof Array) {
+                                       align = align || "normal";
+                                       stagger = stagger || 0;
+                                       curTime = position;
+                                       l = value.length;
+                                       for (i = 0; i < l; i++) {
+                                               if ((child = value[i]) instanceof Array) {
+                                                       child = new TimelineLite({tweens:child});
+                                               }
+                                               this.add(child, curTime);
+                                               if (typeof(child) !== "string" && typeof(child) !== "function") {
+                                                       if (align === "sequence") {
+                                                               curTime = child._startTime + (child.totalDuration() / child._timeScale);
+                                                       } else if (align === "start") {
+                                                               child._startTime -= child.delay();
+                                                       }
+                                               }
+                                               curTime += stagger;
+                                       }
+                                       return this._uncache(true);
+                               } else if (typeof(value) === "string") {
+                                       return this.addLabel(value, position);
+                               } else if (typeof(value) === "function") {
+                                       value = TweenLite.delayedCall(0, value);
+                               } else {
+                                       throw("Cannot add " + value + " into the timeline; it is neither a tween, timeline, function, nor a string.");
+                               }
+                       }
+
+                       SimpleTimeline.prototype.add.call(this, value, position);
+
+                       //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly.
+                       if (this._gc) if (!this._paused) if (this._time === this._duration) if (this._time < this.duration()) {
+                               //in case any of the anscestors had completed but should now be enabled...
+                               tl = this;
+                               while (tl._gc && tl._timeline) {
+                                       if (tl._timeline.smoothChildTiming) {
+                                               tl.totalTime(tl._totalTime, true); //also enables them
+                                       } else {
+                                               tl._enabled(true, false);
+                                       }
+                                       tl = tl._timeline;
+                               }
+                       }
+
+                       return this;
+               };
+
+               p.remove = function(value) {
+                       if (value instanceof Animation) {
+                               return this._remove(value, false);
+                       } else if (value instanceof Array) {
+                               var i = value.length;
+                               while (--i > -1) {
+                                       this.remove(value[i]);
+                               }
+                               return this;
+                       } else if (typeof(value) === "string") {
+                               return this.removeLabel(value);
+                       }
+                       return this.kill(null, value);
+               };
+
+               p._remove = function(tween, skipDisable) {
+                       SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
+                       if (!this._last) {
+                               this._time = this._totalTime = 0;
+                       } else if (this._time > this._last._startTime) {
+                               this._time = this.duration();
+                               this._totalTime = this._totalDuration;
+                       }
+                       return this;
+               };
+
+               p.append = function(value, offsetOrLabel) {
+                       return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
+               };
+
+               p.insert = p.insertMultiple = function(value, position, align, stagger) {
+                       return this.add(value, position || 0, align, stagger);
+               };
+
+               p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
+                       return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
+               };
+
+               p.addLabel = function(label, position) {
+                       this._labels[label] = this._parseTimeOrLabel(position);
+                       return this;
+               };
+
+               p.removeLabel = function(label) {
+                       delete this._labels[label];
+                       return this;
+               };
+
+               p.getLabelTime = function(label) {
+                       return (this._labels[label] != null) ? this._labels[label] : -1;
+               };
+
+               p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
+                       var i;
+                       //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
+                       if (ignore instanceof Animation && ignore.timeline === this) {
+                               this.remove(ignore);
+                       } else if (ignore instanceof Array) {
+                               i = ignore.length;
+                               while (--i > -1) {
+                                       if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
+                                               this.remove(ignore[i]);
+                                       }
+                               }
+                       }
+                       if (typeof(offsetOrLabel) === "string") {
+                               return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
+                       }
+                       offsetOrLabel = offsetOrLabel || 0;
+                       if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
+                               i = timeOrLabel.indexOf("=");
+                               if (i === -1) {
+                                       if (this._labels[timeOrLabel] == null) {
+                                               return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
+                                       }
+                                       return this._labels[timeOrLabel] + offsetOrLabel;
+                               }
+                               offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
+                               timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
+                       } else if (timeOrLabel == null) {
+                               timeOrLabel = this.duration();
+                       }
+                       return Number(timeOrLabel) + offsetOrLabel;
+               };
+
+               p.seek = function(position, suppressEvents) {
+                       return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
+               };
+
+               p.stop = function() {
+                       return this.paused(true);
+               };
+
+               p.gotoAndPlay = function(position, suppressEvents) {
+                       return this.play(position, suppressEvents);
+               };
+
+               p.gotoAndStop = function(position, suppressEvents) {
+                       return this.pause(position, suppressEvents);
+               };
+
+               p.render = function(time, suppressEvents, force) {
+                       if (this._gc) {
+                               this._enabled(true, false);
+                       }
+                       this._active = !this._paused;
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
+                               prevTime = this._time,
+                               prevStart = this._startTime,
+                               prevTimeScale = this._timeScale,
+                               prevPaused = this._paused,
+                               tween, isComplete, next, callback, internalForce;
+                       if (time >= totalDur) {
+                               this._totalTime = this._time = totalDur;
+                               if (!this._reversed) if (!this._hasPausedChild()) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                                       if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time && this._first) { //In order to accommodate zero-duration timelines, we must discern the momentum/direction of time in order to render values properly when the "playhead" goes past 0 in the forward direction or lands directly on it, and also when it moves past it in the backward direction (from a postitive time to a negative time).
+                                               internalForce = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                               }
+                                       }
+                               }
+                               this._rawPrevTime = time;
+                               time = totalDur + 0.000001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off)
+
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = 0;
+                               if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               internalForce = true;
+                                       }
+                               } else if (!this._initted) {
+                                       internalForce = true;
+                               }
+                               this._rawPrevTime = time;
+                               time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
+
+                       } else {
+                               this._totalTime = this._time = this._rawPrevTime = time;
+                       }
+                       if ((this._time === prevTime || !this._first) && !force && !internalForce) {
+                               return;
+                       } else if (!this._initted) {
+                               this._initted = true;
+                       }
+                       if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
+                               this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                       }
+
+                       if (this._time >= prevTime) {
+                               tween = this._first;
+                               while (tween) {
+                                       next = tween._next; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
+
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       } else {
+                               tween = this._last;
+                               while (tween) {
+                                       next = tween._prev; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
+
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       }
+
+                       if (this._onUpdate) if (!suppressEvents) {
+                               this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                       }
+
+                       if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+
+               p._hasPausedChild = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
+                                       return true;
+                               }
+                               tween = tween._next;
+                       }
+                       return false;
+               };
+
+               p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || -9999999999;
+                       var a = [],
+                               tween = this._first,
+                               cnt = 0;
+                       while (tween) {
+                               if (tween._startTime < ignoreBeforeTime) {
+                                       //do nothing
+                               } else if (tween instanceof TweenLite) {
+                                       if (tweens !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                               } else {
+                                       if (timelines !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                                       if (nested !== false) {
+                                               a = a.concat(tween.getChildren(true, tweens, timelines));
+                                               cnt = a.length;
+                                       }
+                               }
+                               tween = tween._next;
+                       }
+                       return a;
+               };
+
+               p.getTweensOf = function(target, nested) {
+                       var tweens = TweenLite.getTweensOf(target),
+                               i = tweens.length,
+                               a = [],
+                               cnt = 0;
+                       while (--i > -1) {
+                               if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
+                                       a[cnt++] = tweens[i];
+                               }
+                       }
+                       return a;
+               };
+
+               p._contains = function(tween) {
+                       var tl = tween.timeline;
+                       while (tl) {
+                               if (tl === this) {
+                                       return true;
+                               }
+                               tl = tl.timeline;
+                       }
+                       return false;
+               };
+
+               p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || 0;
+                       var tween = this._first,
+                               labels = this._labels,
+                               p;
+                       while (tween) {
+                               if (tween._startTime >= ignoreBeforeTime) {
+                                       tween._startTime += amount;
+                               }
+                               tween = tween._next;
+                       }
+                       if (adjustLabels) {
+                               for (p in labels) {
+                                       if (labels[p] >= ignoreBeforeTime) {
+                                               labels[p] += amount;
+                                       }
+                               }
+                       }
+                       return this._uncache(true);
+               };
+
+               p._kill = function(vars, target) {
+                       if (!vars && !target) {
+                               return this._enabled(false, false);
+                       }
+                       var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
+                               i = tweens.length,
+                               changed = false;
+                       while (--i > -1) {
+                               if (tweens[i]._kill(vars, target)) {
+                                       changed = true;
+                               }
+                       }
+                       return changed;
+               };
+
+               p.clear = function(labels) {
+                       var tweens = this.getChildren(false, true, true),
+                               i = tweens.length;
+                       this._time = this._totalTime = 0;
+                       while (--i > -1) {
+                               tweens[i]._enabled(false, false);
+                       }
+                       if (labels !== false) {
+                               this._labels = {};
+                       }
+                       return this._uncache(true);
+               };
+
+               p.invalidate = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               tween.invalidate();
+                               tween = tween._next;
+                       }
+                       return this;
+               };
+
+               p._enabled = function(enabled, ignoreTimeline) {
+                       if (enabled === this._gc) {
+                               var tween = this._first;
+                               while (tween) {
+                                       tween._enabled(enabled, true);
+                                       tween = tween._next;
+                               }
+                       }
+                       return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
+               };
+
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, false);
+               };
+
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       this.totalDuration(); //just triggers recalculation
+                               }
+                               return this._duration;
+                       }
+                       if (this.duration() !== 0 && value !== 0) {
+                               this.timeScale(this._duration / value);
+                       }
+                       return this;
+               };
+
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       var max = 0,
+                                               tween = this._last,
+                                               prevStart = 999999999999,
+                                               prev, end;
+                                       while (tween) {
+                                               prev = tween._prev; //record it here in case the tween changes position in the sequence...
+                                               if (tween._dirty) {
+                                                       tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
+                                               }
+                                               if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
+                                                       this.add(tween, tween._startTime - tween._delay);
+                                               } else {
+                                                       prevStart = tween._startTime;
+                                               }
+                                               if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
+                                                       max -= tween._startTime;
+                                                       if (this._timeline.smoothChildTiming) {
+                                                               this._startTime += tween._startTime / this._timeScale;
+                                                       }
+                                                       this.shiftChildren(-tween._startTime, false, -9999999999);
+                                                       prevStart = 0;
+                                               }
+                                               end = tween._startTime + (tween._totalDuration / tween._timeScale);
+                                               if (end > max) {
+                                                       max = end;
+                                               }
+                                               tween = prev;
+                                       }
+                                       this._duration = this._totalDuration = max;
+                                       this._dirty = false;
+                               }
+                               return this._totalDuration;
+                       }
+                       if (this.totalDuration() !== 0) if (value !== 0) {
+                               this.timeScale(this._totalDuration / value);
+                       }
+                       return this;
+               };
+
+               p.usesFrames = function() {
+                       var tl = this._timeline;
+                       while (tl._timeline) {
+                               tl = tl._timeline;
+                       }
+                       return (tl === Animation._rootFramesTimeline);
+               };
+
+               p.rawTime = function() {
+                       return (this._paused || (this._totalTime !== 0 && this._totalTime !== this._totalDuration)) ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
+               };
+
+               return TimelineLite;
+
+       }, true);
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/TweenLite.js b/js/libs/gsap/TweenLite.js
new file mode 100644 (file)
index 0000000..cbab897
--- /dev/null
@@ -0,0 +1,1604 @@
+/*!
+ * VERSION: beta 1.9.8
+ * DATE: 2013-06-05
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(function(window) {
+       
+               "use strict";
+               var _globals = window.GreenSockGlobals || window,
+                       _namespace = function(ns) {
+                               var a = ns.split("."), 
+                                       p = _globals, i;
+                               for (i = 0; i < a.length; i++) {
+                                       p[a[i]] = p = p[a[i]] || {};
+                               }
+                               return p;
+                       },
+                       gs = _namespace("com.greensock"),
+                       _slice = [].slice,
+                       _emptyFunc = function() {},
+                       a, i, p, _ticker, _tickerActive,
+                       _defLookup = {},
+
+                       /**
+                        * @constructor
+                        * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
+                        * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
+                        * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
+                        * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
+                        *
+                        * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
+                        * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere,
+                        * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
+                        * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
+                        * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
+                        * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could
+                        * sandbox the banner one like:
+                        *
+                        * <script>
+                        *     var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever.
+                        * </script>
+                        * <script src="js/greensock/v1.7/TweenMax.js"></script>
+                        * <script>
+                        *     window.GreenSockGlobals = null; //reset it back to null so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...)
+                        * </script>
+                        * <script src="js/greensock/v1.6/TweenMax.js"></script>
+                        * <script>
+                        *     gs.TweenLite.to(...); //would use v1.7
+                        *     TweenLite.to(...); //would use v1.6
+                        * </script>
+                        *
+                        * @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back".
+                        * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
+                        * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
+                        * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
+                        */
+                       Definition = function(ns, dependencies, func, global) {
+                               this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
+                               _defLookup[ns] = this;
+                               this.gsClass = null;
+                               this.func = func;
+                               var _classes = [];
+                               this.check = function(init) {
+                                       var i = dependencies.length,
+                                               missing = i,
+                                               cur, a, n, cl;
+                                       while (--i > -1) {
+                                               if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
+                                                       _classes[i] = cur.gsClass;
+                                                       missing--;
+                                               } else if (init) {
+                                                       cur.sc.push(this);
+                                               }
+                                       }
+                                       if (missing === 0 && func) {
+                                               a = ("com.greensock." + ns).split(".");
+                                               n = a.pop();
+                                               cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
+
+                                               //exports to multiple environments
+                                               if (global) {
+                                                       _globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.)
+                                                       if (typeof(define) === "function" && define.amd){ //AMD
+                                                               define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
+                                                       } else if (typeof(module) !== "undefined" && module.exports){ //node
+                                                               module.exports = cl;
+                                                       }
+                                               }
+                                               for (i = 0; i < this.sc.length; i++) {
+                                                       this.sc[i].check();
+                                               }
+                                       }
+                               };
+                               this.check(true);
+                       },
+
+                       //used to create Definition instances (which basically registers a class that has dependencies).
+                       _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
+                               return new Definition(ns, dependencies, func, global);
+                       },
+
+                       //a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class).
+                       _class = gs._class = function(ns, func, global) {
+                               func = func || function() {};
+                               _gsDefine(ns, [], function(){ return func; }, global);
+                               return func;
+                       };
+
+               _gsDefine.globals = _globals;
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * Ease
+ * ----------------------------------------------------------------
+ */
+               var _baseParams = [0, 0, 1, 1],
+                       _blankArray = [],
+                       Ease = _class("easing.Ease", function(func, extraParams, type, power) {
+                               this._func = func;
+                               this._type = type || 0;
+                               this._power = power || 0;
+                               this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
+                       }, true),
+                       _easeMap = Ease.map = {},
+                       _easeReg = Ease.register = function(ease, names, types, create) {
+                               var na = names.split(","),
+                                       i = na.length,
+                                       ta = (types || "easeIn,easeOut,easeInOut").split(","),
+                                       e, name, j, type;
+                               while (--i > -1) {
+                                       name = na[i];
+                                       e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
+                                       j = ta.length;
+                                       while (--j > -1) {
+                                               type = ta[j];
+                                               _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
+                                       }
+                               }
+                       };
+               
+               p = Ease.prototype;
+               p._calcEnd = false;
+               p.getRatio = function(p) {
+                       if (this._func) {
+                               this._params[0] = p;
+                               return this._func.apply(null, this._params);
+                       }
+                       var t = this._type,
+                               pw = this._power,
+                               r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
+                       if (pw === 1) {
+                               r *= r;
+                       } else if (pw === 2) {
+                               r *= r * r;
+                       } else if (pw === 3) {
+                               r *= r * r * r;
+                       } else if (pw === 4) {
+                               r *= r * r * r * r;
+                       }
+                       return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
+               };
+
+               //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
+               a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
+               i = a.length;
+               while (--i > -1) {
+                       p = a[i]+",Power"+i;
+                       _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
+                       _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
+                       _easeReg(new Ease(null,null,3,i), p, "easeInOut");
+               }
+               _easeMap.linear = gs.easing.Linear.easeIn;
+               _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
+
+
+/*
+ * ----------------------------------------------------------------
+ * EventDispatcher
+ * ----------------------------------------------------------------
+ */
+               var EventDispatcher = _class("events.EventDispatcher", function(target) {
+                       this._listeners = {};
+                       this._eventTarget = target || this;
+               });
+               p = EventDispatcher.prototype;
+
+               p.addEventListener = function(type, callback, scope, useParam, priority) {
+                       priority = priority || 0;
+                       var list = this._listeners[type],
+                               index = 0,
+                               listener, i;
+                       if (list == null) {
+                               this._listeners[type] = list = [];
+                       }
+                       i = list.length;
+                       while (--i > -1) {
+                               listener = list[i];
+                               if (listener.c === callback && listener.s === scope) {
+                                       list.splice(i, 1);
+                               } else if (index === 0 && listener.pr < priority) {
+                                       index = i + 1;
+                               }
+                       }
+                       list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
+                       if (this === _ticker && !_tickerActive) {
+                               _ticker.wake();
+                       }
+               };
+               
+               p.removeEventListener = function(type, callback) {
+                       var list = this._listeners[type], i;
+                       if (list) {
+                               i = list.length;
+                               while (--i > -1) {
+                                       if (list[i].c === callback) {
+                                               list.splice(i, 1);
+                                               return;
+                                       }
+                               }
+                       }
+               };
+               
+               p.dispatchEvent = function(type) {
+                       var list = this._listeners[type],
+                               i, t, listener;
+                       if (list) {
+                               i = list.length;
+                               t = this._eventTarget;
+                               while (--i > -1) {
+                                       listener = list[i];
+                                       if (listener.up) {
+                                               listener.c.call(listener.s || t, {type:type, target:t});
+                                       } else {
+                                               listener.c.call(listener.s || t);
+                                       }
+                               }
+                       }
+               };
+
+
+/*
+ * ----------------------------------------------------------------
+ * Ticker
+ * ----------------------------------------------------------------
+ */
+               var _reqAnimFrame = window.requestAnimationFrame, 
+                       _cancelAnimFrame = window.cancelAnimationFrame, 
+                       _getTime = Date.now || function() {return new Date().getTime();};
+               
+               //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
+               a = ["ms","moz","webkit","o"];
+               i = a.length;
+               while (--i > -1 && !_reqAnimFrame) {
+                       _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
+                       _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
+               }
+
+               _class("Ticker", function(fps, useRAF) {
+                       var _self = this,
+                               _startTime = _getTime(),
+                               _useRAF = (useRAF !== false && _reqAnimFrame),
+                               _fps, _req, _id, _gap, _nextTime,
+                               _tick = function(manual) {
+                                       _self.time = (_getTime() - _startTime) / 1000;
+                                       var id = _id,
+                                               overlap = _self.time - _nextTime;
+                                       if (!_fps || overlap > 0 || manual === true) {
+                                               _self.frame++;
+                                               _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
+                                               _self.dispatchEvent("tick");
+                                       }
+                                       if (manual !== true && id === _id) { //make sure the ids match in case the "tick" dispatch triggered something that caused the ticker to shut down or change _useRAF or something like that.
+                                               _id = _req(_tick);
+                                       }
+                               };
+
+                       EventDispatcher.call(_self);
+                       this.time = this.frame = 0;
+                       this.tick = function() {
+                               _tick(true);
+                       };
+
+                       this.sleep = function() {
+                               if (_id == null) {
+                                       return;
+                               }
+                               if (!_useRAF || !_cancelAnimFrame) {
+                                       clearTimeout(_id);
+                               } else {
+                                       _cancelAnimFrame(_id);
+                               }
+                               _req = _emptyFunc;
+                               _id = null;
+                               if (_self === _ticker) {
+                                       _tickerActive = false;
+                               }
+                       };
+
+                       this.wake = function() {
+                               if (_id !== null) {
+                                       _self.sleep();
+                               }
+                               _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
+                               if (_self === _ticker) {
+                                       _tickerActive = true;
+                               }
+                               _tick(2);
+                       };
+
+                       this.fps = function(value) {
+                               if (!arguments.length) {
+                                       return _fps;
+                               }
+                               _fps = value;
+                               _gap = 1 / (_fps || 60);
+                               _nextTime = this.time + _gap;
+                               _self.wake();
+                       };
+
+                       this.useRAF = function(value) {
+                               if (!arguments.length) {
+                                       return _useRAF;
+                               }
+                               _self.sleep();
+                               _useRAF = value;
+                               _self.fps(_fps);
+                       };
+                       _self.fps(fps);
+
+                       //a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition.
+                       setTimeout(function() {
+                               if (_useRAF && (!_id || _self.frame < 5)) {
+                                       _self.useRAF(false);
+                               }
+                       }, 1500);
+               });
+               
+               p = gs.Ticker.prototype = new gs.events.EventDispatcher();
+               p.constructor = gs.Ticker;
+
+
+/*
+ * ----------------------------------------------------------------
+ * Animation
+ * ----------------------------------------------------------------
+ */
+               var Animation = _class("core.Animation", function(duration, vars) {
+                               this.vars = vars || {};
+                               this._duration = this._totalDuration = duration || 0;
+                               this._delay = Number(this.vars.delay) || 0;
+                               this._timeScale = 1;
+                               this._active = (this.vars.immediateRender === true);
+                               this.data = this.vars.data;
+                               this._reversed = (this.vars.reversed === true);
+                               
+                               if (!_rootTimeline) {
+                                       return;
+                               }
+                               if (!_tickerActive) {
+                                       _ticker.wake();
+                               }
+
+                               var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
+                               tl.add(this, tl._time);
+                               
+                               if (this.vars.paused) {
+                                       this.paused(true);
+                               }
+                       });
+
+               _ticker = Animation.ticker = new gs.Ticker();
+               p = Animation.prototype;
+               p._dirty = p._gc = p._initted = p._paused = false;
+               p._totalTime = p._time = 0;
+               p._rawPrevTime = -1;
+               p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
+               p._paused = false;
+               
+               p.play = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(from, suppressEvents);
+                       }
+                       return this.reversed(false).paused(false);
+               };
+               
+               p.pause = function(atTime, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(atTime, suppressEvents);
+                       }
+                       return this.paused(true);
+               };
+               
+               p.resume = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(from, suppressEvents);
+                       }
+                       return this.paused(false);
+               };
+               
+               p.seek = function(time, suppressEvents) {
+                       return this.totalTime(Number(time), suppressEvents !== false);
+               };
+               
+               p.restart = function(includeDelay, suppressEvents) {
+                       return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
+               };
+               
+               p.reverse = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek((from || this.totalDuration()), suppressEvents);
+                       }
+                       return this.reversed(true).paused(false);
+               };
+               
+               p.render = function() {
+                       
+               };
+               
+               p.invalidate = function() {
+                       return this;
+               };
+               
+               p._enabled = function (enabled, ignoreTimeline) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       this._gc = !enabled; 
+                       this._active = (enabled && !this._paused && this._totalTime > 0 && this._totalTime < this._totalDuration);
+                       if (ignoreTimeline !== true) {
+                               if (enabled && !this.timeline) {
+                                       this._timeline.add(this, this._startTime - this._delay);
+                               } else if (!enabled && this.timeline) {
+                                       this._timeline._remove(this, true);
+                               }
+                       }
+                       return false;
+               };
+       
+               
+               p._kill = function(vars, target) {
+                       return this._enabled(false, false);
+               };
+               
+               p.kill = function(vars, target) {
+                       this._kill(vars, target);
+                       return this;
+               };
+               
+               p._uncache = function(includeSelf) {
+                       var tween = includeSelf ? this : this.timeline;
+                       while (tween) {
+                               tween._dirty = true;
+                               tween = tween.timeline;
+                       }
+                       return this;
+               };
+       
+//----Animation getters/setters --------------------------------------------------------
+               
+               p.eventCallback = function(type, callback, params, scope) {
+                       if (type == null) {
+                               return null;
+                       } else if (type.substr(0,2) === "on") {
+                               var v = this.vars,
+                                       i;
+                               if (arguments.length === 1) {
+                                       return v[type];
+                               }
+                               if (callback == null) {
+                                       delete v[type];
+                               } else {
+                                       v[type] = callback;
+                                       v[type + "Params"] = params;
+                                       v[type + "Scope"] = scope;
+                                       if (params) {
+                                               i = params.length;
+                                               while (--i > -1) {
+                                                       if (params[i] === "{self}") {
+                                                               params = v[type + "Params"] = params.concat(); //copying the array avoids situations where the same array is passed to multiple tweens/timelines and {self} doesn't correctly point to each individual instance.
+                                                               params[i] = this;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (type === "onUpdate") {
+                                       this._onUpdate = callback;
+                               }
+                       }
+                       return this;
+               };
+               
+               p.delay = function(value) {
+                       if (!arguments.length) {
+                               return this._delay;
+                       }
+                       if (this._timeline.smoothChildTiming) {
+                               this.startTime( this._startTime + value - this._delay );
+                       }
+                       this._delay = value;
+                       return this;
+               };
+               
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               this._dirty = false;
+                               return this._duration;
+                       }
+                       this._duration = this._totalDuration = value;
+                       this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration. 
+                       if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
+                               this.totalTime(this._totalTime * (value / this._duration), true);
+                       }
+                       return this;
+               };
+               
+               p.totalDuration = function(value) {
+                       this._dirty = false;
+                       return (!arguments.length) ? this._totalDuration : this.duration(value);
+               };
+               
+               p.time = function(value, suppressEvents) {
+                       if (!arguments.length) {
+                               return this._time;
+                       }
+                       if (this._dirty) {
+                               this.totalDuration();
+                       }
+                       return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
+               };
+               
+               p.totalTime = function(time, suppressEvents, uncapped) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       if (!arguments.length) {
+                               return this._totalTime;
+                       }
+                       if (this._timeline) {
+                               if (time < 0 && !uncapped) {
+                                       time += this.totalDuration();
+                               }
+                               if (this._timeline.smoothChildTiming) {
+                                       if (this._dirty) {
+                                               this.totalDuration();
+                                       }
+                                       var totalDuration = this._totalDuration,
+                                               tl = this._timeline;
+                                       if (time > totalDuration && !uncapped) {
+                                               time = totalDuration;
+                                       }
+                                       this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
+                                       if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the anscestors as dirty too, so skip the function call here.
+                                               this._uncache(false);
+                                       }
+                                       if (!tl._active) {
+                                               //in case any of the anscestors had completed but should now be enabled...
+                                               while (tl._timeline) {
+                                                       tl.totalTime(tl._totalTime, true);
+                                                       tl = tl._timeline;
+                                               }
+                                       }
+                               }
+                               if (this._gc) {
+                                       this._enabled(true, false);
+                               }
+                               if (this._totalTime !== time) {
+                                       this.render(time, suppressEvents, false);
+                               }
+                       }
+                       return this;
+               };
+               
+               p.startTime = function(value) {
+                       if (!arguments.length) {
+                               return this._startTime;
+                       }
+                       if (value !== this._startTime) {
+                               this._startTime = value;
+                               if (this.timeline) if (this.timeline._sortChildren) {
+                                       this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
+                               }
+                       }
+                       return this;
+               };
+               
+               p.timeScale = function(value) {
+                       if (!arguments.length) {
+                               return this._timeScale;
+                       }
+                       value = value || 0.000001; //can't allow zero because it'll throw the math off
+                       if (this._timeline && this._timeline.smoothChildTiming) {
+                               var pauseTime = this._pauseTime,
+                                       t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
+                               this._startTime = t - ((t - this._startTime) * this._timeScale / value);
+                       }
+                       this._timeScale = value;
+                       return this._uncache(false);
+               };
+               
+               p.reversed = function(value) {
+                       if (!arguments.length) {
+                               return this._reversed;
+                       }
+                       if (value != this._reversed) {
+                               this._reversed = value;
+                               this.totalTime(this._totalTime, true);
+                       }
+                       return this;
+               };
+               
+               p.paused = function(value) {
+                       if (!arguments.length) {
+                               return this._paused;
+                       }
+                       if (value != this._paused) if (this._timeline) {
+                               if (!_tickerActive && !value) {
+                                       _ticker.wake();
+                               }
+                               var raw = this._timeline.rawTime(),
+                                       elapsed = raw - this._pauseTime;
+                               if (!value && this._timeline.smoothChildTiming) {
+                                       this._startTime += elapsed;
+                                       this._uncache(false);
+                               }
+                               this._pauseTime = value ? raw : null;
+                               this._paused = value;
+                               this._active = (!value && this._totalTime > 0 && this._totalTime < this._totalDuration);
+                               if (!value && elapsed !== 0 && this._duration !== 0) {
+                                       this.render(this._totalTime, true, true);
+                               }
+                       }
+                       if (this._gc && !value) {
+                               this._enabled(true, false);
+                       }
+                       return this;
+               };
+       
+
+/*
+ * ----------------------------------------------------------------
+ * SimpleTimeline
+ * ----------------------------------------------------------------
+ */
+               var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
+                       Animation.call(this, 0, vars);
+                       this.autoRemoveChildren = this.smoothChildTiming = true;
+               });
+               
+               p = SimpleTimeline.prototype = new Animation();
+               p.constructor = SimpleTimeline;
+               p.kill()._gc = false;
+               p._first = p._last = null;
+               p._sortChildren = false;
+
+               p.add = p.insert = function(child, position, align, stagger) {
+                       var prevTween, st;
+                       child._startTime = Number(position || 0) + child._delay;
+                       if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order).
+                               child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
+                       }
+                       if (child.timeline) {
+                               child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
+                       }
+                       child.timeline = child._timeline = this;
+                       if (child._gc) {
+                               child._enabled(true, true);
+                       }
+                       prevTween = this._last;
+                       if (this._sortChildren) {
+                               st = child._startTime;
+                               while (prevTween && prevTween._startTime > st) {
+                                       prevTween = prevTween._prev;
+                               }
+                       }
+                       if (prevTween) {
+                               child._next = prevTween._next;
+                               prevTween._next = child;
+                       } else {
+                               child._next = this._first;
+                               this._first = child;
+                       }
+                       if (child._next) {
+                               child._next._prev = child;
+                       } else {
+                               this._last = child;
+                       }
+                       child._prev = prevTween;
+                       if (this._timeline) {
+                               this._uncache(true);
+                       }
+                       return this;
+               };
+               
+               p._remove = function(tween, skipDisable) {
+                       if (tween.timeline === this) {
+                               if (!skipDisable) {
+                                       tween._enabled(false, true);
+                               }
+                               tween.timeline = null;
+                               
+                               if (tween._prev) {
+                                       tween._prev._next = tween._next;
+                               } else if (this._first === tween) {
+                                       this._first = tween._next;
+                               }
+                               if (tween._next) {
+                                       tween._next._prev = tween._prev;
+                               } else if (this._last === tween) {
+                                       this._last = tween._prev;
+                               }
+                               
+                               if (this._timeline) {
+                                       this._uncache(true);
+                               }
+                       }
+                       return this;
+               };
+               
+               p.render = function(time, suppressEvents, force) {
+                       var tween = this._first, 
+                               next;
+                       this._totalTime = this._time = this._rawPrevTime = time;
+                       while (tween) {
+                               next = tween._next; //record it here because the value could change after rendering...
+                               if (tween._active || (time >= tween._startTime && !tween._paused)) {
+                                       if (!tween._reversed) {
+                                               tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                       } else {
+                                               tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                       }
+                               }
+                               tween = next;
+                       }
+               };
+                               
+               p.rawTime = function() {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       return this._totalTime;                 
+               };
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * TweenLite
+ * ----------------------------------------------------------------
+ */
+               var TweenLite = _class("TweenLite", function(target, duration, vars) {
+                               Animation.call(this, duration, vars);
+                               
+                               if (target == null) {
+                                       throw "Cannot tween a null target.";
+                               }
+
+                               this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
+
+                               var isSelector = (target.jquery || (target.length && target[0] && target[0].nodeType && target[0].style && !target.nodeType)),
+                                       overwrite = this.vars.overwrite,
+                                       i, targ, targets;
+
+                               this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
+
+                               if ((isSelector || target instanceof Array) && typeof(target[0]) !== "number") {
+                                       this._targets = targets = _slice.call(target, 0);
+                                       this._propLookup = [];
+                                       this._siblings = [];
+                                       for (i = 0; i < targets.length; i++) {
+                                               targ = targets[i];
+                                               if (!targ) {
+                                                       targets.splice(i--, 1);
+                                                       continue;
+                                               } else if (typeof(targ) === "string") {
+                                                       targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
+                                                       if (typeof(targ) === "string") {
+                                                               targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
+                                                       }
+                                                       continue;
+                                               } else if (targ.length && targ[0] && targ[0].nodeType && targ[0].style && !targ.nodeType) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself.
+                                                       targets.splice(i--, 1);
+                                                       this._targets = targets = targets.concat(_slice.call(targ, 0));
+                                                       continue;
+                                               }
+                                               this._siblings[i] = _register(targ, this, false);
+                                               if (overwrite === 1) if (this._siblings[i].length > 1) {
+                                                       _applyOverwrite(targ, this, null, 1, this._siblings[i]);
+                                               }
+                                       }
+                                       
+                               } else {
+                                       this._propLookup = {};
+                                       this._siblings = _register(target, this, false);
+                                       if (overwrite === 1) if (this._siblings.length > 1) {
+                                               _applyOverwrite(target, this, null, 1, this._siblings);
+                                       }
+                               }
+                               if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
+                                       this.render(-this._delay, false, true);
+                               }
+                       }, true),
+                       _isSelector = function(v) {
+                               return (v.length && v[0] && v[0].nodeType && v[0].style && !v.nodeType);
+                       },
+                       _autoCSS = function(vars, target) {
+                               var css = {},
+                                       p;
+                               for (p in vars) {
+                                       if (!_reservedProps[p] && (!(p in target) || p === "x" || p === "y" || p === "width" || p === "height" || p === "className") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties.
+                                               css[p] = vars[p];
+                                               delete vars[p];
+                                       }
+                               }
+                               vars.css = css;
+                       };
+       
+               p = TweenLite.prototype = new Animation();
+               p.constructor = TweenLite;
+               p.kill()._gc = false;
+       
+//----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
+       
+               p.ratio = 0;
+               p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
+               p._notifyPluginsOfEnabled = false;
+               
+               TweenLite.version = "1.9.8";
+               TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
+               TweenLite.defaultOverwrite = "auto";
+               TweenLite.ticker = _ticker;
+               TweenLite.autoSleep = true;
+               TweenLite.selector = window.$ || window.jQuery || function(e) { if (window.$) { TweenLite.selector = window.$; return window.$(e); } return window.document ? window.document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e) : e; };
+
+               var _internals = TweenLite._internals = {}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object.
+                       _plugins = TweenLite._plugins = {},
+                       _tweenLookup = TweenLite._tweenLookup = {}, 
+                       _tweenLookupNum = 0,
+                       _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1},
+                       _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
+                       _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(), 
+                       _rootTimeline = Animation._rootTimeline = new SimpleTimeline();
+                       
+               _rootTimeline._startTime = _ticker.time;
+               _rootFramesTimeline._startTime = _ticker.frame;
+               _rootTimeline._active = _rootFramesTimeline._active = true;
+               
+               Animation._updateRoot = function() {
+                               _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
+                               _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
+                               if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
+                                       var i, a, p;
+                                       for (p in _tweenLookup) {
+                                               a = _tweenLookup[p].tweens;
+                                               i = a.length;
+                                               while (--i > -1) {
+                                                       if (a[i]._gc) {
+                                                               a.splice(i, 1);
+                                                       }
+                                               }
+                                               if (a.length === 0) {
+                                                       delete _tweenLookup[p];
+                                               }
+                                       }
+                                       //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly
+                                       p = _rootTimeline._first;
+                                       if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
+                                               while (p && p._paused) {
+                                                       p = p._next;
+                                               }
+                                               if (!p) {
+                                                       _ticker.sleep();
+                                               }
+                                       }
+                               }
+                       };
+               
+               _ticker.addEventListener("tick", Animation._updateRoot);
+               
+               var _register = function(target, tween, scrub) {
+                               var id = target._gsTweenID, a, i;
+                               if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
+                                       _tweenLookup[id] = {target:target, tweens:[]};
+                               }
+                               if (tween) {
+                                       a = _tweenLookup[id].tweens;
+                                       a[(i = a.length)] = tween;
+                                       if (scrub) {
+                                               while (--i > -1) {
+                                                       if (a[i] === tween) {
+                                                               a.splice(i, 1);
+                                                       }
+                                               }
+                                       }
+                               }
+                               return _tweenLookup[id].tweens;
+                       },
+                       
+                       _applyOverwrite = function(target, tween, props, mode, siblings) {
+                               var i, changed, curTween, l;
+                               if (mode === 1 || mode >= 4) {
+                                       l = siblings.length;
+                                       for (i = 0; i < l; i++) {
+                                               if ((curTween = siblings[i]) !== tween) {
+                                                       if (!curTween._gc) if (curTween._enabled(false, false)) {
+                                                               changed = true;
+                                                       }
+                                               } else if (mode === 5) {
+                                                       break;
+                                               }
+                                       }
+                                       return changed;
+                               }
+                               //NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example)
+                               var startTime = tween._startTime + 0.0000000001, 
+                                       overlaps = [], 
+                                       oCount = 0,
+                                       zeroDur = (tween._duration === 0),
+                                       globalStart;
+                               i = siblings.length;
+                               while (--i > -1) {
+                                       if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
+                                               //ignore
+                                       } else if (curTween._timeline !== tween._timeline) {
+                                               globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
+                                               if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
+                                                       overlaps[oCount++] = curTween;
+                                               }
+                                       } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale + 0.0000000001 > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
+                                               overlaps[oCount++] = curTween;
+                                       }
+                               }
+                               
+                               i = oCount;
+                               while (--i > -1) {
+                                       curTween = overlaps[i];
+                                       if (mode === 2) if (curTween._kill(props, target)) {
+                                               changed = true;
+                                       }
+                                       if (mode !== 2 || (!curTween._firstPT && curTween._initted)) { 
+                                               if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
+                                                       changed = true;
+                                               }
+                                       }
+                               }
+                               return changed;
+                       },
+                       
+                       _checkOverlap = function(tween, reference, zeroDur) {
+                               var tl = tween._timeline, 
+                                       ts = tl._timeScale, 
+                                       t = tween._startTime,
+                                       min = 0.0000000001; //we use this to protect from rounding errors.
+                               while (tl._timeline) {
+                                       t += tl._startTime;
+                                       ts *= tl._timeScale;
+                                       if (tl._paused) {
+                                               return -100;
+                                       }
+                                       tl = tl._timeline;
+                               }
+                               t /= ts;
+                               return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * min)) ? min : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + min) ? 0 : t - reference - min;
+                       };
+
+       
+//---- TweenLite instance methods -----------------------------------------------------------------------------
+
+               p._init = function() {
+                       var v = this.vars,
+                               op = this._overwrittenProps,
+                               dur = this._duration,
+                               ease = v.ease,
+                               i, initPlugins, pt, p;
+                       if (v.startAt) {
+                               v.startAt.overwrite = 0;
+                               v.startAt.immediateRender = true;
+                               this._startAt = TweenLite.to(this.target, 0, v.startAt);
+                               if (v.immediateRender) {
+                                       this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()).
+                                       if (this._time === 0 && dur !== 0) {
+                                               return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.
+                                       }
+                               }
+                       } else if (v.runBackwards && v.immediateRender && dur !== 0) {
+                               //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)
+                               if (this._startAt) {
+                                       this._startAt.render(-1, true);
+                                       this._startAt = null;
+                               } else if (this._time === 0) {
+                                       pt = {};
+                                       for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through.
+                                               if (!_reservedProps[p] || p === "autoCSS") {
+                                                       pt[p] = v[p];
+                                               }
+                                       }
+                                       pt.overwrite = 0;
+                                       this._startAt = TweenLite.to(this.target, 0, pt);
+                                       return;
+                               }
+                       }
+                       if (!ease) {
+                               this._ease = TweenLite.defaultEase;
+                       } else if (ease instanceof Ease) {
+                               this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
+                       } else {
+                               this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
+                       }
+                       this._easeType = this._ease._type;
+                       this._easePower = this._ease._power;
+                       this._firstPT = null;
+                       
+                       if (this._targets) {
+                               i = this._targets.length;
+                               while (--i > -1) {
+                                       if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
+                                               initPlugins = true;
+                                       }
+                               }
+                       } else {
+                               initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
+                       }
+                       
+                       if (initPlugins) {
+                               TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
+                       }
+                       if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live.
+                               this._enabled(false, false);
+                       }
+                       if (v.runBackwards) {
+                               pt = this._firstPT;
+                               while (pt) {
+                                       pt.s += pt.c;
+                                       pt.c = -pt.c;
+                                       pt = pt._next;
+                               }
+                       }
+                       this._onUpdate = v.onUpdate;
+                       this._initted = true;
+               };
+               
+               p._initProps = function(target, propLookup, siblings, overwrittenProps) {
+                       var p, i, initPlugins, plugin, a, pt, v;
+                       if (target == null) {
+                               return false;
+                       }
+                       if (!this.vars.css) if (target.style) if (target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity)
+                               _autoCSS(this.vars, target);
+                       }
+                       for (p in this.vars) {
+                               if (_reservedProps[p]) { 
+                                       if (p === "onStartParams" || p === "onUpdateParams" || p === "onCompleteParams" || p === "onReverseCompleteParams" || p === "onRepeatParams") if ((a = this.vars[p])) {
+                                               i = a.length;
+                                               while (--i > -1) {
+                                                       if (a[i] === "{self}") {
+                                                               a = this.vars[p] = a.concat(); //copy the array in case the user referenced the same array in multiple tweens/timelines (each {self} should be unique)
+                                                               a[i] = this;
+                                                       }
+                                               }
+                                       }
+                                       
+                               } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
+                                       
+                                       //t - target            [object]
+                                       //p - property          [string]
+                                       //s - start                     [number]
+                                       //c - change            [number]
+                                       //f - isFunction        [boolean]
+                                       //n - name                      [string]
+                                       //pg - isPlugin         [boolean]
+                                       //pr - priority         [number]
+                                       this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
+                                       i = plugin._overwriteProps.length;
+                                       while (--i > -1) {
+                                               propLookup[plugin._overwriteProps[i]] = this._firstPT;
+                                       }
+                                       if (plugin._priority || plugin._onInitAllProps) {
+                                               initPlugins = true;
+                                       }
+                                       if (plugin._onDisable || plugin._onEnable) {
+                                               this._notifyPluginsOfEnabled = true;
+                                       }
+                                       
+                               } else {
+                                       this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
+                                       pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
+                                       v = this.vars[p];
+                                       pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
+                               }
+                               if (pt) if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                       }
+                       
+                       if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first)
+                               return this._initProps(target, propLookup, siblings, overwrittenProps);
+                       }
+                       if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
+                               this._kill(propLookup, target);
+                               return this._initProps(target, propLookup, siblings, overwrittenProps);
+                       }
+                       return initPlugins;
+               };
+               
+               p.render = function(time, suppressEvents, force) {
+                       var prevTime = this._time,
+                               isComplete, callback, pt;
+                       if (time >= this._duration) {
+                               this._totalTime = this._time = this._duration;
+                               this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
+                               if (!this._reversed) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                               }
+                               if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                       if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time) {
+                                               force = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                                       if (suppressEvents) {
+                                                               time = -1; //when a callback is placed at the VERY beginning of a timeline and it repeats (or if timeline.seek(0) is called), events are normally suppressed during those behaviors (repeat or seek()) and without adjusting the _rawPrevTime back slightly, the onComplete wouldn't get called on the next render. This only applies to zero-duration tweens/callbacks of course.
+                                                       }
+                                               }
+                                       }
+                                       this._rawPrevTime = time;
+                               }
+                               
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = 0;
+                               this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
+                               if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               if (this._rawPrevTime >= 0) {
+                                                       force = true;
+                                               }
+                                               this._rawPrevTime = time;
+                                       }
+                               } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
+                                       force = true;
+                               }
+                               
+                       } else {
+                               this._totalTime = this._time = time;
+                               
+                               if (this._easeType) {
+                                       var r = time / this._duration, type = this._easeType, pow = this._easePower;
+                                       if (type === 1 || (type === 3 && r >= 0.5)) {
+                                               r = 1 - r;
+                                       }
+                                       if (type === 3) {
+                                               r *= 2;
+                                       }
+                                       if (pow === 1) {
+                                               r *= r;
+                                       } else if (pow === 2) {
+                                               r *= r * r;
+                                       } else if (pow === 3) {
+                                               r *= r * r * r;
+                                       } else if (pow === 4) {
+                                               r *= r * r * r * r;
+                                       }
+                                       
+                                       if (type === 1) {
+                                               this.ratio = 1 - r;
+                                       } else if (type === 2) {
+                                               this.ratio = r;
+                                       } else if (time / this._duration < 0.5) {
+                                               this.ratio = r / 2;
+                                       } else {
+                                               this.ratio = 1 - (r / 2);
+                                       }
+                                       
+                               } else {
+                                       this.ratio = this._ease.getRatio(time / this._duration);
+                               }
+                               
+                       }
+
+                       if (this._time === prevTime && !force) {
+                               return;
+                       } else if (!this._initted) {
+                               this._init();
+                               if (!this._initted) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly.
+                                       return;
+                               }
+                               //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
+                               if (this._time && !isComplete) {
+                                       this.ratio = this._ease.getRatio(this._time / this._duration);
+                               } else if (isComplete && this._ease._calcEnd) {
+                                       this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
+                               }
+                       }
+                       
+                       if (!this._active) if (!this._paused) {
+                               this._active = true;  //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
+                       }
+                       if (prevTime === 0) {
+                               if (this._startAt) {
+                                       if (time >= 0) {
+                                               this._startAt.render(time, suppressEvents, force);
+                                       } else if (!callback) {
+                                               callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
+                                       }
+                               }
+                               if (this.vars.onStart) if (this._time !== 0 || this._duration === 0) if (!suppressEvents) {
+                                       this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                               }
+                       }
+
+                       pt = this._firstPT;
+                       while (pt) {
+                               if (pt.f) {
+                                       pt.t[pt.p](pt.c * this.ratio + pt.s);
+                               } else {
+                                       pt.t[pt.p] = pt.c * this.ratio + pt.s;
+                               }
+                               pt = pt._next;
+                       }
+                       
+                       if (this._onUpdate) {
+                               if (time < 0) if (this._startAt) {
+                                       this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
+                               }
+                               if (!suppressEvents) {
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                       }
+                       
+                       if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (time < 0 && this._startAt && !this._onUpdate) {
+                                       this._startAt.render(time, suppressEvents, force);
+                               }
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+                       
+               };
+               
+               p._kill = function(vars, target) {
+                       if (vars === "all") {
+                               vars = null;
+                       }
+                       if (vars == null) if (target == null || target === this.target) {
+                               return this._enabled(false, false);
+                       }
+                       target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
+                       var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
+                       if ((target instanceof Array || _isSelector(target)) && typeof(target[0]) !== "number") {
+                               i = target.length;
+                               while (--i > -1) {
+                                       if (this._kill(vars, target[i])) {
+                                               changed = true;
+                                       }
+                               }
+                       } else {
+                               if (this._targets) {
+                                       i = this._targets.length;
+                                       while (--i > -1) {
+                                               if (target === this._targets[i]) {
+                                                       propLookup = this._propLookup[i] || {};
+                                                       this._overwrittenProps = this._overwrittenProps || [];
+                                                       overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
+                                                       break;
+                                               }
+                                       }
+                               } else if (target !== this.target) {
+                                       return false;
+                               } else {
+                                       propLookup = this._propLookup;
+                                       overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
+                               }
+
+                               if (propLookup) {
+                                       killProps = vars || propLookup;
+                                       record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (vars == null || vars._tempKill !== true)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin)
+                                       for (p in killProps) {
+                                               if ((pt = propLookup[p])) {
+                                                       if (pt.pg && pt.t._kill(killProps)) {
+                                                               changed = true; //some plugins need to be notified so they can perform cleanup tasks first
+                                                       }
+                                                       if (!pt.pg || pt.t._overwriteProps.length === 0) {
+                                                               if (pt._prev) {
+                                                                       pt._prev._next = pt._next;
+                                                               } else if (pt === this._firstPT) {
+                                                                       this._firstPT = pt._next;
+                                                               }
+                                                               if (pt._next) {
+                                                                       pt._next._prev = pt._prev;
+                                                               }
+                                                               pt._next = pt._prev = null;
+                                                       }
+                                                       delete propLookup[p];
+                                               }
+                                               if (record) { 
+                                                       overwrittenProps[p] = 1;
+                                               }
+                                       }
+                                       if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.
+                                               this._enabled(false, false);
+                                       }
+                               }
+                       }
+                       return changed;
+               };
+       
+               p.invalidate = function() {
+                       if (this._notifyPluginsOfEnabled) {
+                               TweenLite._onPluginEvent("_onDisable", this);
+                       }
+                       this._firstPT = null;
+                       this._overwrittenProps = null;
+                       this._onUpdate = null;
+                       this._startAt = null;
+                       this._initted = this._active = this._notifyPluginsOfEnabled = false;
+                       this._propLookup = (this._targets) ? {} : [];
+                       return this;
+               };
+               
+               p._enabled = function(enabled, ignoreTimeline) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       if (enabled && this._gc) {
+                               var targets = this._targets,
+                                       i;
+                               if (targets) {
+                                       i = targets.length;
+                                       while (--i > -1) {
+                                               this._siblings[i] = _register(targets[i], this, true);
+                                       }
+                               } else {
+                                       this._siblings = _register(this.target, this, true);
+                               }
+                       }
+                       Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
+                       if (this._notifyPluginsOfEnabled) if (this._firstPT) {
+                               return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
+                       }
+                       return false;
+               };
+       
+       
+//----TweenLite static methods -----------------------------------------------------
+               
+               TweenLite.to = function(target, duration, vars) {
+                       return new TweenLite(target, duration, vars);
+               };
+               
+               TweenLite.from = function(target, duration, vars) {
+                       vars.runBackwards = true;
+                       vars.immediateRender = (vars.immediateRender != false);
+                       return new TweenLite(target, duration, vars);
+               };
+               
+               TweenLite.fromTo = function(target, duration, fromVars, toVars) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return new TweenLite(target, duration, toVars);
+               };
+               
+               TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
+                       return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
+               };
+               
+               TweenLite.set = function(target, vars) {
+                       return new TweenLite(target, 0, vars);
+               };
+               
+               TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, vars) {
+                       var a = TweenLite.getTweensOf(target), 
+                               i = a.length;
+                       while (--i > -1) {
+                               a[i]._kill(vars, target);
+                       }
+               };
+               
+               TweenLite.getTweensOf = function(target) {
+                       if (target == null) { return []; }
+                       target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
+                       var i, a, j, t;
+                       if ((target instanceof Array || _isSelector(target)) && typeof(target[0]) !== "number") {
+                               i = target.length;
+                               a = [];
+                               while (--i > -1) {
+                                       a = a.concat(TweenLite.getTweensOf(target[i]));
+                               }
+                               i = a.length;
+                               //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
+                               while (--i > -1) {
+                                       t = a[i];
+                                       j = i;
+                                       while (--j > -1) {
+                                               if (t === a[j]) {
+                                                       a.splice(i, 1);
+                                               }
+                                       }
+                               }
+                       } else {
+                               a = _register(target).concat();
+                               i = a.length;
+                               while (--i > -1) {
+                                       if (a[i]._gc) {
+                                               a.splice(i, 1);
+                                       }
+                               }
+                       }
+                       return a;
+               };
+               
+               
+               
+/*
+ * ----------------------------------------------------------------
+ * TweenPlugin   (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another <script> call before loading plugins which is easy to forget)
+ * ----------------------------------------------------------------
+ */
+               var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
+                                       this._overwriteProps = (props || "").split(",");
+                                       this._propName = this._overwriteProps[0];
+                                       this._priority = priority || 0;
+                                       this._super = TweenPlugin.prototype;
+                               }, true);
+               
+               p = TweenPlugin.prototype;
+               TweenPlugin.version = "1.9.1";
+               TweenPlugin.API = 2;
+               p._firstPT = null;              
+                       
+               p._addTween = function(target, prop, start, end, overwriteProp, round) {
+                       var c, pt;
+                       if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0)+"1", 10) * Number(end.substr(2)))) {
+                               this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
+                               if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                       }
+               };
+                       
+               p.setRatio = function(v) {
+                       var pt = this._firstPT,
+                               min = 0.000001,
+                               val;
+                       while (pt) {
+                               val = pt.c * v + pt.s;
+                               if (pt.r) {
+                                       val = (val + ((val > 0) ? 0.5 : -0.5)) >> 0; //about 4x faster than Math.round()
+                               } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
+                                       val = 0;
+                               }
+                               if (pt.f) {
+                                       pt.t[pt.p](val);
+                               } else {
+                                       pt.t[pt.p] = val;
+                               }
+                               pt = pt._next;
+                       }
+               };
+                       
+               p._kill = function(lookup) {
+                       var a = this._overwriteProps,
+                               pt = this._firstPT,
+                               i;
+                       if (lookup[this._propName] != null) {
+                               this._overwriteProps = [];
+                       } else {
+                               i = a.length;
+                               while (--i > -1) {
+                                       if (lookup[a[i]] != null) {
+                                               a.splice(i, 1);
+                                       }
+                               }
+                       }
+                       while (pt) {
+                               if (lookup[pt.n] != null) {
+                                       if (pt._next) {
+                                               pt._next._prev = pt._prev;
+                                       }
+                                       if (pt._prev) {
+                                               pt._prev._next = pt._next;
+                                               pt._prev = null;
+                                       } else if (this._firstPT === pt) {
+                                               this._firstPT = pt._next;
+                                       }
+                               }
+                               pt = pt._next;
+                       }
+                       return false;
+               };
+                       
+               p._roundProps = function(lookup, value) {
+                       var pt = this._firstPT;
+                       while (pt) {
+                               if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here.
+                                       pt.r = value;
+                               }
+                               pt = pt._next;
+                       }
+               };
+               
+               TweenLite._onPluginEvent = function(type, tween) {
+                       var pt = tween._firstPT, 
+                               changed, pt2, first, last, next;
+                       if (type === "_onInitAllProps") {
+                               //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame.
+                               while (pt) {
+                                       next = pt._next;
+                                       pt2 = first;
+                                       while (pt2 && pt2.pr > pt.pr) {
+                                               pt2 = pt2._next;
+                                       }
+                                       if ((pt._prev = pt2 ? pt2._prev : last)) {
+                                               pt._prev._next = pt;
+                                       } else {
+                                               first = pt;
+                                       }
+                                       if ((pt._next = pt2)) {
+                                               pt2._prev = pt;
+                                       } else {
+                                               last = pt;
+                                       }
+                                       pt = next;
+                               }
+                               pt = tween._firstPT = first;
+                       }
+                       while (pt) {
+                               if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
+                                       changed = true;
+                               }
+                               pt = pt._next;
+                       }
+                       return changed;
+               };
+               
+               TweenPlugin.activate = function(plugins) {
+                       var i = plugins.length;
+                       while (--i > -1) {
+                               if (plugins[i].API === TweenPlugin.API) {
+                                       _plugins[(new plugins[i]())._propName] = plugins[i];
+                               }
+                       }
+                       return true;
+               };
+
+               //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations.
+               _gsDefine.plugin = function(config) {
+                       if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
+                       var propName = config.propName,
+                               priority = config.priority || 0,
+                               overwriteProps = config.overwriteProps,
+                               map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
+                               Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
+                                       function() {
+                                               TweenPlugin.call(this, propName, priority);
+                                               this._overwriteProps = overwriteProps || [];
+                                       }, (config.global === true)),
+                               p = Plugin.prototype = new TweenPlugin(propName),
+                               prop;
+                       p.constructor = Plugin;
+                       Plugin.API = config.API;
+                       for (prop in map) {
+                               if (typeof(config[prop]) === "function") {
+                                       p[map[prop]] = config[prop];
+                               }
+                       }
+                       Plugin.version = config.version;
+                       TweenPlugin.activate([Plugin]);
+                       return Plugin;
+               };
+
+
+               //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you. 
+               a = window._gsQueue;
+               if (a) {
+                       for (i = 0; i < a.length; i++) {
+                               a[i]();
+                       }
+                       for (p in _defLookup) {
+                               if (!_defLookup[p].func) {
+                                       window.console.log("GSAP encountered missing dependency: com.greensock." + p);
+                               }
+                       }
+               }
+
+               _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
+       
+})(window);
\ No newline at end of file
diff --git a/js/libs/gsap/TweenMax.js b/js/libs/gsap/TweenMax.js
new file mode 100644 (file)
index 0000000..1579b07
--- /dev/null
@@ -0,0 +1,6538 @@
+/*!
+ * VERSION: beta 1.9.8
+ * DATE: 2013-06-05
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ * 
+ * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
+               
+               var _slice = [].slice,
+                       TweenMax = function(target, duration, vars) {
+                               TweenLite.call(this, target, duration, vars);
+                               this._cycle = 0;
+                               this._yoyo = (this.vars.yoyo === true);
+                               this._repeat = this.vars.repeat || 0;
+                               this._repeatDelay = this.vars.repeatDelay || 0;
+                               this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
+                       },
+                       _isSelector = function(v) {
+                               return (v.jquery || (v.length && v[0] && v[0].nodeType && v[0].style && !v.nodeType));
+                       },
+                       p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
+                       _blankArray = [];
+
+               TweenMax.version = "1.9.8";
+               p.constructor = TweenMax;
+               p.kill()._gc = false;
+               TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
+               TweenMax.getTweensOf = TweenLite.getTweensOf;
+               TweenMax.ticker = TweenLite.ticker;
+       
+               p.invalidate = function() {
+                       this._yoyo = (this.vars.yoyo === true);
+                       this._repeat = this.vars.repeat || 0;
+                       this._repeatDelay = this.vars.repeatDelay || 0;
+                       this._uncache(true);
+                       return TweenLite.prototype.invalidate.call(this);
+               };
+               
+               p.updateTo = function(vars, resetDuration) {
+                       var curRatio = this.ratio, p;
+                       if (resetDuration && this.timeline && this._startTime < this._timeline._time) {
+                               this._startTime = this._timeline._time;
+                               this._uncache(false);
+                               if (this._gc) {
+                                       this._enabled(true, false);
+                               } else {
+                                       this._timeline.insert(this, this._startTime - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
+                               }
+                       }
+                       for (p in vars) {
+                               this.vars[p] = vars[p];
+                       }
+                       if (this._initted) {
+                               if (resetDuration) {
+                                       this._initted = false;
+                               } else {
+                                       if (this._notifyPluginsOfEnabled && this._firstPT) {
+                                               TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
+                                       }
+                                       if (this._time / this._duration > 0.998) { //if the tween has finished (or come extremely close to finishing), we just need to rewind it to 0 and then render it again at the end which forces it to re-initialize (parsing the new vars). We allow tweens that are close to finishing (but haven't quite finished) to work this way too because otherwise, the values are so small when determining where to project the starting values that binary math issues creep in and can make the tween appear to render incorrectly when run backwards. 
+                                               var prevTime = this._time;
+                                               this.render(0, true, false);
+                                               this._initted = false;
+                                               this.render(prevTime, true, false);
+                                       } else if (this._time > 0) {
+                                               this._initted = false;
+                                               this._init();
+                                               var inv = 1 / (1 - curRatio),
+                                                       pt = this._firstPT, endValue;
+                                               while (pt) {
+                                                       endValue = pt.s + pt.c; 
+                                                       pt.c *= inv;
+                                                       pt.s = endValue - pt.c;
+                                                       pt = pt._next;
+                                               }
+                                       }
+                               }
+                       }
+                       return this;
+               };
+                               
+               p.render = function(time, suppressEvents, force) {
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
+                               prevTime = this._time,
+                               prevTotalTime = this._totalTime, 
+                               prevCycle = this._cycle, 
+                               isComplete, callback, pt, cycleDuration, r, type, pow;
+                       if (time >= totalDur) {
+                               this._totalTime = totalDur;
+                               this._cycle = this._repeat;
+                               if (this._yoyo && (this._cycle & 1) !== 0) {
+                                       this._time = 0;
+                                       this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
+                               } else {
+                                       this._time = this._duration;
+                                       this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
+                               }
+                               if (!this._reversed) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                               }
+                               if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                       if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time) {
+                                               force = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                                       if (suppressEvents) {
+                                                               time = -1; //when a callback is placed at the VERY beginning of a timeline and it repeats (or if timeline.seek(0) is called), events are normally suppressed during those behaviors (repeat or seek()) and without adjusting the _rawPrevTime back slightly, the onComplete wouldn't get called on the next render. This only applies to zero-duration tweens/callbacks of course.
+                                                       }
+                                               }
+                                       }
+                                       this._rawPrevTime = time;
+                               }
+                               
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = this._cycle = 0;
+                               this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
+                               if (prevTotalTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               if (this._rawPrevTime >= 0) {
+                                                       force = true;
+                                               }
+                                               this._rawPrevTime = time;
+                                       }
+                               } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
+                                       force = true;
+                               }
+                       } else {
+                               this._totalTime = this._time = time;
+                               
+                               if (this._repeat !== 0) {
+                                       cycleDuration = this._duration + this._repeatDelay;
+                                       this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but Flash reports it as 0.79999999!)
+                                       if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
+                                               this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
+                                       }
+                                       this._time = this._totalTime - (this._cycle * cycleDuration);
+                                       if (this._yoyo) if ((this._cycle & 1) !== 0) {
+                                               this._time = this._duration - this._time;
+                                       }
+                                       if (this._time > this._duration) {
+                                               this._time = this._duration;
+                                       } else if (this._time < 0) {
+                                               this._time = 0;
+                                       }
+                               }
+                               
+                               if (this._easeType) {
+                                       r = this._time / this._duration;
+                                       type = this._easeType;
+                                       pow = this._easePower;
+                                       if (type === 1 || (type === 3 && r >= 0.5)) {
+                                               r = 1 - r;
+                                       }
+                                       if (type === 3) {
+                                               r *= 2;
+                                       }
+                                       if (pow === 1) {
+                                               r *= r;
+                                       } else if (pow === 2) {
+                                               r *= r * r;
+                                       } else if (pow === 3) {
+                                               r *= r * r * r;
+                                       } else if (pow === 4) {
+                                               r *= r * r * r * r;
+                                       }
+                                       
+                                       if (type === 1) {
+                                               this.ratio = 1 - r;
+                                       } else if (type === 2) {
+                                               this.ratio = r;
+                                       } else if (this._time / this._duration < 0.5) {
+                                               this.ratio = r / 2;
+                                       } else {
+                                               this.ratio = 1 - (r / 2);
+                                       }
+                                       
+                               } else {
+                                       this.ratio = this._ease.getRatio(this._time / this._duration);
+                               }
+                               
+                       }
+                               
+                       if (prevTime === this._time && !force) {
+                               if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                               return;
+                       } else if (!this._initted) {
+                               this._init();
+                               if (!this._initted) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly.
+                                       return;
+                               }
+                               //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
+                               if (this._time && !isComplete) {
+                                       this.ratio = this._ease.getRatio(this._time / this._duration);
+                               } else if (isComplete && this._ease._calcEnd) {
+                                       this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
+                               }
+                       }
+                       
+                       if (!this._active) if (!this._paused) {
+                               this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
+                       }
+                       if (prevTotalTime === 0) {
+                               if (this._startAt) {
+                                       if (time >= 0) {
+                                               this._startAt.render(time, suppressEvents, force);
+                                       } else if (!callback) {
+                                               callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
+                                       }
+                               }
+                               if (this.vars.onStart) if (this._totalTime !== 0 || this._duration === 0) if (!suppressEvents) {
+                                       this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                               }
+                       }
+                       
+                       pt = this._firstPT;
+                       while (pt) {
+                               if (pt.f) {
+                                       pt.t[pt.p](pt.c * this.ratio + pt.s);
+                               } else {
+                                       pt.t[pt.p] = pt.c * this.ratio + pt.s;
+                               }
+                               pt = pt._next;
+                       }
+                       
+                       if (this._onUpdate) {
+                               if (time < 0) if (this._startAt) {
+                                       this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
+                               }
+                               if (!suppressEvents) {
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                       }
+                       if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
+                               this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
+                       }
+                       if (callback) if (!this._gc) { //check gc because there's a chance that kill() could be called in an onUpdate
+                               if (time < 0 && this._startAt && !this._onUpdate) {
+                                       this._startAt.render(time, suppressEvents, force);
+                               }
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+               
+//---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
+               
+               TweenMax.to = function(target, duration, vars) {
+                       return new TweenMax(target, duration, vars);
+               };
+               
+               TweenMax.from = function(target, duration, vars) {
+                       vars.runBackwards = true;
+                       vars.immediateRender = (vars.immediateRender != false);
+                       return new TweenMax(target, duration, vars);
+               };
+               
+               TweenMax.fromTo = function(target, duration, fromVars, toVars) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return new TweenMax(target, duration, toVars);
+               };
+               
+               TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       stagger = stagger || 0;
+                       var delay = vars.delay || 0,
+                               a = [],
+                               finalComplete = function() {
+                                       if (vars.onComplete) {
+                                               vars.onComplete.apply(vars.onCompleteScope || this, vars.onCompleteParams || _blankArray);
+                                       }
+                                       onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
+                               },
+                               l, copy, i, p;
+                       if (!(targets instanceof Array)) {
+                               if (typeof(targets) === "string") {
+                                       targets = TweenLite.selector(targets) || targets;
+                               }
+                               if (_isSelector(targets)) {
+                                       targets = _slice.call(targets, 0);
+                               }
+                       }
+                       l = targets.length;
+                       for (i = 0; i < l; i++) {
+                               copy = {};
+                               for (p in vars) {
+                                       copy[p] = vars[p];
+                               }
+                               copy.delay = delay;
+                               if (i === l - 1 && onCompleteAll) {
+                                       copy.onComplete = finalComplete;
+                               }
+                               a[i] = new TweenMax(targets[i], duration, copy);
+                               delay += stagger;
+                       }
+                       return a;
+               };
+               
+               TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       vars.runBackwards = true;
+                       vars.immediateRender = (vars.immediateRender != false);
+                       return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+               
+               TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+                               
+               TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
+                       return new TweenMax(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
+               };
+               
+               TweenMax.set = function(target, vars) {
+                       return new TweenMax(target, 0, vars);
+               };
+               
+               TweenMax.isTweening = function(target) {
+                       var a = TweenLite.getTweensOf(target),
+                               i = a.length,
+                               tween;
+                       while (--i > -1) {
+                               tween = a[i];
+                               if (tween._active || (tween._startTime === tween._timeline._time && tween._timeline._active)) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               };
+               
+               var _getChildrenOf = function(timeline, includeTimelines) {
+                               var a = [],
+                                       cnt = 0,
+                                       tween = timeline._first;
+                               while (tween) {
+                                       if (tween instanceof TweenLite) {
+                                               a[cnt++] = tween;
+                                       } else {
+                                               if (includeTimelines) {
+                                                       a[cnt++] = tween;
+                                               }
+                                               a = a.concat(_getChildrenOf(tween, includeTimelines));
+                                               cnt = a.length;
+                                       }
+                                       tween = tween._next;
+                               }
+                               return a;
+                       }, 
+                       getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
+                               return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
+                       };
+               
+               TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
+                       if (tweens == null) {
+                               tweens = true;
+                       }
+                       if (delayedCalls == null) {
+                               delayedCalls = true;
+                       }
+                       var a = getAllTweens((timelines != false)),
+                               l = a.length,
+                               allTrue = (tweens && delayedCalls && timelines),
+                               isDC, tween, i;
+                       for (i = 0; i < l; i++) {
+                               tween = a[i];
+                               if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
+                                       if (complete) {
+                                               tween.totalTime(tween.totalDuration());
+                                       } else {
+                                               tween._enabled(false, false);
+                                       }
+                               }
+                       }
+               };
+               
+               TweenMax.killChildTweensOf = function(parent, complete) {
+                       if (parent == null) {
+                               return;
+                       }
+                       var tl = TweenLite._tweenLookup,
+                               a, curParent, p, i, l;
+                       if (typeof(parent) === "string") {
+                               parent = TweenLite.selector(parent) || parent;
+                       }
+                       if (_isSelector(parent)) {
+                               parent = _slice(parent, 0);
+                       }
+                       if (parent instanceof Array) {
+                               i = parent.length;
+                               while (--i > -1) {
+                                       TweenMax.killChildTweensOf(parent[i], complete);
+                               }
+                               return;
+                       }
+                       a = [];
+                       for (p in tl) {
+                               curParent = tl[p].target.parentNode;
+                               while (curParent) {
+                                       if (curParent === parent) {
+                                               a = a.concat(tl[p].tweens);
+                                       }
+                                       curParent = curParent.parentNode;
+                               }
+                       }
+                       l = a.length;
+                       for (i = 0; i < l; i++) {
+                               if (complete) {
+                                       a[i].totalTime(a[i].totalDuration());
+                               }
+                               a[i]._enabled(false, false);
+                       }
+               };
+
+               var _changePause = function(pause, tweens, delayedCalls, timelines) {
+                       if (tweens === undefined) {
+                               tweens = true;
+                       }
+                       if (delayedCalls === undefined) {
+                               delayedCalls = true;
+                       }
+                       var a = getAllTweens(timelines),
+                               allTrue = (tweens && delayedCalls && timelines),
+                               i = a.length,
+                               isDC, tween;
+                       while (--i > -1) {
+                               tween = a[i];
+                               if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
+                                       tween.paused(pause);
+                               }
+                       }
+               };
+               
+               TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
+                       _changePause(true, tweens, delayedCalls, timelines);
+               };
+               
+               TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
+                       _changePause(false, tweens, delayedCalls, timelines);
+               };
+               
+       
+//---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
+               
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
+               };
+               
+               p.totalProgress = function(value) {
+                       return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
+               };
+               
+               p.time = function(value, suppressEvents) {
+                       if (!arguments.length) {
+                               return this._time;
+                       }
+                       if (this._dirty) {
+                               this.totalDuration();
+                       }
+                       if (value > this._duration) {
+                               value = this._duration;
+                       }
+                       if (this._yoyo && (this._cycle & 1) !== 0) {
+                               value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
+                       } else if (this._repeat !== 0) {
+                               value += this._cycle * (this._duration + this._repeatDelay);
+                       }
+                       return this.totalTime(value, suppressEvents);
+               };
+
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               return this._duration; //don't set _dirty = false because there could be repeats that haven't been factored into the _totalDuration yet. Otherwise, if you create a repeated TweenMax and then immediately check its duration(), it would cache the value and the totalDuration would not be correct, thus repeats wouldn't take effect.
+                       }
+                       return Animation.prototype.duration.call(this, value);
+               };
+
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       //instead of Infinity, we use 999999999999 so that we can accommodate reverses
+                                       this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
+                                       this._dirty = false;
+                               }
+                               return this._totalDuration;
+                       }
+                       return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
+               };
+               
+               p.repeat = function(value) {
+                       if (!arguments.length) {
+                               return this._repeat;
+                       }
+                       this._repeat = value;
+                       return this._uncache(true);
+               };
+               
+               p.repeatDelay = function(value) {
+                       if (!arguments.length) {
+                               return this._repeatDelay;
+                       }
+                       this._repeatDelay = value;
+                       return this._uncache(true);
+               };
+               
+               p.yoyo = function(value) {
+                       if (!arguments.length) {
+                               return this._yoyo;
+                       }
+                       this._yoyo = value;
+                       return this;
+               };
+               
+               
+               return TweenMax;
+               
+       }, true);
+
+
+
+
+
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * TimelineLite
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
+
+               var TimelineLite = function(vars) {
+                               SimpleTimeline.call(this, vars);
+                               this._labels = {};
+                               this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
+                               this.smoothChildTiming = (this.vars.smoothChildTiming === true);
+                               this._sortChildren = true;
+                               this._onUpdate = this.vars.onUpdate;
+                               var v = this.vars,
+                                       i = _paramProps.length,
+                                       j, a;
+                               while (--i > -1) {
+                                       a = v[_paramProps[i]];
+                                       if (a) {
+                                               j = a.length;
+                                               while (--j > -1) {
+                                                       if (a[j] === "{self}") {
+                                                               a = v[_paramProps[i]] = a.concat(); //copy the array in case the user referenced the same array in multiple timelines/tweens (each {self} should be unique)
+                                                               a[j] = this;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (v.tweens instanceof Array) {
+                                       this.add(v.tweens, 0, v.align, v.stagger);
+                               }
+                       },
+                       _paramProps = ["onStartParams","onUpdateParams","onCompleteParams","onReverseCompleteParams","onRepeatParams"],
+                       _blankArray = [],
+                       _copy = function(vars) {
+                               var copy = {}, p;
+                               for (p in vars) {
+                                       copy[p] = vars[p];
+                               }
+                               return copy;
+                       },
+                       _slice = _blankArray.slice,
+                       p = TimelineLite.prototype = new SimpleTimeline();
+
+               TimelineLite.version = "1.9.8";
+               p.constructor = TimelineLite;
+               p.kill()._gc = false;
+
+               p.to = function(target, duration, vars, position) {
+                       return duration ? this.add( new TweenLite(target, duration, vars), position) : this.set(target, vars, position);
+               };
+
+               p.from = function(target, duration, vars, position) {
+                       return this.add( TweenLite.from(target, duration, vars), position);
+               };
+
+               p.fromTo = function(target, duration, fromVars, toVars, position) {
+                       return duration ? this.add( TweenLite.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
+               };
+
+               p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope}),
+                               i;
+                       if (typeof(targets) === "string") {
+                               targets = TweenLite.selector(targets) || targets;
+                       }
+                       if (!(targets instanceof Array) && targets.length && targets[0] && targets[0].nodeType && targets[0].style) { //senses if the targets object is a selector. If it is, we should translate it into an array.
+                               targets = _slice.call(targets, 0);
+                       }
+                       stagger = stagger || 0;
+                       for (i = 0; i < targets.length; i++) {
+                               if (vars.startAt) {
+                                       vars.startAt = _copy(vars.startAt);
+                               }
+                               tl.to(targets[i], duration, _copy(vars), i * stagger);
+                       }
+                       return this.add(tl, position);
+               };
+
+               p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       vars.immediateRender = (vars.immediateRender != false);
+                       vars.runBackwards = true;
+                       return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+
+               p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
+               };
+
+               p.call = function(callback, params, scope, position) {
+                       return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
+               };
+
+               p.set = function(target, vars, position) {
+                       position = this._parseTimeOrLabel(position, 0, true);
+                       if (vars.immediateRender == null) {
+                               vars.immediateRender = (position === this._time && !this._paused);
+                       }
+                       return this.add( new TweenLite(target, 0, vars), position);
+               };
+
+               TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
+                       vars = vars || {};
+                       if (vars.smoothChildTiming == null) {
+                               vars.smoothChildTiming = true;
+                       }
+                       var tl = new TimelineLite(vars),
+                               root = tl._timeline,
+                               tween, next;
+                       if (ignoreDelayedCalls == null) {
+                               ignoreDelayedCalls = true;
+                       }
+                       root._remove(tl, true);
+                       tl._startTime = 0;
+                       tl._rawPrevTime = tl._time = tl._totalTime = root._time;
+                       tween = root._first;
+                       while (tween) {
+                               next = tween._next;
+                               if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
+                                       tl.add(tween, tween._startTime - tween._delay);
+                               }
+                               tween = next;
+                       }
+                       root.add(tl, 0);
+                       return tl;
+               };
+
+               p.add = function(value, position, align, stagger) {
+                       var curTime, l, i, child, tl;
+                       if (typeof(position) !== "number") {
+                               position = this._parseTimeOrLabel(position, 0, true, value);
+                       }
+                       if (!(value instanceof Animation)) {
+                               if (value instanceof Array) {
+                                       align = align || "normal";
+                                       stagger = stagger || 0;
+                                       curTime = position;
+                                       l = value.length;
+                                       for (i = 0; i < l; i++) {
+                                               if ((child = value[i]) instanceof Array) {
+                                                       child = new TimelineLite({tweens:child});
+                                               }
+                                               this.add(child, curTime);
+                                               if (typeof(child) !== "string" && typeof(child) !== "function") {
+                                                       if (align === "sequence") {
+                                                               curTime = child._startTime + (child.totalDuration() / child._timeScale);
+                                                       } else if (align === "start") {
+                                                               child._startTime -= child.delay();
+                                                       }
+                                               }
+                                               curTime += stagger;
+                                       }
+                                       return this._uncache(true);
+                               } else if (typeof(value) === "string") {
+                                       return this.addLabel(value, position);
+                               } else if (typeof(value) === "function") {
+                                       value = TweenLite.delayedCall(0, value);
+                               } else {
+                                       throw("Cannot add " + value + " into the timeline; it is neither a tween, timeline, function, nor a string.");
+                               }
+                       }
+
+                       SimpleTimeline.prototype.add.call(this, value, position);
+
+                       //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly.
+                       if (this._gc) if (!this._paused) if (this._time === this._duration) if (this._time < this.duration()) {
+                               //in case any of the anscestors had completed but should now be enabled...
+                               tl = this;
+                               while (tl._gc && tl._timeline) {
+                                       if (tl._timeline.smoothChildTiming) {
+                                               tl.totalTime(tl._totalTime, true); //also enables them
+                                       } else {
+                                               tl._enabled(true, false);
+                                       }
+                                       tl = tl._timeline;
+                               }
+                       }
+
+                       return this;
+               };
+
+               p.remove = function(value) {
+                       if (value instanceof Animation) {
+                               return this._remove(value, false);
+                       } else if (value instanceof Array) {
+                               var i = value.length;
+                               while (--i > -1) {
+                                       this.remove(value[i]);
+                               }
+                               return this;
+                       } else if (typeof(value) === "string") {
+                               return this.removeLabel(value);
+                       }
+                       return this.kill(null, value);
+               };
+
+               p._remove = function(tween, skipDisable) {
+                       SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
+                       if (!this._last) {
+                               this._time = this._totalTime = 0;
+                       } else if (this._time > this._last._startTime) {
+                               this._time = this.duration();
+                               this._totalTime = this._totalDuration;
+                       }
+                       return this;
+               };
+
+               p.append = function(value, offsetOrLabel) {
+                       return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
+               };
+
+               p.insert = p.insertMultiple = function(value, position, align, stagger) {
+                       return this.add(value, position || 0, align, stagger);
+               };
+
+               p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
+                       return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
+               };
+
+               p.addLabel = function(label, position) {
+                       this._labels[label] = this._parseTimeOrLabel(position);
+                       return this;
+               };
+
+               p.removeLabel = function(label) {
+                       delete this._labels[label];
+                       return this;
+               };
+
+               p.getLabelTime = function(label) {
+                       return (this._labels[label] != null) ? this._labels[label] : -1;
+               };
+
+               p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
+                       var i;
+                       //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
+                       if (ignore instanceof Animation && ignore.timeline === this) {
+                               this.remove(ignore);
+                       } else if (ignore instanceof Array) {
+                               i = ignore.length;
+                               while (--i > -1) {
+                                       if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
+                                               this.remove(ignore[i]);
+                                       }
+                               }
+                       }
+                       if (typeof(offsetOrLabel) === "string") {
+                               return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
+                       }
+                       offsetOrLabel = offsetOrLabel || 0;
+                       if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
+                               i = timeOrLabel.indexOf("=");
+                               if (i === -1) {
+                                       if (this._labels[timeOrLabel] == null) {
+                                               return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
+                                       }
+                                       return this._labels[timeOrLabel] + offsetOrLabel;
+                               }
+                               offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
+                               timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
+                       } else if (timeOrLabel == null) {
+                               timeOrLabel = this.duration();
+                       }
+                       return Number(timeOrLabel) + offsetOrLabel;
+               };
+
+               p.seek = function(position, suppressEvents) {
+                       return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
+               };
+
+               p.stop = function() {
+                       return this.paused(true);
+               };
+
+               p.gotoAndPlay = function(position, suppressEvents) {
+                       return this.play(position, suppressEvents);
+               };
+
+               p.gotoAndStop = function(position, suppressEvents) {
+                       return this.pause(position, suppressEvents);
+               };
+
+               p.render = function(time, suppressEvents, force) {
+                       if (this._gc) {
+                               this._enabled(true, false);
+                       }
+                       this._active = !this._paused;
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
+                               prevTime = this._time,
+                               prevStart = this._startTime,
+                               prevTimeScale = this._timeScale,
+                               prevPaused = this._paused,
+                               tween, isComplete, next, callback, internalForce;
+                       if (time >= totalDur) {
+                               this._totalTime = this._time = totalDur;
+                               if (!this._reversed) if (!this._hasPausedChild()) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                                       if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time && this._first) { //In order to accommodate zero-duration timelines, we must discern the momentum/direction of time in order to render values properly when the "playhead" goes past 0 in the forward direction or lands directly on it, and also when it moves past it in the backward direction (from a postitive time to a negative time).
+                                               internalForce = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                               }
+                                       }
+                               }
+                               this._rawPrevTime = time;
+                               time = totalDur + 0.000001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off)
+
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = 0;
+                               if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               internalForce = true;
+                                       }
+                               } else if (!this._initted) {
+                                       internalForce = true;
+                               }
+                               this._rawPrevTime = time;
+                               time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
+
+                       } else {
+                               this._totalTime = this._time = this._rawPrevTime = time;
+                       }
+                       if ((this._time === prevTime || !this._first) && !force && !internalForce) {
+                               return;
+                       } else if (!this._initted) {
+                               this._initted = true;
+                       }
+                       if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
+                               this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                       }
+
+                       if (this._time >= prevTime) {
+                               tween = this._first;
+                               while (tween) {
+                                       next = tween._next; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
+
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       } else {
+                               tween = this._last;
+                               while (tween) {
+                                       next = tween._prev; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
+
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       }
+
+                       if (this._onUpdate) if (!suppressEvents) {
+                               this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                       }
+
+                       if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+
+               p._hasPausedChild = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
+                                       return true;
+                               }
+                               tween = tween._next;
+                       }
+                       return false;
+               };
+
+               p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || -9999999999;
+                       var a = [],
+                               tween = this._first,
+                               cnt = 0;
+                       while (tween) {
+                               if (tween._startTime < ignoreBeforeTime) {
+                                       //do nothing
+                               } else if (tween instanceof TweenLite) {
+                                       if (tweens !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                               } else {
+                                       if (timelines !== false) {
+                                               a[cnt++] = tween;
+                                       }
+                                       if (nested !== false) {
+                                               a = a.concat(tween.getChildren(true, tweens, timelines));
+                                               cnt = a.length;
+                                       }
+                               }
+                               tween = tween._next;
+                       }
+                       return a;
+               };
+
+               p.getTweensOf = function(target, nested) {
+                       var tweens = TweenLite.getTweensOf(target),
+                               i = tweens.length,
+                               a = [],
+                               cnt = 0;
+                       while (--i > -1) {
+                               if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
+                                       a[cnt++] = tweens[i];
+                               }
+                       }
+                       return a;
+               };
+
+               p._contains = function(tween) {
+                       var tl = tween.timeline;
+                       while (tl) {
+                               if (tl === this) {
+                                       return true;
+                               }
+                               tl = tl.timeline;
+                       }
+                       return false;
+               };
+
+               p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
+                       ignoreBeforeTime = ignoreBeforeTime || 0;
+                       var tween = this._first,
+                               labels = this._labels,
+                               p;
+                       while (tween) {
+                               if (tween._startTime >= ignoreBeforeTime) {
+                                       tween._startTime += amount;
+                               }
+                               tween = tween._next;
+                       }
+                       if (adjustLabels) {
+                               for (p in labels) {
+                                       if (labels[p] >= ignoreBeforeTime) {
+                                               labels[p] += amount;
+                                       }
+                               }
+                       }
+                       return this._uncache(true);
+               };
+
+               p._kill = function(vars, target) {
+                       if (!vars && !target) {
+                               return this._enabled(false, false);
+                       }
+                       var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
+                               i = tweens.length,
+                               changed = false;
+                       while (--i > -1) {
+                               if (tweens[i]._kill(vars, target)) {
+                                       changed = true;
+                               }
+                       }
+                       return changed;
+               };
+
+               p.clear = function(labels) {
+                       var tweens = this.getChildren(false, true, true),
+                               i = tweens.length;
+                       this._time = this._totalTime = 0;
+                       while (--i > -1) {
+                               tweens[i]._enabled(false, false);
+                       }
+                       if (labels !== false) {
+                               this._labels = {};
+                       }
+                       return this._uncache(true);
+               };
+
+               p.invalidate = function() {
+                       var tween = this._first;
+                       while (tween) {
+                               tween.invalidate();
+                               tween = tween._next;
+                       }
+                       return this;
+               };
+
+               p._enabled = function(enabled, ignoreTimeline) {
+                       if (enabled === this._gc) {
+                               var tween = this._first;
+                               while (tween) {
+                                       tween._enabled(enabled, true);
+                                       tween = tween._next;
+                               }
+                       }
+                       return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
+               };
+
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, false);
+               };
+
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       this.totalDuration(); //just triggers recalculation
+                               }
+                               return this._duration;
+                       }
+                       if (this.duration() !== 0 && value !== 0) {
+                               this.timeScale(this._duration / value);
+                       }
+                       return this;
+               };
+
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       var max = 0,
+                                               tween = this._last,
+                                               prevStart = 999999999999,
+                                               prev, end;
+                                       while (tween) {
+                                               prev = tween._prev; //record it here in case the tween changes position in the sequence...
+                                               if (tween._dirty) {
+                                                       tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
+                                               }
+                                               if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
+                                                       this.add(tween, tween._startTime - tween._delay);
+                                               } else {
+                                                       prevStart = tween._startTime;
+                                               }
+                                               if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
+                                                       max -= tween._startTime;
+                                                       if (this._timeline.smoothChildTiming) {
+                                                               this._startTime += tween._startTime / this._timeScale;
+                                                       }
+                                                       this.shiftChildren(-tween._startTime, false, -9999999999);
+                                                       prevStart = 0;
+                                               }
+                                               end = tween._startTime + (tween._totalDuration / tween._timeScale);
+                                               if (end > max) {
+                                                       max = end;
+                                               }
+                                               tween = prev;
+                                       }
+                                       this._duration = this._totalDuration = max;
+                                       this._dirty = false;
+                               }
+                               return this._totalDuration;
+                       }
+                       if (this.totalDuration() !== 0) if (value !== 0) {
+                               this.timeScale(this._totalDuration / value);
+                       }
+                       return this;
+               };
+
+               p.usesFrames = function() {
+                       var tl = this._timeline;
+                       while (tl._timeline) {
+                               tl = tl._timeline;
+                       }
+                       return (tl === Animation._rootFramesTimeline);
+               };
+
+               p.rawTime = function() {
+                       return (this._paused || (this._totalTime !== 0 && this._totalTime !== this._totalDuration)) ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
+               };
+
+               return TimelineLite;
+
+       }, true);
+       
+
+
+
+
+
+
+
+       
+       
+       
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * TimelineMax
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) {
+
+               var TimelineMax = function(vars) {
+                               TimelineLite.call(this, vars);
+                               this._repeat = this.vars.repeat || 0;
+                               this._repeatDelay = this.vars.repeatDelay || 0;
+                               this._cycle = 0;
+                               this._yoyo = (this.vars.yoyo === true);
+                               this._dirty = true;
+                       },
+                       _blankArray = [],
+                       _easeNone = new Ease(null, null, 1, 0),
+                       _getGlobalPaused = function(tween) {
+                               while (tween) {
+                                       if (tween._paused) {
+                                               return true;
+                                       }
+                                       tween = tween._timeline;
+                               }
+                               return false;
+                       },
+                       p = TimelineMax.prototype = new TimelineLite();
+
+               p.constructor = TimelineMax;
+               p.kill()._gc = false;
+               TimelineMax.version = "1.9.8";
+
+               p.invalidate = function() {
+                       this._yoyo = (this.vars.yoyo === true);
+                       this._repeat = this.vars.repeat || 0;
+                       this._repeatDelay = this.vars.repeatDelay || 0;
+                       this._uncache(true);
+                       return TimelineLite.prototype.invalidate.call(this);
+               };
+
+               p.addCallback = function(callback, position, params, scope) {
+                       return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
+               };
+
+               p.removeCallback = function(callback, position) {
+                       if (callback) {
+                               if (position == null) {
+                                       this._kill(null, callback);
+                               } else {
+                                       var a = this.getTweensOf(callback, false),
+                                               i = a.length,
+                                               time = this._parseTimeOrLabel(position);
+                                       while (--i > -1) {
+                                               if (a[i]._startTime === time) {
+                                                       a[i]._enabled(false, false);
+                                               }
+                                       }
+                               }
+                       }
+                       return this;
+               };
+
+               p.tweenTo = function(position, vars) {
+                       vars = vars || {};
+                       var copy = {ease:_easeNone, overwrite:2, useFrames:this.usesFrames(), immediateRender:false}, p, t;
+                       for (p in vars) {
+                               copy[p] = vars[p];
+                       }
+                       copy.time = this._parseTimeOrLabel(position);
+                       t = new TweenLite(this, (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001, copy);
+                       copy.onStart = function() {
+                               t.target.paused(true);
+                               if (t.vars.time !== t.target.time()) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all.
+                                       t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale );
+                               }
+                               if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it.
+                                       vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray);
+                               }
+                       };
+                       return t;
+               };
+
+               p.tweenFromTo = function(fromPosition, toPosition, vars) {
+                       vars = vars || {};
+                       fromPosition = this._parseTimeOrLabel(fromPosition);
+                       vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this};
+                       vars.immediateRender = (vars.immediateRender !== false);
+                       var t = this.tweenTo(toPosition, vars);
+                       return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001);
+               };
+
+               p.render = function(time, suppressEvents, force) {
+                       if (this._gc) {
+                               this._enabled(true, false);
+                       }
+                       this._active = !this._paused;
+                       var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
+                               dur = this._duration,
+                               prevTime = this._time,
+                               prevTotalTime = this._totalTime,
+                               prevStart = this._startTime,
+                               prevTimeScale = this._timeScale,
+                               prevRawPrevTime = this._rawPrevTime,
+                               prevPaused = this._paused,
+                               prevCycle = this._cycle,
+                               tween, isComplete, next, callback, internalForce, cycleDuration;
+                       if (time >= totalDur) {
+                               if (!this._locked) {
+                                       this._totalTime = totalDur;
+                                       this._cycle = this._repeat;
+                               }
+                               if (!this._reversed) if (!this._hasPausedChild()) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                                       if (dur === 0) if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time && this._first) { //In order to accommodate zero-duration timelines, we must discern the momentum/direction of time in order to render values properly when the "playhead" goes past 0 in the forward direction or lands directly on it, and also when it moves past it in the backward direction (from a postitive time to a negative time).
+                                               internalForce = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                               }
+                                       }
+                               }
+                               this._rawPrevTime = time;
+                               if (this._yoyo && (this._cycle & 1) !== 0) {
+                                       this._time = time = 0;
+                               } else {
+                                       this._time = dur;
+                                       time = dur + 0.000001; //to avoid occasional floating point rounding errors
+                               }
+
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               if (!this._locked) {
+                                       this._totalTime = this._cycle = 0;
+                               }
+                               this._time = 0;
+                               if (prevTime !== 0 || (dur === 0 && this._rawPrevTime > 0 && !this._locked)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (dur === 0) if (this._rawPrevTime >= 0 && this._first) { //zero-duration timelines are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               internalForce = true;
+                                       }
+                               } else if (!this._initted) {
+                                       internalForce = true;
+                               }
+                               this._rawPrevTime = time;
+                               time = 0;  //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
+
+                       } else {
+                               this._time = this._rawPrevTime = time;
+                               if (!this._locked) {
+                                       this._totalTime = time;
+                                       if (this._repeat !== 0) {
+                                               cycleDuration = dur + this._repeatDelay;
+                                               this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!)
+                                               if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
+                                                       this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
+                                               }
+                                               this._time = this._totalTime - (this._cycle * cycleDuration);
+                                               if (this._yoyo) if ((this._cycle & 1) !== 0) {
+                                                       this._time = dur - this._time;
+                                               }
+                                               if (this._time > dur) {
+                                                       this._time = dur;
+                                                       time = dur + 0.000001; //to avoid occasional floating point rounding error
+                                               } else if (this._time < 0) {
+                                                       this._time = time = 0;
+                                               } else {
+                                                       time = this._time;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (this._cycle !== prevCycle) if (!this._locked) {
+                               /*
+                               make sure children at the end/beginning of the timeline are rendered properly. If, for example,
+                               a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
+                               would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there
+                               could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So
+                               we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must
+                               ensure that zero-duration tweens at the very beginning or end of the TimelineMax work.
+                               */
+                               var backwards = (this._yoyo && (prevCycle & 1) !== 0),
+                                       wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)),
+                                       recTotalTime = this._totalTime,
+                                       recCycle = this._cycle,
+                                       recRawPrevTime = this._rawPrevTime,
+                                       recTime = this._time;
+
+                               this._totalTime = prevCycle * dur;
+                               if (this._cycle < prevCycle) {
+                                       backwards = !backwards;
+                               } else {
+                                       this._totalTime += dur;
+                               }
+                               this._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method.
+
+                               this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.00001 : prevRawPrevTime;
+                               this._cycle = prevCycle;
+                               this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render()
+                               prevTime = (backwards) ? 0 : dur;
+                               this.render(prevTime, suppressEvents, (dur === 0));
+                               if (!suppressEvents) if (!this._gc) {
+                                       if (this.vars.onRepeat) {
+                                               this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
+                                       }
+                               }
+                               if (wrap) {
+                                       prevTime = (backwards) ? dur + 0.000001 : -0.000001;
+                                       this.render(prevTime, true, false);
+                               }
+                               this._locked = false;
+                               if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible)
+                                       return;
+                               }
+                               this._time = recTime;
+                               this._totalTime = recTotalTime;
+                               this._cycle = recCycle;
+                               this._rawPrevTime = recRawPrevTime;
+                       }
+
+                       if ((this._time === prevTime || !this._first) && !force && !internalForce) {
+                               if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate.
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                               return;
+                       } else if (!this._initted) {
+                               this._initted = true;
+                       }
+
+                       if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) {
+                               this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                       }
+
+                       if (this._time >= prevTime) {
+                               tween = this._first;
+                               while (tween) {
+                                       next = tween._next; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       } else {
+                               tween = this._last;
+                               while (tween) {
+                                       next = tween._prev; //record it here because the value could change after rendering...
+                                       if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
+                                               break;
+                                       } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
+                                               if (!tween._reversed) {
+                                                       tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                               } else {
+                                                       tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                               }
+
+                                       }
+                                       tween = next;
+                               }
+                       }
+
+                       if (this._onUpdate) if (!suppressEvents) {
+                               this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                       }
+                       if (callback) if (!this._locked) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+               };
+
+               p.getActive = function(nested, tweens, timelines) {
+                       if (nested == null) {
+                               nested = true;
+                       }
+                       if (tweens == null) {
+                               tweens = true;
+                       }
+                       if (timelines == null) {
+                               timelines = false;
+                       }
+                       var a = [],
+                               all = this.getChildren(nested, tweens, timelines),
+                               cnt = 0,
+                               l = all.length,
+                               i, tween;
+                       for (i = 0; i < l; i++) {
+                               tween = all[i];
+                               //note: we cannot just check tween.active because timelines that contain paused children will continue to have "active" set to true even after the playhead passes their end point (technically a timeline can only be considered complete after all of its children have completed too, but paused tweens are...well...just waiting and until they're unpaused we don't know where their end point will be).
+                               if (!tween._paused) if (tween._timeline._time >= tween._startTime) if (tween._timeline._time < tween._startTime + tween._totalDuration / tween._timeScale) if (!_getGlobalPaused(tween._timeline)) {
+                                       a[cnt++] = tween;
+                               }
+                       }
+                       return a;
+               };
+
+
+               p.getLabelAfter = function(time) {
+                       if (!time) if (time !== 0) { //faster than isNan()
+                               time = this._time;
+                       }
+                       var labels = this.getLabelsArray(),
+                               l = labels.length,
+                               i;
+                       for (i = 0; i < l; i++) {
+                               if (labels[i].time > time) {
+                                       return labels[i].name;
+                               }
+                       }
+                       return null;
+               };
+
+               p.getLabelBefore = function(time) {
+                       if (time == null) {
+                               time = this._time;
+                       }
+                       var labels = this.getLabelsArray(),
+                               i = labels.length;
+                       while (--i > -1) {
+                               if (labels[i].time < time) {
+                                       return labels[i].name;
+                               }
+                       }
+                       return null;
+               };
+
+               p.getLabelsArray = function() {
+                       var a = [],
+                               cnt = 0,
+                               p;
+                       for (p in this._labels) {
+                               a[cnt++] = {time:this._labels[p], name:p};
+                       }
+                       a.sort(function(a,b) {
+                               return a.time - b.time;
+                       });
+                       return a;
+               };
+
+
+//---- GETTERS / SETTERS -------------------------------------------------------------------------------------------------------
+
+               p.progress = function(value) {
+                       return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false);
+               };
+
+               p.totalProgress = function(value) {
+                       return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
+               };
+
+               p.totalDuration = function(value) {
+                       if (!arguments.length) {
+                               if (this._dirty) {
+                                       TimelineLite.prototype.totalDuration.call(this); //just forces refresh
+                                       //Instead of Infinity, we use 999999999999 so that we can accommodate reverses.
+                                       this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
+                               }
+                               return this._totalDuration;
+                       }
+                       return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
+               };
+
+               p.time = function(value, suppressEvents) {
+                       if (!arguments.length) {
+                               return this._time;
+                       }
+                       if (this._dirty) {
+                               this.totalDuration();
+                       }
+                       if (value > this._duration) {
+                               value = this._duration;
+                       }
+                       if (this._yoyo && (this._cycle & 1) !== 0) {
+                               value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
+                       } else if (this._repeat !== 0) {
+                               value += this._cycle * (this._duration + this._repeatDelay);
+                       }
+                       return this.totalTime(value, suppressEvents);
+               };
+
+               p.repeat = function(value) {
+                       if (!arguments.length) {
+                               return this._repeat;
+                       }
+                       this._repeat = value;
+                       return this._uncache(true);
+               };
+
+               p.repeatDelay = function(value) {
+                       if (!arguments.length) {
+                               return this._repeatDelay;
+                       }
+                       this._repeatDelay = value;
+                       return this._uncache(true);
+               };
+
+               p.yoyo = function(value) {
+                       if (!arguments.length) {
+                               return this._yoyo;
+                       }
+                       this._yoyo = value;
+                       return this;
+               };
+
+               p.currentLabel = function(value) {
+                       if (!arguments.length) {
+                               return this.getLabelBefore(this._time + 0.00000001);
+                       }
+                       return this.seek(value, true);
+               };
+
+               return TimelineMax;
+
+       }, true);
+       
+
+
+
+
+       
+       
+       
+       
+       
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * BezierPlugin
+ * ----------------------------------------------------------------
+ */
+       (function() {
+
+               var _RAD2DEG = 180 / Math.PI,
+                       _DEG2RAD = Math.PI / 180,
+                       _r1 = [],
+                       _r2 = [],
+                       _r3 = [],
+                       _corProps = {},
+                       Segment = function(a, b, c, d) {
+                               this.a = a;
+                               this.b = b;
+                               this.c = c;
+                               this.d = d;
+                               this.da = d - a;
+                               this.ca = c - a;
+                               this.ba = b - a;
+                       },
+                       _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
+                       cubicToQuadratic = function(a, b, c, d) {
+                               var q1 = {a:a},
+                                       q2 = {},
+                                       q3 = {},
+                                       q4 = {c:d},
+                                       mab = (a + b) / 2,
+                                       mbc = (b + c) / 2,
+                                       mcd = (c + d) / 2,
+                                       mabc = (mab + mbc) / 2,
+                                       mbcd = (mbc + mcd) / 2,
+                                       m8 = (mbcd - mabc) / 8;
+                               q1.b = mab + (a - mab) / 4;
+                               q2.b = mabc + m8;
+                               q1.c = q2.a = (q1.b + q2.b) / 2;
+                               q2.c = q3.a = (mabc + mbcd) / 2;
+                               q3.b = mbcd - m8;
+                               q4.b = mcd + (d - mcd) / 4;
+                               q3.c = q4.a = (q3.b + q4.b) / 2;
+                               return [q1, q2, q3, q4];
+                       },
+                       _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
+                               var l = a.length - 1,
+                                       ii = 0,
+                                       cp1 = a[0].a,
+                                       i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
+                               for (i = 0; i < l; i++) {
+                                       seg = a[ii];
+                                       p1 = seg.a;
+                                       p2 = seg.d;
+                                       p3 = a[ii+1].d;
+
+                                       if (correlate) {
+                                               r1 = _r1[i];
+                                               r2 = _r2[i];
+                                               tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
+                                               m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
+                                               m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
+                                               mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
+                                       } else {
+                                               m1 = p2 - (p2 - p1) * curviness * 0.5;
+                                               m2 = p2 + (p3 - p2) * curviness * 0.5;
+                                               mm = p2 - (m1 + m2) / 2;
+                                       }
+                                       m1 += mm;
+                                       m2 += mm;
+
+                                       seg.c = cp2 = m1;
+                                       if (i !== 0) {
+                                               seg.b = cp1;
+                                       } else {
+                                               seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly.
+                                       }
+
+                                       seg.da = p2 - p1;
+                                       seg.ca = cp2 - p1;
+                                       seg.ba = cp1 - p1;
+
+                                       if (quad) {
+                                               qb = cubicToQuadratic(p1, cp1, cp2, p2);
+                                               a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
+                                               ii += 4;
+                                       } else {
+                                               ii++;
+                                       }
+
+                                       cp1 = m2;
+                               }
+                               seg = a[ii];
+                               seg.b = cp1;
+                               seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly.
+                               seg.da = seg.d - seg.a;
+                               seg.ca = seg.c - seg.a;
+                               seg.ba = cp1 - seg.a;
+                               if (quad) {
+                                       qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
+                                       a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
+                               }
+                       },
+                       _parseAnchors = function(values, p, correlate, prepend) {
+                               var a = [],
+                                       l, i, p1, p2, p3, tmp;
+                               if (prepend) {
+                                       values = [prepend].concat(values);
+                                       i = values.length;
+                                       while (--i > -1) {
+                                               if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
+                                                       values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons
+                                               }
+                                       }
+                               }
+                               l = values.length - 2;
+                               if (l < 0) {
+                                       a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
+                                       return a;
+                               }
+                               for (i = 0; i < l; i++) {
+                                       p1 = values[i][p];
+                                       p2 = values[i+1][p];
+                                       a[i] = new Segment(p1, 0, 0, p2);
+                                       if (correlate) {
+                                               p3 = values[i+2][p];
+                                               _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
+                                               _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
+                                       }
+                               }
+                               a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
+                               return a;
+                       },
+                       bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
+                               var obj = {},
+                                       props = [],
+                                       first = prepend || values[0],
+                                       i, p, a, j, r, l, seamless, last;
+                               correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
+                               if (curviness == null) {
+                                       curviness = 1;
+                               }
+                               for (p in values[0]) {
+                                       props.push(p);
+                               }
+                               //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later)
+                               if (values.length > 1) {
+                                       last = values[values.length - 1];
+                                       seamless = true;
+                                       i = props.length;
+                                       while (--i > -1) {
+                                               p = props[i];
+                                               if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9
+                                                       seamless = false;
+                                                       break;
+                                               }
+                                       }
+                                       if (seamless) {
+                                               values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
+                                               if (prepend) {
+                                                       values.unshift(prepend);
+                                               }
+                                               values.push(values[1]);
+                                               prepend = values[values.length - 3];
+                                       }
+                               }
+                               _r1.length = _r2.length = _r3.length = 0;
+                               i = props.length;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
+                                       obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
+                               }
+                               i = _r1.length;
+                               while (--i > -1) {
+                                       _r1[i] = Math.sqrt(_r1[i]);
+                                       _r2[i] = Math.sqrt(_r2[i]);
+                               }
+                               if (!basic) {
+                                       i = props.length;
+                                       while (--i > -1) {
+                                               if (_corProps[p]) {
+                                                       a = obj[props[i]];
+                                                       l = a.length - 1;
+                                                       for (j = 0; j < l; j++) {
+                                                               r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
+                                                               _r3[j] = (_r3[j] || 0) + r * r;
+                                                       }
+                                               }
+                                       }
+                                       i = _r3.length;
+                                       while (--i > -1) {
+                                               _r3[i] = Math.sqrt(_r3[i]);
+                                       }
+                               }
+                               i = props.length;
+                               j = quadratic ? 4 : 1;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       a = obj[p];
+                                       _calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties
+                                       if (seamless) {
+                                               a.splice(0, j);
+                                               a.splice(a.length - j, j);
+                                       }
+                               }
+                               return obj;
+                       },
+                       _parseBezierData = function(values, type, prepend) {
+                               type = type || "soft";
+                               var obj = {},
+                                       inc = (type === "cubic") ? 3 : 2,
+                                       soft = (type === "soft"),
+                                       props = [],
+                                       a, b, c, d, cur, i, j, l, p, cnt, tmp;
+                               if (soft && prepend) {
+                                       values = [prepend].concat(values);
+                               }
+                               if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
+                               for (p in values[0]) {
+                                       props.push(p);
+                               }
+                               i = props.length;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       obj[p] = cur = [];
+                                       cnt = 0;
+                                       l = values.length;
+                                       for (j = 0; j < l; j++) {
+                                               a = (prepend == null) ? values[j][p] : (typeof( (tmp = values[j][p]) ) === "string" && tmp.charAt(1) === "=") ? prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)) : Number(tmp);
+                                               if (soft) if (j > 1) if (j < l - 1) {
+                                                       cur[cnt++] = (a + cur[cnt-2]) / 2;
+                                               }
+                                               cur[cnt++] = a;
+                                       }
+                                       l = cnt - inc + 1;
+                                       cnt = 0;
+                                       for (j = 0; j < l; j += inc) {
+                                               a = cur[j];
+                                               b = cur[j+1];
+                                               c = cur[j+2];
+                                               d = (inc === 2) ? 0 : cur[j+3];
+                                               cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
+                                       }
+                                       cur.length = cnt;
+                               }
+                               return obj;
+                       },
+                       _addCubicLengths = function(a, steps, resolution) {
+                               var inc = 1 / resolution,
+                                       j = a.length,
+                                       d, d1, s, da, ca, ba, p, i, inv, bez, index;
+                               while (--j > -1) {
+                                       bez = a[j];
+                                       s = bez.a;
+                                       da = bez.d - s;
+                                       ca = bez.c - s;
+                                       ba = bez.b - s;
+                                       d = d1 = 0;
+                                       for (i = 1; i <= resolution; i++) {
+                                               p = inc * i;
+                                               inv = 1 - p;
+                                               d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
+                                               index = j * resolution + i - 1;
+                                               steps[index] = (steps[index] || 0) + d * d;
+                                       }
+                               }
+                       },
+                       _parseLengthData = function(obj, resolution) {
+                               resolution = resolution >> 0 || 6;
+                               var a = [],
+                                       lengths = [],
+                                       d = 0,
+                                       total = 0,
+                                       threshold = resolution - 1,
+                                       segments = [],
+                                       curLS = [], //current length segments array
+                                       p, i, l, index;
+                               for (p in obj) {
+                                       _addCubicLengths(obj[p], a, resolution);
+                               }
+                               l = a.length;
+                               for (i = 0; i < l; i++) {
+                                       d += Math.sqrt(a[i]);
+                                       index = i % resolution;
+                                       curLS[index] = d;
+                                       if (index === threshold) {
+                                               total += d;
+                                               index = (i / resolution) >> 0;
+                                               segments[index] = curLS;
+                                               lengths[index] = total;
+                                               d = 0;
+                                               curLS = [];
+                                       }
+                               }
+                               return {length:total, lengths:lengths, segments:segments};
+                       },
+
+
+
+                       BezierPlugin = window._gsDefine.plugin({
+                                       propName: "bezier",
+                                       priority: -1,
+                                       API: 2,
+                                       global:true,
+
+                                       //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                                       init: function(target, vars, tween) {
+                                               this._target = target;
+                                               if (vars instanceof Array) {
+                                                       vars = {values:vars};
+                                               }
+                                               this._func = {};
+                                               this._round = {};
+                                               this._props = [];
+                                               this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
+                                               var values = vars.values || [],
+                                                       first = {},
+                                                       second = values[0],
+                                                       autoRotate = vars.autoRotate || tween.vars.orientToBezier,
+                                                       p, isFunc, i, j, prepend;
+
+                                               this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
+                                               for (p in second) {
+                                                       this._props.push(p);
+                                               }
+
+                                               i = this._props.length;
+                                               while (--i > -1) {
+                                                       p = this._props[i];
+
+                                                       this._overwriteProps.push(p);
+                                                       isFunc = this._func[p] = (typeof(target[p]) === "function");
+                                                       first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
+                                                       if (!prepend) if (first[p] !== values[0][p]) {
+                                                               prepend = first;
+                                                       }
+                                               }
+                                               this._beziers = (vars.type !== "cubic" && vars.type !== "quadratic" && vars.type !== "soft") ? bezierThrough(values, isNaN(vars.curviness) ? 1 : vars.curviness, false, (vars.type === "thruBasic"), vars.correlate, prepend) : _parseBezierData(values, vars.type, first);
+                                               this._segCount = this._beziers[p].length;
+
+                                               if (this._timeRes) {
+                                                       var ld = _parseLengthData(this._beziers, this._timeRes);
+                                                       this._length = ld.length;
+                                                       this._lengths = ld.lengths;
+                                                       this._segments = ld.segments;
+                                                       this._l1 = this._li = this._s1 = this._si = 0;
+                                                       this._l2 = this._lengths[0];
+                                                       this._curSeg = this._segments[0];
+                                                       this._s2 = this._curSeg[0];
+                                                       this._prec = 1 / this._curSeg.length;
+                                               }
+
+                                               if ((autoRotate = this._autoRotate)) {
+                                                       if (!(autoRotate[0] instanceof Array)) {
+                                                               this._autoRotate = autoRotate = [autoRotate];
+                                                       }
+                                                       i = autoRotate.length;
+                                                       while (--i > -1) {
+                                                               for (j = 0; j < 3; j++) {
+                                                                       p = autoRotate[i][j];
+                                                                       this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
+                                                               }
+                                                       }
+                                               }
+                                               return true;
+                                       },
+
+                                       //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+                                       set: function(v) {
+                                               var segments = this._segCount,
+                                                       func = this._func,
+                                                       target = this._target,
+                                                       curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
+                                               if (!this._timeRes) {
+                                                       curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
+                                                       t = (v - (curIndex * (1 / segments))) * segments;
+                                               } else {
+                                                       lengths = this._lengths;
+                                                       curSeg = this._curSeg;
+                                                       v *= this._length;
+                                                       i = this._li;
+                                                       //find the appropriate segment (if the currently cached one isn't correct)
+                                                       if (v > this._l2 && i < segments - 1) {
+                                                               l = segments - 1;
+                                                               while (i < l && (this._l2 = lengths[++i]) <= v) {       }
+                                                               this._l1 = lengths[i-1];
+                                                               this._li = i;
+                                                               this._curSeg = curSeg = this._segments[i];
+                                                               this._s2 = curSeg[(this._s1 = this._si = 0)];
+                                                       } else if (v < this._l1 && i > 0) {
+                                                               while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
+                                                               if (i === 0 && v < this._l1) {
+                                                                       this._l1 = 0;
+                                                               } else {
+                                                                       i++;
+                                                               }
+                                                               this._l2 = lengths[i];
+                                                               this._li = i;
+                                                               this._curSeg = curSeg = this._segments[i];
+                                                               this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
+                                                               this._s2 = curSeg[this._si];
+                                                       }
+                                                       curIndex = i;
+                                                       //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
+                                                       v -= this._l1;
+                                                       i = this._si;
+                                                       if (v > this._s2 && i < curSeg.length - 1) {
+                                                               l = curSeg.length - 1;
+                                                               while (i < l && (this._s2 = curSeg[++i]) <= v) {        }
+                                                               this._s1 = curSeg[i-1];
+                                                               this._si = i;
+                                                       } else if (v < this._s1 && i > 0) {
+                                                               while (i > 0 && (this._s1 = curSeg[--i]) >= v) {        }
+                                                               if (i === 0 && v < this._s1) {
+                                                                       this._s1 = 0;
+                                                               } else {
+                                                                       i++;
+                                                               }
+                                                               this._s2 = curSeg[i];
+                                                               this._si = i;
+                                                       }
+                                                       t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
+                                               }
+                                               inv = 1 - t;
+
+                                               i = this._props.length;
+                                               while (--i > -1) {
+                                                       p = this._props[i];
+                                                       b = this._beziers[p][curIndex];
+                                                       val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
+                                                       if (this._round[p]) {
+                                                               val = (val + ((val > 0) ? 0.5 : -0.5)) >> 0;
+                                                       }
+                                                       if (func[p]) {
+                                                               target[p](val);
+                                                       } else {
+                                                               target[p] = val;
+                                                       }
+                                               }
+
+                                               if (this._autoRotate) {
+                                                       var ar = this._autoRotate,
+                                                               b2, x1, y1, x2, y2, add, conv;
+                                                       i = ar.length;
+                                                       while (--i > -1) {
+                                                               p = ar[i][2];
+                                                               add = ar[i][3] || 0;
+                                                               conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
+                                                               b = this._beziers[ar[i][0]];
+                                                               b2 = this._beziers[ar[i][1]];
+
+                                                               if (b && b2) { //in case one of the properties got overwritten.
+                                                                       b = b[curIndex];
+                                                                       b2 = b2[curIndex];
+
+                                                                       x1 = b.a + (b.b - b.a) * t;
+                                                                       x2 = b.b + (b.c - b.b) * t;
+                                                                       x1 += (x2 - x1) * t;
+                                                                       x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
+
+                                                                       y1 = b2.a + (b2.b - b2.a) * t;
+                                                                       y2 = b2.b + (b2.c - b2.b) * t;
+                                                                       y1 += (y2 - y1) * t;
+                                                                       y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
+
+                                                                       val = Math.atan2(y2 - y1, x2 - x1) * conv + add;
+
+                                                                       if (func[p]) {
+                                                                               target[p](val);
+                                                                       } else {
+                                                                               target[p] = val;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                       }),
+                       p = BezierPlugin.prototype;
+
+
+               BezierPlugin.bezierThrough = bezierThrough;
+               BezierPlugin.cubicToQuadratic = cubicToQuadratic;
+               BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
+               BezierPlugin.quadraticToCubic = function(a, b, c) {
+                       return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
+               };
+
+               BezierPlugin._cssRegister = function() {
+                       var CSSPlugin = window._gsDefine.globals.CSSPlugin;
+                       if (!CSSPlugin) {
+                               return;
+                       }
+                       var _internals = CSSPlugin._internals,
+                               _parseToProxy = _internals._parseToProxy,
+                               _setPluginRatio = _internals._setPluginRatio,
+                               CSSPropTween = _internals.CSSPropTween;
+                       _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
+                               if (e instanceof Array) {
+                                       e = {values:e};
+                               }
+                               plugin = new BezierPlugin();
+                               var values = e.values,
+                                       l = values.length - 1,
+                                       pluginValues = [],
+                                       v = {},
+                                       i, p, data;
+                               if (l < 0) {
+                                       return pt;
+                               }
+                               for (i = 0; i <= l; i++) {
+                                       data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
+                                       pluginValues[i] = data.end;
+                               }
+                               for (p in e) {
+                                       v[p] = e[p]; //duplicate the vars object because we need to alter some things which would cause problems if the user plans to reuse the same vars object for another tween.
+                               }
+                               v.values = pluginValues;
+                               pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
+                               pt.data = data;
+                               pt.plugin = plugin;
+                               pt.setRatio = _setPluginRatio;
+                               if (v.autoRotate === 0) {
+                                       v.autoRotate = true;
+                               }
+                               if (v.autoRotate && !(v.autoRotate instanceof Array)) {
+                                       i = (v.autoRotate === true) ? 0 : Number(v.autoRotate) * _DEG2RAD;
+                                       v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,true]] : (data.end.x != null) ? [["x","y","rotation",i,true]] : false;
+                               }
+                               if (v.autoRotate) {
+                                       if (!cssp._transform) {
+                                               cssp._enableTransforms(false);
+                                       }
+                                       data.autoRotate = cssp._target._gsTransform;
+                               }
+                               plugin._onInitTween(data.proxy, v, cssp._tween);
+                               return pt;
+                       }});
+               };
+
+               p._roundProps = function(lookup, value) {
+                       var op = this._overwriteProps,
+                               i = op.length;
+                       while (--i > -1) {
+                               if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
+                                       this._round[op[i]] = value;
+                               }
+                       }
+               };
+
+               p._kill = function(lookup) {
+                       var a = this._props,
+                               p, i;
+                       for (p in this._beziers) {
+                               if (p in lookup) {
+                                       delete this._beziers[p];
+                                       delete this._func[p];
+                                       i = a.length;
+                                       while (--i > -1) {
+                                               if (a[i] === p) {
+                                                       a.splice(i, 1);
+                                               }
+                                       }
+                               }
+                       }
+                       return this._super._kill.call(this, lookup);
+               };
+
+       }());
+
+
+
+
+
+
+       
+       
+       
+       
+       
+       
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * CSSPlugin
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
+
+               /** @constructor **/
+               var CSSPlugin = function() {
+                               TweenPlugin.call(this, "css");
+                               this._overwriteProps.length = 0;
+                       },
+                       _hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called.
+                       _suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance
+                       _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
+                       _overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification.
+                       _specialProps = {},
+                       p = CSSPlugin.prototype = new TweenPlugin("css");
+
+               p.constructor = CSSPlugin;
+               CSSPlugin.version = "1.9.8";
+               CSSPlugin.API = 2;
+               CSSPlugin.defaultTransformPerspective = 0;
+               p = "px"; //we'll reuse the "p" variable to keep file size down
+               CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p};
+
+
+               var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
+                       _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
+                       _valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
+                       //_clrNumExp = /(?:\b(?:(?:rgb|rgba|hsl|hsla)\(.+?\))|\B#.+?\b)/, //only finds rgb(), rgba(), hsl(), hsla() and # (hexadecimal) values but NOT color names like red, blue, etc.
+                       //_tinyNumExp = /\b\d+?e\-\d+?\b/g, //finds super small numbers in a string like 1e-20. could be used in matrix3d() to fish out invalid numbers and replace them with 0. After performing speed tests, however, we discovered it was slightly faster to just cut the numbers at 5 decimal places with a particular algorithm.
+                       _NaNExp = /[^\d\-\.]/g,
+                       _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
+                       _opacityExp = /opacity *= *([^)]*)/,
+                       _opacityValExp = /opacity:([^;]*)/,
+                       _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
+                       _rgbhslExp = /^(rgb|hsl)/,
+                       _capsExp = /([A-Z])/g,
+                       _camelExp = /-([a-z])/gi,
+                       _urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage)
+                       _camelFunc = function(s, g) { return g.toUpperCase(); },
+                       _horizExp = /(?:Left|Right|Width)/i,
+                       _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
+                       _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
+                       _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
+                       _DEG2RAD = Math.PI / 180,
+                       _RAD2DEG = 180 / Math.PI,
+                       _forcePT = {},
+                       _doc = document,
+                       _tempDiv = _doc.createElement("div"),
+                       _tempImg = _doc.createElement("img"),
+                       _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
+                       _agent = navigator.userAgent,
+                       _autoRound,
+                       _reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance).
+
+                       _isSafari,
+                       _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
+                       _isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!)
+                       _ieVers,
+                       _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
+                               var i = _agent.indexOf("Android"),
+                                       d = _doc.createElement("div"), a;
+
+                               _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
+                               _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
+                               _isFirefox = (_agent.indexOf("Firefox") !== -1);
+
+                               (/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent);
+                               _ieVers = parseFloat( RegExp.$1 );
+
+                               d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>";
+                               a = d.getElementsByTagName("a")[0];
+                               return a ? /^0.55/.test(a.style.opacity) : false;
+                       }()),
+                       _getIEOpacity = function(v) {
+                               return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
+                       },
+                       _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
+                               if (window.console) {
+                                       console.log(s);
+                               }
+                       },
+                       _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
+                       _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
+
+                       //@private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all)
+                       _checkPropPrefix = function(p, e) {
+                               e = e || _tempDiv;
+                               var s = e.style,
+                                       a, i;
+                               if (s[p] !== undefined) {
+                                       return p;
+                               }
+                               p = p.charAt(0).toUpperCase() + p.substr(1);
+                               a = ["O","Moz","ms","Ms","Webkit"];
+                               i = 5;
+                               while (--i > -1 && s[a[i]+p] === undefined) { }
+                               if (i >= 0) {
+                                       _prefix = (i === 3) ? "ms" : a[i];
+                                       _prefixCSS = "-" + _prefix.toLowerCase() + "-";
+                                       return _prefix + p;
+                               }
+                               return null;
+                       },
+
+                       _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
+
+                       /**
+                        * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do:
+                        * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
+                        *
+                        * @param {!Object} t Target element whose style property you want to query
+                        * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
+                        * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call.
+                        * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value.
+                        * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
+                        * @return {?string} The current property value
+                        */
+                       _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
+                               var rv;
+                               if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here.
+                                       return _getIEOpacity(t);
+                               }
+                               if (!calc && t.style[p]) {
+                                       rv = t.style[p];
+                               } else if ((cs = cs || _getComputedStyle(t, null))) {
+                                       t = cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
+                                       rv = (t || cs.length) ? t : cs[p]; //Opera behaves VERY strangely - length is usually 0 and cs[p] is the only way to get accurate results EXCEPT when checking for -o-transform which only works with cs.getPropertyValue()!
+                               } else if (t.currentStyle) {
+                                       cs = t.currentStyle;
+                                       rv = cs[p];
+                               }
+                               return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
+                       },
+
+                       /**
+                        * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number.
+                        * @param {!Object} t Target element
+                        * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
+                        * @param {!number} v Value
+                        * @param {string=} sfx Suffix (like "px" or "%" or "em")
+                        * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect.
+                        * @return {number} value in pixels
+                        */
+                       _convertToPixels = function(t, p, v, sfx, recurse) {
+                               if (sfx === "px" || !sfx) { return v; }
+                               if (sfx === "auto" || !v) { return 0; }
+                               var horiz = _horizExp.test(p),
+                                       node = t,
+                                       style = _tempDiv.style,
+                                       neg = (v < 0),
+                                       pix;
+                               if (neg) {
+                                       v = -v;
+                               }
+                               if (sfx === "%" && p.indexOf("border") !== -1) {
+                                       pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
+                               } else {
+                                       style.cssText = "border-style:solid; border-width:0; position:absolute; line-height:0;";
+                                       if (sfx === "%" || !node.appendChild) {
+                                               node = t.parentNode || _doc.body;
+                                               style[(horiz ? "width" : "height")] = v + sfx;
+                                       } else {
+                                               style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
+                                       }
+                                       node.appendChild(_tempDiv);
+                                       pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
+                                       node.removeChild(_tempDiv);
+                                       if (pix === 0 && !recurse) {
+                                               pix = _convertToPixels(t, p, v, sfx, true);
+                                       }
+                               }
+                               return neg ? -pix : pix;
+                       },
+                       _calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop
+                               if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
+                               var dim = ((p === "left") ? "Left" : "Top"),
+                                       v = _getStyle(t, "margin" + dim, cs);
+                               return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
+                       },
+
+                       //@private returns at object containing ALL of the style properties in camelCase and their associated values.
+                       _getAllStyles = function(t, cs) {
+                               var s = {},
+                                       i, tr;
+                               if ((cs = cs || _getComputedStyle(t, null))) {
+                                       if ((i = cs.length)) {
+                                               while (--i > -1) {
+                                                       s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
+                                               }
+                                       } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
+                                               for (i in cs) {
+                                                       s[i] = cs[i];
+                                               }
+                                       }
+                               } else if ((cs = t.currentStyle || t.style)) {
+                                       for (i in cs) {
+                                               s[i.replace(_camelExp, _camelFunc)] = cs[i];
+                                       }
+                               }
+                               if (!_supportsOpacity) {
+                                       s.opacity = _getIEOpacity(t);
+                               }
+                               tr = _getTransform(t, cs, false);
+                               s.rotation = tr.rotation * _RAD2DEG;
+                               s.skewX = tr.skewX * _RAD2DEG;
+                               s.scaleX = tr.scaleX;
+                               s.scaleY = tr.scaleY;
+                               s.x = tr.x;
+                               s.y = tr.y;
+                               if (_supports3D) {
+                                       s.z = tr.z;
+                                       s.rotationX = tr.rotationX * _RAD2DEG;
+                                       s.rotationY = tr.rotationY * _RAD2DEG;
+                                       s.scaleZ = tr.scaleZ;
+                               }
+                               if (s.filters) {
+                                       delete s.filters;
+                               }
+                               return s;
+                       },
+
+                       //@private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object containing only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details.
+                       _cssDif = function(t, s1, s2, vars, forceLookup) {
+                               var difs = {},
+                                       style = t.style,
+                                       val, p, mpt;
+                               for (p in s2) {
+                                       if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") {
+                                               difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween.
+                                               if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes.
+                                                       mpt = new MiniPropTween(style, p, style[p], mpt);
+                                               }
+                                       }
+                               }
+                               if (vars) {
+                                       for (p in vars) { //copy properties (except className)
+                                               if (p !== "className") {
+                                                       difs[p] = vars[p];
+                                               }
+                                       }
+                               }
+                               return {difs:difs, firstMPT:mpt};
+                       },
+                       _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
+                       _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
+
+                       /**
+                        * @private Gets the width or height of an element
+                        * @param {!Object} t Target element
+                        * @param {!string} p Property name ("width" or "height")
+                        * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
+                        * @return {number} Dimension (in pixels)
+                        */
+                       _getDimension = function(t, p, cs) {
+                               var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
+                                       a = _dimensions[p],
+                                       i = a.length;
+                               cs = cs || _getComputedStyle(t, null);
+                               while (--i > -1) {
+                                       v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
+                                       v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
+                               }
+                               return v;
+                       },
+
+                       //@private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value)
+                       _parsePosition = function(v, recObj) {
+                               if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
+                                       v = "0 0";
+                               }
+                               var a = v.split(" "),
+                                       x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
+                                       y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
+                               if (y == null) {
+                                       y = "0";
+                               } else if (y === "center") {
+                                       y = "50%";
+                               }
+                               if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
+                                       x = "50%";
+                               }
+                               if (recObj) {
+                                       recObj.oxp = (x.indexOf("%") !== -1);
+                                       recObj.oyp = (y.indexOf("%") !== -1);
+                                       recObj.oxr = (x.charAt(1) === "=");
+                                       recObj.oyr = (y.charAt(1) === "=");
+                                       recObj.ox = parseFloat(x.replace(_NaNExp, ""));
+                                       recObj.oy = parseFloat(y.replace(_NaNExp, ""));
+                               }
+                               return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
+                       },
+
+                       /**
+                        * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!)
+                        * @param {(number|string)} e End value which is typically a string, but could be a number
+                        * @param {(number|string)} b Beginning value which is typically a string but could be a number
+                        * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
+                        */
+                       _parseChange = function(e, b) {
+                               return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
+                       },
+
+                       /**
+                        * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
+                        * @param {Object} v Value to be parsed
+                        * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
+                        * @return {number} Parsed value
+                        */
+                       _parseVal = function(v, d) {
+                               return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
+                       },
+
+                       /**
+                        * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly.
+                        * @param {Object} v Value to be parsed
+                        * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
+                        * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY"
+                        * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation.
+                        * @return {number} parsed angle in radians
+                        */
+                       _parseAngle = function(v, d, p, directionalEnd) {
+                               var min = 0.000001,
+                                       cap, split, dif, result;
+                               if (v == null) {
+                                       result = d;
+                               } else if (typeof(v) === "number") {
+                                       result = v * _DEG2RAD;
+                               } else {
+                                       cap = Math.PI * 2;
+                                       split = v.split("_");
+                                       dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? _DEG2RAD : 1) - ((v.charAt(1) === "=") ? 0 : d);
+                                       if (split.length) {
+                                               if (directionalEnd) {
+                                                       directionalEnd[p] = d + dif;
+                                               }
+                                               if (v.indexOf("short") !== -1) {
+                                                       dif = dif % cap;
+                                                       if (dif !== dif % (cap / 2)) {
+                                                               dif = (dif < 0) ? dif + cap : dif - cap;
+                                                       }
+                                               }
+                                               if (v.indexOf("_cw") !== -1 && dif < 0) {
+                                                       dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               } else if (v.indexOf("ccw") !== -1 && dif > 0) {
+                                                       dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               }
+                                       }
+                                       result = d + dif;
+                               }
+                               if (result < min && result > -min) {
+                                       result = 0;
+                               }
+                               return result;
+                       },
+
+                       _colorLookup = {aqua:[0,255,255],
+                               lime:[0,255,0],
+                               silver:[192,192,192],
+                               black:[0,0,0],
+                               maroon:[128,0,0],
+                               teal:[0,128,128],
+                               blue:[0,0,255],
+                               navy:[0,0,128],
+                               white:[255,255,255],
+                               fuchsia:[255,0,255],
+                               olive:[128,128,0],
+                               yellow:[255,255,0],
+                               orange:[255,165,0],
+                               gray:[128,128,128],
+                               purple:[128,0,128],
+                               green:[0,128,0],
+                               red:[255,0,0],
+                               pink:[255,192,203],
+                               cyan:[0,255,255],
+                               transparent:[255,255,255,0]},
+
+                       _hue = function(h, m1, m2) {
+                               h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
+                               return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
+                       },
+
+                       /**
+                        * @private Parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course)
+                        * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc.
+                        * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
+                        */
+                       _parseColor = function(v) {
+                               var c1, c2, c3, h, s, l;
+                               if (!v || v === "") {
+                                       return _colorLookup.black;
+                               }
+                               if (typeof(v) === "number") {
+                                       return [v >> 16, (v >> 8) & 255, v & 255];
+                               }
+                               if (v.charAt(v.length - 1) === ",") { //sometimes a trailing commma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.
+                                       v = v.substr(0, v.length - 1);
+                               }
+                               if (_colorLookup[v]) {
+                                       return _colorLookup[v];
+                               }
+                               if (v.charAt(0) === "#") {
+                                       if (v.length === 4) { //for shorthand like #9F0
+                                               c1 = v.charAt(1),
+                                               c2 = v.charAt(2),
+                                               c3 = v.charAt(3);
+                                               v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
+                                       }
+                                       v = parseInt(v.substr(1), 16);
+                                       return [v >> 16, (v >> 8) & 255, v & 255];
+                               }
+                               if (v.substr(0, 3) === "hsl") {
+                                       v = v.match(_numExp);
+                                       h = (Number(v[0]) % 360) / 360;
+                                       s = Number(v[1]) / 100;
+                                       l = Number(v[2]) / 100;
+                                       c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
+                                       c1 = l * 2 - c2;
+                                       if (v.length > 3) {
+                                               v[3] = Number(v[3]);
+                                       }
+                                       v[0] = _hue(h + 1 / 3, c1, c2);
+                                       v[1] = _hue(h, c1, c2);
+                                       v[2] = _hue(h - 1 / 3, c1, c2);
+                                       return v;
+                               }
+                               v = v.match(_numExp) || _colorLookup.transparent;
+                               v[0] = Number(v[0]);
+                               v[1] = Number(v[1]);
+                               v[2] = Number(v[2]);
+                               if (v.length > 3) {
+                                       v[3] = Number(v[3]);
+                               }
+                               return v;
+                       },
+                       _colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.
+
+               for (p in _colorLookup) {
+                       _colorExp += "|" + p + "\\b";
+               }
+               _colorExp = new RegExp(_colorExp+")", "gi");
+
+               /**
+                * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned.
+                * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned.
+                * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't.
+                * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc.
+                * @return {Function} formatter function
+                */
+               var _getFormatter = function(dflt, clr, collapsible, multi) {
+                               if (dflt == null) {
+                                       return function(v) {return v;};
+                               }
+                               var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
+                                       dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
+                                       pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
+                                       sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
+                                       delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
+                                       numVals = dVals.length,
+                                       dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
+                                       formatter;
+                               if (!numVals) {
+                                       return function(v) {return v;};
+                               }
+                               if (clr) {
+                                       formatter = function(v) {
+                                               var color, vals, i, a;
+                                               if (typeof(v) === "number") {
+                                                       v += dSfx;
+                                               } else if (multi && _commasOutsideParenExp.test(v)) {
+                                                       a = v.replace(_commasOutsideParenExp, "|").split("|");
+                                                       for (i = 0; i < a.length; i++) {
+                                                               a[i] = formatter(a[i]);
+                                                       }
+                                                       return a.join(",");
+                                               }
+                                               color = (v.match(_colorExp) || [dColor])[0];
+                                               vals = v.split(color).join("").match(_valuesExp) || [];
+                                               i = vals.length;
+                                               if (numVals > i--) {
+                                                       while (++i < numVals) {
+                                                               vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
+                                                       }
+                                               }
+                                               return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
+                                       };
+                                       return formatter;
+
+                               }
+                               formatter = function(v) {
+                                       var vals, a, i;
+                                       if (typeof(v) === "number") {
+                                               v += dSfx;
+                                       } else if (multi && _commasOutsideParenExp.test(v)) {
+                                               a = v.replace(_commasOutsideParenExp, "|").split("|");
+                                               for (i = 0; i < a.length; i++) {
+                                                       a[i] = formatter(a[i]);
+                                               }
+                                               return a.join(",");
+                                       }
+                                       vals = v.match(_valuesExp) || [];
+                                       i = vals.length;
+                                       if (numVals > i--) {
+                                               while (++i < numVals) {
+                                                       vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
+                                               }
+                                       }
+                                       return pfx + vals.join(delim) + sfx;
+                               };
+                               return formatter;
+                       },
+
+                       /**
+                        * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges.
+                        * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
+                        * @return {Function} a formatter function
+                        */
+                       _getEdgeParser = function(props) {
+                               props = props.split(",");
+                               return function(t, e, p, cssp, pt, plugin, vars) {
+                                       var a = (e + "").split(" "),
+                                               i;
+                                       vars = {};
+                                       for (i = 0; i < 4; i++) {
+                                               vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
+                                       }
+                                       return cssp.parse(t, vars, pt, plugin);
+                               };
+                       },
+
+                       //@private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens  which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color.
+                       _setPluginRatio = _internals._setPluginRatio = function(v) {
+                               this.plugin.setRatio(v);
+                               var d = this.data,
+                                       proxy = d.proxy,
+                                       mpt = d.firstMPT,
+                                       min = 0.000001,
+                                       val, pt, i, str;
+                               while (mpt) {
+                                       val = proxy[mpt.v];
+                                       if (mpt.r) {
+                                               val = (val > 0) ? (val + 0.5) | 0 : (val - 0.5) | 0;
+                                       } else if (val < min && val > -min) {
+                                               val = 0;
+                                       }
+                                       mpt.t[mpt.p] = val;
+                                       mpt = mpt._next;
+                               }
+                               if (d.autoRotate) {
+                                       d.autoRotate.rotation = proxy.rotation;
+                               }
+                               //at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method.
+                               if (v === 1) {
+                                       mpt = d.firstMPT;
+                                       while (mpt) {
+                                               pt = mpt.t;
+                                               if (!pt.type) {
+                                                       pt.e = pt.s + pt.xs0;
+                                               } else if (pt.type === 1) {
+                                                       str = pt.xs0 + pt.s + pt.xs1;
+                                                       for (i = 1; i < pt.l; i++) {
+                                                               str += pt["xn"+i] + pt["xs"+(i+1)];
+                                                       }
+                                                       pt.e = str;
+                                               }
+                                               mpt = mpt._next;
+                                       }
+                               }
+                       },
+
+                       /**
+                        * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value.
+                        * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
+                        * @param {!string} p property name
+                        * @param {(number|string|object)} v value
+                        * @param {MiniPropTween=} next next MiniPropTween in the linked list
+                        * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
+                        */
+                       MiniPropTween = function(t, p, v, next, r) {
+                               this.t = t;
+                               this.p = p;
+                               this.v = v;
+                               this.r = r;
+                               if (next) {
+                                       next._prev = this;
+                                       this._next = next;
+                               }
+                       },
+
+                       /**
+                        * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be rounded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element.
+                        * This method returns an object that has the following properties:
+                        *  - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin.  This is what we feed to the external _onInitTween() as the target
+                        *  - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values
+                        *  - firstMPT: the first MiniPropTween in the linked list
+                        *  - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter.
+                        * @param {!Object} t target object to be tweened
+                        * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
+                        * @param {!CSSPlugin} cssp The CSSPlugin instance
+                        * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
+                        * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
+                        * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter.
+                        * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
+                        */
+                       _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
+                               var bpt = pt,
+                                       start = {},
+                                       end = {},
+                                       transform = cssp._transform,
+                                       oldForce = _forcePT,
+                                       i, p, xp, mpt, firstPT;
+                               cssp._transform = null;
+                               _forcePT = vars;
+                               pt = firstPT = cssp.parse(t, vars, pt, plugin);
+                               _forcePT = oldForce;
+                               //break off from the linked list so the new ones are isolated.
+                               if (shallow) {
+                                       cssp._transform = transform;
+                                       if (bpt) {
+                                               bpt._prev = null;
+                                               if (bpt._prev) {
+                                                       bpt._prev._next = null;
+                                               }
+                                       }
+                               }
+                               while (pt && pt !== bpt) {
+                                       if (pt.type <= 1) {
+                                               p = pt.p;
+                                               end[p] = pt.s + pt.c;
+                                               start[p] = pt.s;
+                                               if (!shallow) {
+                                                       mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
+                                                       pt.c = 0;
+                                               }
+                                               if (pt.type === 1) {
+                                                       i = pt.l;
+                                                       while (--i > 0) {
+                                                               xp = "xn" + i;
+                                                               p = pt.p + "_" + xp;
+                                                               end[p] = pt.data[xp];
+                                                               start[p] = pt[xp];
+                                                               if (!shallow) {
+                                                                       mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       pt = pt._next;
+                               }
+                               return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
+                       },
+
+
+
+                       /**
+                        * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory.
+                        * CSSPropTweens have the following optional properties as well (not defined through the constructor):
+                        *  - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc.
+                        *  - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list)
+                        *  - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subtweens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request.
+                        *  - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target.
+                        *  - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible.
+                        * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
+                        * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
+                        * @param {number} s Starting numeric value
+                        * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95.
+                        * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it.
+                        * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update.
+                        * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip"
+                        * @param {boolean=} r If true, the value(s) should be rounded
+                        * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
+                        * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues.
+                        * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues.
+                        */
+                       CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
+                               this.t = t; //target
+                               this.p = p; //property
+                               this.s = s; //starting value
+                               this.c = c; //change value
+                               this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at)
+                               if (!(t instanceof CSSPropTween)) {
+                                       _overwriteProps.push(this.n);
+                               }
+                               this.r = r; //round (boolean)
+                               this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work
+                               if (pr) {
+                                       this.pr = pr;
+                                       _hasPriority = true;
+                               }
+                               this.b = (b === undefined) ? s : b;
+                               this.e = (e === undefined) ? s + c : e;
+                               if (next) {
+                                       this._next = next;
+                                       next._prev = this;
+                               }
+                       },
+
+                       /**
+                        * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
+                        * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
+                        * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio().
+                        * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method.
+                        *
+                        * @param {!Object} t Target whose property will be tweened
+                        * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
+                        * @param {string} b Beginning value
+                        * @param {string} e Ending value
+                        * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization)
+                        * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match
+                        * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
+                        * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
+                        * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300}
+                        * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here.
+                        * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
+                        */
+                       _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
+                               //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
+                               b = b || dflt || "";
+                               pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
+                               e += ""; //ensures it's a string
+                               var ba = b.split(", ").join(",").split(" "), //beginning array
+                                       ea = e.split(", ").join(",").split(" "), //ending array
+                                       l = ba.length,
+                                       autoRound = (_autoRound !== false),
+                                       i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
+                               if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
+                                       ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
+                                       ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
+                                       l = ba.length;
+                               }
+                               if (l !== ea.length) {
+                                       //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
+                                       ba = (dflt || "").split(" ");
+                                       l = ba.length;
+                               }
+                               pt.plugin = plugin;
+                               pt.setRatio = setRatio;
+                               for (i = 0; i < l; i++) {
+                                       bv = ba[i];
+                                       ev = ea[i];
+                                       bn = parseFloat(bv);
+
+                                       //if the value begins with a number (most common). It's fine if it has a suffix like px
+                                       if (bn || bn === 0) {
+                                               pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
+
+                                       //if the value is a color
+                                       } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
+                                               str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
+                                               bv = _parseColor(bv);
+                                               ev = _parseColor(ev);
+                                               rgba = (bv.length + ev.length > 6);
+                                               if (rgba && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color
+                                                       pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
+                                                       pt.e = pt.e.split(ea[i]).join("transparent");
+                                               } else {
+                                                       if (!_supportsOpacity) { //old versions of IE don't support rgba().
+                                                               rgba = false;
+                                                       }
+                                                       pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
+                                                               .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
+                                                               .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
+                                                       if (rgba) {
+                                                               bv = (bv.length < 4) ? 1 : bv[3];
+                                                               pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
+                                                       }
+                                               }
+
+                                       } else {
+                                               bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
+
+                                               //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
+                                               if (!bnums) {
+                                                       pt["xs" + pt.l] += pt.l ? " " + bv : bv;
+
+                                               //loop through all the numbers that are found and construct the extra values on the pt.
+                                               } else {
+                                                       enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5
+                                                       if (!enums || enums.length !== bnums.length) {
+                                                               //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
+                                                               return pt;
+                                                       }
+                                                       ni = 0;
+                                                       for (xi = 0; xi < bnums.length; xi++) {
+                                                               cv = bnums[xi];
+                                                               temp = bv.indexOf(cv, ni);
+                                                               pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
+                                                               ni = temp + cv.length;
+                                                       }
+                                                       pt["xs" + pt.l] += bv.substr(ni);
+                                               }
+                                       }
+                               }
+                               //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
+                               if (e.indexOf("=") !== -1) if (pt.data) {
+                                       str = pt.xs0 + pt.data.s;
+                                       for (i = 1; i < pt.l; i++) {
+                                               str += pt["xs" + i] + pt.data["xn" + i];
+                                       }
+                                       pt.e = str + pt["xs" + i];
+                               }
+                               if (!pt.l) {
+                                       pt.type = -1;
+                                       pt.xs0 = pt.e;
+                               }
+                               return pt.xfirst || pt;
+                       },
+                       i = 9;
+
+
+               p = CSSPropTween.prototype;
+               p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
+               while (--i > 0) {
+                       p["xn" + i] = 0;
+                       p["xs" + i] = "";
+               }
+               p.xs0 = "";
+               p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
+
+
+               /**
+                * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this:
+                * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
+                * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
+                * @param {string=} pfx Prefix (if any)
+                * @param {!number} s Starting value
+                * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95.
+                * @param {string=} sfx Suffix (if any)
+                * @param {boolean=} r Round (if true).
+                * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space.
+                * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
+                */
+               p.appendXtra = function(pfx, s, c, sfx, r, pad) {
+                       var pt = this,
+                               l = pt.l;
+                       pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
+                       if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value!
+                               pt["xs" + l] += s + (sfx || "");
+                               return pt;
+                       }
+                       pt.l++;
+                       pt.type = pt.setRatio ? 2 : 1;
+                       pt["xs" + pt.l] = sfx || "";
+                       if (l > 0) {
+                               pt.data["xn" + l] = s + c;
+                               pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
+                               pt["xn" + l] = s;
+                               if (!pt.plugin) {
+                                       pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
+                                       pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly.
+                               }
+                               return pt;
+                       }
+                       pt.data = {s:s + c};
+                       pt.rxp = {};
+                       pt.s = s;
+                       pt.c = c;
+                       pt.r = r;
+                       return pt;
+               };
+
+               /**
+                * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly.
+                * @param {!string} p Property name (like "boxShadow" or "throwProps")
+                * @param {Object=} options An object containing any of the following configuration options:
+                *                      - defaultValue: the default value
+                *                      - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker)
+                *                      - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.)
+                *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
+                *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
+                *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
+                *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
+                *                      - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc.
+                *                      - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default).
+                */
+               var SpecialProp = function(p, options) {
+                               options = options || {};
+                               this.p = options.prefix ? _checkPropPrefix(p) || p : p;
+                               _specialProps[p] = _specialProps[this.p] = this;
+                               this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
+                               if (options.parser) {
+                                       this.parse = options.parser;
+                               }
+                               this.clrs = options.color;
+                               this.multi = options.multi;
+                               this.keyword = options.keyword;
+                               this.dflt = options.defaultValue;
+                               this.pr = options.priority || 0;
+                       },
+
+                       //shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin.
+                       _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
+                               if (typeof(options) !== "object") {
+                                       options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
+                               }
+                               var a = p.split(","),
+                                       d = options.defaultValue,
+                                       i, temp;
+                               defaults = defaults || [d];
+                               for (i = 0; i < a.length; i++) {
+                                       options.prefix = (i === 0 && options.prefix);
+                                       options.defaultValue = defaults[i] || d;
+                                       temp = new SpecialProp(a[i], options);
+                               }
+                       },
+
+                       //creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file.
+                       _registerPluginProp = function(p) {
+                               if (!_specialProps[p]) {
+                                       var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
+                                       _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                                               var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
+                                               if (!pluginClass) {
+                                                       _log("Error: " + pluginName + " js file not loaded.");
+                                                       return pt;
+                                               }
+                                               pluginClass._cssRegister();
+                                               return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
+                                       }});
+                               }
+                       };
+
+
+               p = SpecialProp.prototype;
+
+               /**
+                * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxShadow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list)
+                * @param {!Object} t target element
+                * @param {(string|number|object)} b beginning value
+                * @param {(string|number|object)} e ending (destination) value
+                * @param {CSSPropTween=} pt next CSSPropTween in the linked list
+                * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
+                * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
+                * @return {CSSPropTween=} First CSSPropTween in the linked list
+                */
+               p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
+                       var kwd = this.keyword,
+                               i, ba, ea, l, bi, ei;
+                       //if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example)
+                       if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
+                               ba = b.replace(_commasOutsideParenExp, "|").split("|");
+                               ea = e.replace(_commasOutsideParenExp, "|").split("|");
+                       } else if (kwd) {
+                               ba = [b];
+                               ea = [e];
+                       }
+                       if (ea) {
+                               l = (ea.length > ba.length) ? ea.length : ba.length;
+                               for (i = 0; i < l; i++) {
+                                       b = ba[i] = ba[i] || this.dflt;
+                                       e = ea[i] = ea[i] || this.dflt;
+                                       if (kwd) {
+                                               bi = b.indexOf(kwd);
+                                               ei = e.indexOf(kwd);
+                                               if (bi !== ei) {
+                                                       e = (ei === -1) ? ea : ba;
+                                                       e[i] += " " + kwd;
+                                               }
+                                       }
+                               }
+                               b = ba.join(", ");
+                               e = ea.join(", ");
+                       }
+                       return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
+               };
+
+               /**
+                * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call:
+                * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
+                * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that).
+                * @param {!Object) t Target object whose property is being tweened
+                * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
+                * @param {!string} p Property name
+                * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
+                * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
+                * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
+                * @param {Object=} vars Original vars object that contains the data for parsing.
+                * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
+                */
+               p.parse = function(t, e, p, cssp, pt, plugin, vars) {
+                       return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
+               };
+
+               /**
+                * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters:
+                *  1) Target object whose property should be tweened (typically a DOM element)
+                *  2) The end/destination value (could be a string, number, object, or whatever you want)
+                *  3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration)
+                *
+                * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example:
+                *
+                * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
+                *      var start = target.style.width;
+                *      return function(ratio) {
+                *              target.style.width = (start + value * ratio) + "px";
+                *              console.log("set width to " + target.style.width);
+                *          }
+                * }, 0);
+                *
+                * Then, when I do this tween, it will trigger my special property:
+                *
+                * TweenLite.to(element, 1, {css:{myCustomProp:100}});
+                *
+                * In the example, of course, we're just changing the width, but you can do anything you want.
+                *
+                * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}})
+                * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function.
+                * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones.
+                */
+               CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
+                       _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                               var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
+                               rv.plugin = plugin;
+                               rv.setRatio = onInitTween(t, e, cssp._tween, p);
+                               return rv;
+                       }, priority:priority});
+               };
+
+
+
+
+
+
+
+
+               //transform-related methods and properties
+               var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,rotation,rotationX,rotationY,perspective").split(","),
+                       _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
+                       _transformPropCSS = _prefixCSS + "transform",
+                       _transformOriginProp = _checkPropPrefix("transformOrigin"),
+                       _supports3D = (_checkPropPrefix("perspective") !== null),
+
+                       /**
+                        * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
+                        * @param {!Object} t target element
+                        * @param {Object=} cs computed style object (optional)
+                        * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...}
+                        * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style)
+                        * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
+                        */
+                       _getTransform = function(t, cs, rec, parse) {
+                               if (t._gsTransform && rec && !parse) {
+                                       return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things.
+                               }
+                               var tm = rec ? t._gsTransform || {skewY:0} : {skewY:0},
+                                       invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
+                                       min = 0.00002,
+                                       rnd = 100000,
+                                       minPI = -Math.PI + 0.0001,
+                                       maxPI = Math.PI - 0.0001,
+                                       zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
+                                       s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
+                               if (_transformProp) {
+                                       s = _getStyle(t, _transformPropCSS, cs, true);
+                               } else if (t.currentStyle) {
+                                       //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
+                                       s = t.currentStyle.filter.match(_ieGetMatrixExp);
+                                       s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
+                               }
+                               //split the matrix values out into an array (m for matrix)
+                               m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
+                               i = m.length;
+                               while (--i > -1) {
+                                       n = Number(m[i]);
+                                       m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
+                               }
+                               if (m.length === 16) {
+
+                                       //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
+                                       var a13 = m[8], a23 = m[9], a33 = m[10],
+                                               a14 = m[12], a24 = m[13], a34 = m[14];
+
+                                       //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
+                                       if (tm.zOrigin) {
+                                               a34 = -tm.zOrigin;
+                                               a14 = a13*a34-m[12];
+                                               a24 = a23*a34-m[13];
+                                               a34 = a33*a34+tm.zOrigin-m[14];
+                                       }
+
+                                       //only parse from the matrix if we MUST because not only is it usually unnecessary due to the fact that we store the values in the _gsTransform object, but also because it's impossible to accurately interpret rotationX, rotationY, and rotationZ if all are applied, so it's much better to rely on what we store. However, we must parse the first time that an object is tweened. We also assume that if the position has changed, the user must have done some styling changes outside of CSSPlugin, thus we force a parse in that scenario.
+                                       if (!rec || parse || tm.rotationX == null) {
+                                               var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
+                                                       a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
+                                                       a43 = m[11],
+                                                       angle = tm.rotationX = Math.atan2(a32, a33),
+                                                       xFlip = (angle < minPI || angle > maxPI),
+                                                       t1, t2, t3, cos, sin, yFlip, zFlip;
+                                               //rotationX
+                                               if (angle) {
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       t1 = a12*cos+a13*sin;
+                                                       t2 = a22*cos+a23*sin;
+                                                       t3 = a32*cos+a33*sin;
+                                                       //t4 = a42*cos+a43*sin;
+                                                       a13 = a12*-sin+a13*cos;
+                                                       a23 = a22*-sin+a23*cos;
+                                                       a33 = a32*-sin+a33*cos;
+                                                       a43 = a42*-sin+a43*cos;
+                                                       a12 = t1;
+                                                       a22 = t2;
+                                                       a32 = t3;
+                                                       //a42 = t4;
+                                               }
+                                               //rotationY
+                                               angle = tm.rotationY = Math.atan2(a13, a11);
+                                               if (angle) {
+                                                       yFlip = (angle < minPI || angle > maxPI);
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       t1 = a11*cos-a13*sin;
+                                                       t2 = a21*cos-a23*sin;
+                                                       t3 = a31*cos-a33*sin;
+                                                       //t4 = a41*cos-a43*sin;
+                                                       //a13 = a11*sin+a13*cos;
+                                                       a23 = a21*sin+a23*cos;
+                                                       a33 = a31*sin+a33*cos;
+                                                       a43 = a41*sin+a43*cos;
+                                                       a11 = t1;
+                                                       a21 = t2;
+                                                       a31 = t3;
+                                                       //a41 = t4;
+                                               }
+                                               //rotationZ
+                                               angle = tm.rotation = Math.atan2(a21, a22);
+                                               if (angle) {
+                                                       zFlip = (angle < minPI || angle > maxPI);
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       a11 = a11*cos+a12*sin;
+                                                       t2 = a21*cos+a22*sin;
+                                                       a22 = a21*-sin+a22*cos;
+                                                       a32 = a31*-sin+a32*cos;
+                                                       a21 = t2;
+                                               }
+
+                                               if (zFlip && xFlip) {
+                                                       tm.rotation = tm.rotationX = 0;
+                                               } else if (zFlip && yFlip) {
+                                                       tm.rotation = tm.rotationY = 0;
+                                               } else if (yFlip && xFlip) {
+                                                       tm.rotationY = tm.rotationX = 0;
+                                               }
+
+                                               tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
+                                               tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
+                                               tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
+                                               tm.skewX = 0;
+                                               tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
+                                               tm.x = a14;
+                                               tm.y = a24;
+                                               tm.z = a34;
+                                       }
+
+                               } else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those.
+                                       var k = (m.length >= 6),
+                                               a = k ? m[0] : 1,
+                                               b = m[1] || 0,
+                                               c = m[2] || 0,
+                                               d = k ? m[3] : 1;
+                                       tm.x = m[4] || 0;
+                                       tm.y = m[5] || 0;
+                                       scaleX = Math.sqrt(a * a + b * b);
+                                       scaleY = Math.sqrt(d * d + c * c);
+                                       rotation = (a || b) ? Math.atan2(b, a) : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
+                                       skewX = (c || d) ? Math.atan2(c, d) + rotation : tm.skewX || 0;
+                                       difX = scaleX - Math.abs(tm.scaleX || 0);
+                                       difY = scaleY - Math.abs(tm.scaleY || 0);
+                                       if (Math.abs(skewX) > Math.PI / 2 && Math.abs(skewX) < Math.PI * 1.5) {
+                                               if (invX) {
+                                                       scaleX *= -1;
+                                                       skewX += (rotation <= 0) ? Math.PI : -Math.PI;
+                                                       rotation += (rotation <= 0) ? Math.PI : -Math.PI;
+                                               } else {
+                                                       scaleY *= -1;
+                                                       skewX += (skewX <= 0) ? Math.PI : -Math.PI;
+                                               }
+                                       }
+                                       difR = (rotation - tm.rotation) % Math.PI; //note: matching ranges would be very small (+/-0.0001) or very close to Math.PI (+/-3.1415).
+                                       difS = (skewX - tm.skewX) % Math.PI;
+                                       //if there's already a recorded _gsTransform in place for the target, we should leave those values in place unless we know things changed for sure (beyond a super small amount). This gets around ambiguous interpretations, like if scaleX and scaleY are both -1, the matrix would be the same as if the rotation was 180 with normal scaleX/scaleY. If the user tweened to particular values, those must be prioritized to ensure animation is consistent.
+                                       if (tm.skewX === undefined || difX > min || difX < -min || difY > min || difY < -min || (difR > minPI && difR < maxPI && (difR * rnd) | 0 !== 0) || (difS > minPI && difS < maxPI && (difS * rnd) | 0 !== 0)) {
+                                               tm.scaleX = scaleX;
+                                               tm.scaleY = scaleY;
+                                               tm.rotation = rotation;
+                                               tm.skewX = skewX;
+                                       }
+                                       if (_supports3D) {
+                                               tm.rotationX = tm.rotationY = tm.z = 0;
+                                               tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
+                                               tm.scaleZ = 1;
+                                       }
+                               }
+                               tm.zOrigin = zOrigin;
+
+                               //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate.
+                               for (i in tm) {
+                                       if (tm[i] < min) if (tm[i] > -min) {
+                                               tm[i] = 0;
+                                       }
+                               }
+                               //DEBUG: _log("parsed rotation: "+(tm.rotationX*_RAD2DEG)+", "+(tm.rotationY*_RAD2DEG)+", "+(tm.rotation*_RAD2DEG)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective);
+                               if (rec) {
+                                       t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
+                               }
+                               return tm;
+                       },
+                       //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
+                       _setIETransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       ang = -t.rotation,
+                                       skew = ang + t.skewX,
+                                       rnd = 100000,
+                                       a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
+                                       b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
+                                       c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
+                                       d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
+                                       style = this.t.style,
+                                       cs = this.t.currentStyle,
+                                       filters, val;
+                               if (!cs) {
+                                       return;
+                               }
+                               val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted)
+                               b = -c;
+                               c = -val;
+                               filters = cs.filter;
+                               style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
+                               var w = this.t.offsetWidth,
+                                       h = this.t.offsetHeight,
+                                       clip = (cs.position !== "absolute"),
+                                       m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
+                                       ox = t.x,
+                                       oy = t.y,
+                                       dx, dy;
+
+                               //if transformOrigin is being used, adjust the offset x and y
+                               if (t.ox != null) {
+                                       dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
+                                       dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
+                                       ox += dx - (dx * a + dy * b);
+                                       oy += dy - (dx * c + dy * d);
+                               }
+
+                               if (!clip) {
+                                       var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom
+                                               marg, prop, dif;
+                                       dx = t.ieOffsetX || 0;
+                                       dy = t.ieOffsetY || 0;
+                                       t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
+                                       t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
+                                       for (i = 0; i < 4; i++) {
+                                               prop = _margins[i];
+                                               marg = cs[prop];
+                                               //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
+                                               val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
+                                               if (val !== t[prop]) {
+                                                       dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible.
+                                               } else {
+                                                       dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
+                                               }
+                                               style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
+                                       }
+                                       m += ", sizingMethod='auto expand')";
+                               } else {
+                                       dx = (w / 2);
+                                       dy = (h / 2);
+                                       //translate to ensure that transformations occur around the correct origin (default is center).
+                                       m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
+                               }
+                               if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
+                                       style.filter = filters.replace(_ieSetMatrixExp, m);
+                               } else {
+                                       style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha.
+                               }
+
+                               //at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance.
+                               if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(") === -1) {
+                                       style.removeAttribute("filter");
+                               }
+                       },
+                       _set3DTransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       style = this.t.style,
+                                       perspective = t.perspective,
+                                       a11 = t.scaleX, a12 = 0, a13 = 0, a14 = 0,
+                                       a21 = 0, a22 = t.scaleY, a23 = 0, a24 = 0,
+                                       a31 = 0, a32 = 0, a33 = t.scaleZ, a34 = 0,
+                                       a41 = 0, a42 = 0, a43 = (perspective) ? -1 / perspective : 0,
+                                       angle = t.rotation,
+                                       zOrigin = t.zOrigin,
+                                       rnd = 100000,
+                                       cos, sin, t1, t2, t3, t4, ffProp, n, sfx;
+
+                               if (_isFirefox) { //Firefox has a bug that causes 3D elements to randomly disappear during animation unless a repaint is forced. One way to do this is change "top" or "bottom" by 0.05 which is imperceptible, so we go back and forth. Another way is to change the display to "none", read the clientTop, and then revert the display but that is much slower.
+                                       ffProp = style.top ? "top" : style.bottom ? "bottom" : parseFloat(_getStyle(this.t, "top", null, false)) ? "bottom" : "top";
+                                       t1 = _getStyle(this.t, ffProp, null, false);
+                                       n = parseFloat(t1) || 0;
+                                       sfx = t1.substr((n + "").length) || "px";
+                                       t._ffFix = !t._ffFix;
+                                       style[ffProp] = (t._ffFix ? n + 0.05 : n - 0.05) + sfx;
+                               }
+
+                               if (angle || t.skewX) {
+                                       t1 = a11*Math.cos(angle);
+                                       t2 = a22*Math.sin(angle);
+                                       angle -= t.skewX;
+                                       a12 = a11*-Math.sin(angle);
+                                       a22 = a22*Math.cos(angle);
+                                       a11 = t1;
+                                       a21 = t2;
+                               } else if (!t.rotationY && !t.rotationX && a33 === 1) { //if we're only translating and/or 2D scaling, this is faster...
+                                       style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((a11 !== 1 || a22 !== 1) ? " scale(" + a11 + "," + a22 + ")" : "");
+                                       return;
+                               }
+                               angle = t.rotationY;
+                               if (angle) {
+                                       cos = Math.cos(angle);
+                                       sin = Math.sin(angle);
+                                       t1 = a11*cos;
+                                       t2 = a21*cos;
+                                       t3 = a33*-sin;
+                                       t4 = a43*-sin;
+                                       a13 = a11*sin;
+                                       a23 = a21*sin;
+                                       a33 = a33*cos;
+                                       a43 *= cos;
+                                       a11 = t1;
+                                       a21 = t2;
+                                       a31 = t3;
+                                       a41 = t4;
+                               }
+                               angle = t.rotationX;
+                               if (angle) {
+                                       cos = Math.cos(angle);
+                                       sin = Math.sin(angle);
+                                       t1 = a12*cos+a13*sin;
+                                       t2 = a22*cos+a23*sin;
+                                       t3 = a32*cos+a33*sin;
+                                       t4 = a42*cos+a43*sin;
+                                       a13 = a12*-sin+a13*cos;
+                                       a23 = a22*-sin+a23*cos;
+                                       a33 = a32*-sin+a33*cos;
+                                       a43 = a42*-sin+a43*cos;
+                                       a12 = t1;
+                                       a22 = t2;
+                                       a32 = t3;
+                                       a42 = t4;
+                               }
+                               if (zOrigin) {
+                                       a34 -= zOrigin;
+                                       a14 = a13*a34;
+                                       a24 = a23*a34;
+                                       a34 = a33*a34+zOrigin;
+                               }
+                               //we round the x, y, and z slightly differently to allow even larger values.
+                               a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
+                               a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
+                               a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
+                               style[_transformProp] = "matrix3d(" + [ (((a11 * rnd) | 0) / rnd), (((a21 * rnd) | 0) / rnd), (((a31 * rnd) | 0) / rnd), (((a41 * rnd) | 0) / rnd), (((a12 * rnd) | 0) / rnd), (((a22 * rnd) | 0) / rnd), (((a32 * rnd) | 0) / rnd), (((a42 * rnd) | 0) / rnd), (((a13 * rnd) | 0) / rnd), (((a23 * rnd) | 0) / rnd), (((a33 * rnd) | 0) / rnd), (((a43 * rnd) | 0) / rnd), a14, a24, a34, (perspective ? (1 + (-a34 / perspective)) : 1) ].join(",") + ")";
+                       },
+                       _set2DTransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       targ = this.t,
+                                       style = targ.style,
+                                       ffProp, t1, n, sfx, ang, skew, rnd, sx, sy;
+                               if (_isFirefox) { //Firefox has a bug that causes elements to randomly disappear during animation unless a repaint is forced. One way to do this is change "top" or "bottom" by 0.05 which is imperceptible, so we go back and forth. Another way is to change the display to "none", read the clientTop, and then revert the display but that is much slower.
+                                       ffProp = style.top ? "top" : style.bottom ? "bottom" : parseFloat(_getStyle(targ, "top", null, false)) ? "bottom" : "top";
+                                       t1 = _getStyle(targ, ffProp, null, false);
+                                       n = parseFloat(t1) || 0;
+                                       sfx = t1.substr((n + "").length) || "px";
+                                       t._ffFix = !t._ffFix;
+                                       style[ffProp] = (t._ffFix ? n + 0.05 : n - 0.05) + sfx;
+                               }
+                               if (!t.rotation && !t.skewX) {
+                                       style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
+                               } else {
+                                       ang = t.rotation;
+                                       skew = ang - t.skewX;
+                                       rnd = 100000;
+                                       sx = t.scaleX * rnd;
+                                       sy = t.scaleY * rnd;
+                                       //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places.
+                                       style[_transformProp] = "matrix(" + (((Math.cos(ang) * sx) | 0) / rnd) + "," + (((Math.sin(ang) * sx) | 0) / rnd) + "," + (((Math.sin(skew) * -sy) | 0) / rnd) + "," + (((Math.cos(skew) * sy) | 0) / rnd) + "," + t.x + "," + t.y + ")";
+                               }
+                       };
+
+               _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform", {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                       if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
+                       var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
+                               style = t.style,
+                               min = 0.000001,
+                               i = _transformProps.length,
+                               v = vars,
+                               endRotations = {},
+                               m2, skewY, copy, orig, has3D, hasChange, dr;
+
+                       if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
+                               copy = style.cssText;
+                               style[_transformProp] = v.transform;
+                               style.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
+                               m2 = _getTransform(t, null, false);
+                               style.cssText = copy;
+                       } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
+                               m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
+                                       scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
+                                       scaleZ:_parseVal((v.scaleZ != null) ? v.scaleZ : v.scale, m1.scaleZ),
+                                       x:_parseVal(v.x, m1.x),
+                                       y:_parseVal(v.y, m1.y),
+                                       z:_parseVal(v.z, m1.z),
+                                       perspective:_parseVal(v.transformPerspective, m1.perspective)};
+                               dr = v.directionalRotation;
+                               if (dr != null) {
+                                       if (typeof(dr) === "object") {
+                                               for (copy in dr) {
+                                                       v[copy] = dr[copy];
+                                               }
+                                       } else {
+                                               v.rotation = dr;
+                                       }
+                               }
+                               m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : (m1.rotation * _RAD2DEG), m1.rotation, "rotation", endRotations);
+                               if (_supports3D) {
+                                       m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : (m1.rotationX * _RAD2DEG) || 0, m1.rotationX, "rotationX", endRotations);
+                                       m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : (m1.rotationY * _RAD2DEG) || 0, m1.rotationY, "rotationY", endRotations);
+                               }
+                               m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
+
+                               //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
+                               m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
+                               if ((skewY = m2.skewY - m1.skewY)) {
+                                       m2.skewX += skewY;
+                                       m2.rotation += skewY;
+                               }
+                       }
+
+                       has3D = (m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
+                       if (!has3D && v.scale != null) {
+                               m2.scaleZ = 1; //no need to tween scaleZ.
+                       }
+
+                       while (--i > -1) {
+                               p = _transformProps[i];
+                               orig = m2[p] - m1[p];
+                               if (orig > min || orig < -min || _forcePT[p] != null) {
+                                       hasChange = true;
+                                       pt = new CSSPropTween(m1, p, m1[p], orig, pt);
+                                       if (p in endRotations) {
+                                               pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested
+                                       }
+                                       pt.xs0 = 0; //ensures the value stays numeric in setRatio()
+                                       pt.plugin = plugin;
+                                       cssp._overwriteProps.push(pt.n);
+                               }
+                       }
+
+                       orig = v.transformOrigin;
+                       if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
+                               if (_transformProp) {
+                                       hasChange = true;
+                                       orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
+                                       p = _transformOriginProp;
+                                       pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
+                                       pt.b = style[p];
+                                       pt.plugin = plugin;
+                                       if (_supports3D) {
+                                               copy = m1.zOrigin;
+                                               orig = orig.split(" ");
+                                               m1.zOrigin = ((orig.length > 2) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method.
+                                               pt.xs0 = pt.e = style[p] = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)!
+                                               pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here)
+                                               pt.b = copy;
+                                               pt.xs0 = pt.e = m1.zOrigin;
+                                       } else {
+                                               pt.xs0 = pt.e = style[p] = orig;
+                                       }
+
+                               //for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp).
+                               } else {
+                                       _parsePosition(orig + "", m1);
+                               }
+                       }
+
+                       if (hasChange) {
+                               cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
+                       }
+                       return pt;
+               }, prefix:true});
+
+               _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
+
+               _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
+                       e = this.format(e);
+                       var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
+                               style = t.style,
+                               ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
+                       w = parseFloat(t.offsetWidth);
+                       h = parseFloat(t.offsetHeight);
+                       ea1 = e.split(" ");
+                       for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
+                               if (this.p.indexOf("border")) { //older browsers used a prefix
+                                       props[i] = _checkPropPrefix(props[i]);
+                               }
+                               bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
+                               if (bs.indexOf(" ") !== -1) {
+                                       bs2 = bs.split(" ");
+                                       bs = bs2[0];
+                                       bs2 = bs2[1];
+                               }
+                               es = es2 = ea1[i];
+                               bn = parseFloat(bs);
+                               bsfx = bs.substr((bn + "").length);
+                               rel = (es.charAt(1) === "=");
+                               if (rel) {
+                                       en = parseInt(es.charAt(0)+"1", 10);
+                                       es = es.substr(2);
+                                       en *= parseFloat(es);
+                                       esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
+                               } else {
+                                       en = parseFloat(es);
+                                       esfx = es.substr((en + "").length);
+                               }
+                               if (esfx === "") {
+                                       esfx = _suffixMap[p] || bsfx;
+                               }
+                               if (esfx !== bsfx) {
+                                       hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent.
+                                       vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
+                                       if (esfx === "%") {
+                                               bs = (hn / w * 100) + "%";
+                                               bs2 = (vn / h * 100) + "%";
+                                       } else if (esfx === "em") {
+                                               em = _convertToPixels(t, "borderLeft", 1, "em");
+                                               bs = (hn / em) + "em";
+                                               bs2 = (vn / em) + "em";
+                                       } else {
+                                               bs = hn + "px";
+                                               bs2 = vn + "px";
+                                       }
+                                       if (rel) {
+                                               es = (parseFloat(bs) + en) + esfx;
+                                               es2 = (parseFloat(bs2) + en) + esfx;
+                                       }
+                               }
+                               pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
+                       }
+                       return pt;
+               }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
+               _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
+                       var bp = "background-position",
+                               cs = (_cs || _getComputedStyle(t, null)),
+                               bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase
+                               es = this.format(e),
+                               ba, ea, i, pct, overlap, src;
+                       if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
+                               src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
+                               if (src && src !== "none") {
+                                       ba = bs.split(" ");
+                                       ea = es.split(" ");
+                                       _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
+                                       i = 2;
+                                       while (--i > -1) {
+                                               bs = ba[i];
+                                               pct = (bs.indexOf("%") !== -1);
+                                               if (pct !== (ea[i].indexOf("%") !== -1)) {
+                                                       overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
+                                                       ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
+                                               }
+                                       }
+                                       bs = ba.join(" ");
+                               }
+                       }
+                       return this.parseComplex(t.style, bs, es, pt, plugin);
+               }, formatter:_parsePosition});
+               _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
+               _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
+               _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
+               _registerComplexSpecialProp("transformStyle", {prefix:true});
+               _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
+               _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
+               _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
+               _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
+                       var b, cs, delim;
+                       if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited.
+                               cs = t.currentStyle;
+                               delim = _ieVers < 8 ? " " : ",";
+                               b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
+                               e = this.format(e).split(",").join(delim);
+                       } else {
+                               b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
+                               e = this.format(e);
+                       }
+                       return this.parseComplex(t.style, b, e, pt, plugin);
+               }});
+               _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
+               _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
+               _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
+                               return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin);
+                       }, color:true, formatter:function(v) {
+                               var a = v.split(" ");
+                               return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
+                       }});
+               _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
+                       var s = t.style,
+                               prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
+                       return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
+               }});
+
+               //opacity-related
+               var _setIEOpacityRatio = function(v) {
+                               var t = this.t, //refers to the element's style property
+                                       filters = t.filter,
+                                       val = (this.s + this.c * v) | 0,
+                                       skip;
+                               if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters.
+                                       if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1) {
+                                               t.removeAttribute("filter");
+                                               skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check.
+                                       } else {
+                                               t.filter = filters.replace(_alphaFilterExp, "");
+                                               skip = true;
+                                       }
+                               }
+                               if (!skip) {
+                                       if (this.xn1) {
+                                               t.filter = filters = filters || "alpha(opacity=100)"; //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame.
+                                       }
+                                       if (filters.indexOf("opacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8)
+                                               t.filter += " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
+                                       } else {
+                                               t.filter = filters.replace(_opacityExp, "opacity=" + val);
+                                       }
+                               }
+                       };
+               _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
+                       var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
+                               style = t.style,
+                               vb;
+                       e = parseFloat(e);
+                       if (p === "autoAlpha") {
+                               vb = _getStyle(t, "visibility", _cs);
+                               if (b === 1 && vb === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience)
+                                       b = 0;
+                               }
+                               pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "visible" : "hidden"), ((e === 0) ? "hidden" : "visible"));
+                               pt.xs0 = "visible";
+                               cssp._overwriteProps.push(pt.n);
+                       }
+                       if (_supportsOpacity) {
+                               pt = new CSSPropTween(style, "opacity", b, e - b, pt);
+                       } else {
+                               pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
+                               pt.xn1 = (p === "autoAlpha") ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug.
+                               style.zoom = 1; //helps correct an IE issue.
+                               pt.type = 2;
+                               pt.b = "alpha(opacity=" + pt.s + ")";
+                               pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
+                               pt.data = t;
+                               pt.plugin = plugin;
+                               pt.setRatio = _setIEOpacityRatio;
+                       }
+                       return pt;
+               }});
+
+
+               var _removeProp = function(s, p) {
+                               if (p) {
+                                       if (s.removeProperty) {
+                                               s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
+                                       } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
+                                               s.removeAttribute(p);
+                                       }
+                               }
+                       },
+                       _setClassNameRatio = function(v) {
+                               this.t._gsClassPT = this;
+                               if (v === 1 || v === 0) {
+                                       this.t.className = (v === 0) ? this.b : this.e;
+                                       var mpt = this.data, //first MiniPropTween
+                                               s = this.t.style;
+                                       while (mpt) {
+                                               if (!mpt.v) {
+                                                       _removeProp(s, mpt.p);
+                                               } else {
+                                                       s[mpt.p] = mpt.v;
+                                               }
+                                               mpt = mpt._next;
+                                       }
+                                       if (v === 1 && this.t._gsClassPT === this) {
+                                               this.t._gsClassPT = null;
+                                       }
+                               } else if (this.t.className !== this.e) {
+                                       this.t.className = this.e;
+                               }
+                       };
+               _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                       var b = t.className,
+                               cssText = t.style.cssText,
+                               difData, bs, cnpt, cnptLookup, mpt;
+                       pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
+                       pt.setRatio = _setClassNameRatio;
+                       pt.pr = -11;
+                       _hasPriority = true;
+                       pt.b = b;
+                       bs = _getAllStyles(t, _cs);
+                       //if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfering that were there just for class-specific values)
+                       cnpt = t._gsClassPT;
+                       if (cnpt) {
+                               cnptLookup = {};
+                               mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned.
+                               while (mpt) {
+                                       cnptLookup[mpt.p] = 1;
+                                       mpt = mpt._next;
+                               }
+                               cnpt.setRatio(1);
+                       }
+                       t._gsClassPT = pt;
+                       pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
+                       if (cssp._tween._duration) { //if it's a zero-duration tween, there's no need to tween anything or parse the data. In fact, if we switch classes temporarily (which we must do for proper parsing) and the class has a transition applied, it could cause a quick flash to the end state and back again initially in some browsers.
+                               t.className = pt.e;
+                               difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
+                               t.className = b;
+                               pt.data = difData.firstMPT;
+                               t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
+                               pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
+                       }
+                       return pt;
+               }});
+
+
+               var _setClearPropsRatio = function(v) {
+                       if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration) { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that).
+                               var all = (this.e === "all"),
+                                       s = this.t.style,
+                                       a = all ? s.cssText.split(";") : this.e.split(","),
+                                       i = a.length,
+                                       transformParse = _specialProps.transform.parse,
+                                       p;
+                               while (--i > -1) {
+                                       p = a[i];
+                                       if (all) {
+                                               p = p.substr(0, p.indexOf(":")).split(" ").join("");
+                                       }
+                                       if (_specialProps[p]) {
+                                               p = (_specialProps[p].parse === transformParse) ? _transformProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow"
+                                       }
+                                       _removeProp(s, p);
+                               }
+                       }
+               };
+               _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
+                       pt = new CSSPropTween(t, p, 0, 0, pt, 2);
+                       pt.setRatio = _setClearPropsRatio;
+                       pt.e = e;
+                       pt.pr = -10;
+                       pt.data = cssp._tween;
+                       _hasPriority = true;
+                       return pt;
+               }});
+
+               p = "bezier,throwProps,physicsProps,physics2D".split(",");
+               i = p.length;
+               while (i--) {
+                       _registerPluginProp(p[i]);
+               }
+
+
+
+
+
+
+
+
+               p = CSSPlugin.prototype;
+               p._firstPT = null;
+
+               //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
+               p._onInitTween = function(target, vars, tween) {
+                       if (!target.nodeType) { //css is only for dom elements
+                               return false;
+                       }
+                       this._target = target;
+                       this._tween = tween;
+                       this._vars = vars;
+                       _autoRound = vars.autoRound;
+                       _hasPriority = false;
+                       _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
+                       _cs = _getComputedStyle(target, "");
+                       _overwriteProps = this._overwriteProps;
+                       var style = target.style,
+                               v, pt, pt2, first, last, next, zIndex, tpt, threeD;
+
+                       if (_reqSafariFix) if (style.zIndex === "") {
+                               v = _getStyle(target, "zIndex", _cs);
+                               if (v === "auto" || v === "") {
+                                       //corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive.
+                                       style.zIndex = 0;
+                               }
+                       }
+
+                       if (typeof(vars) === "string") {
+                               first = style.cssText;
+                               v = _getAllStyles(target, _cs);
+                               style.cssText = first + ";" + vars;
+                               v = _cssDif(target, v, _getAllStyles(target)).difs;
+                               if (!_supportsOpacity && _opacityValExp.test(vars)) {
+                                       v.opacity = parseFloat( RegExp.$1 );
+                               }
+                               vars = v;
+                               style.cssText = first;
+                       }
+                       this._firstPT = pt = this.parse(target, vars, null);
+
+                       if (this._transformType) {
+                               threeD = (this._transformType === 3);
+                               if (!_transformProp) {
+                                       style.zoom = 1; //helps correct an IE issue.
+                               } else if (_isSafari) {
+                                       _reqSafariFix = true;
+                                       //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
+                                       if (style.zIndex === "") {
+                                               zIndex = _getStyle(target, "zIndex", _cs);
+                                               if (zIndex === "auto" || zIndex === "") {
+                                                       style.zIndex = 0;
+                                               }
+                                       }
+                                       //Setting WebkitBackfaceVisibility corrects 3 bugs:
+                                       // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
+                                       // 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly.
+                                       // 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug.
+                                       //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
+                                       if (_isSafariLT6) {
+                                               style.WebkitBackfaceVisibility = this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden");
+                                       }
+                               }
+                               pt2 = pt;
+                               while (pt2 && pt2._next) {
+                                       pt2 = pt2._next;
+                               }
+                               tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
+                               this._linkCSSP(tpt, null, pt2);
+                               tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
+                               tpt.data = this._transform || _getTransform(target, _cs, true);
+                               _overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here.
+                       }
+
+                       if (_hasPriority) {
+                               //reorders the linked list in order of pr (priority)
+                               while (pt) {
+                                       next = pt._next;
+                                       pt2 = first;
+                                       while (pt2 && pt2.pr > pt.pr) {
+                                               pt2 = pt2._next;
+                                       }
+                                       if ((pt._prev = pt2 ? pt2._prev : last)) {
+                                               pt._prev._next = pt;
+                                       } else {
+                                               first = pt;
+                                       }
+                                       if ((pt._next = pt2)) {
+                                               pt2._prev = pt;
+                                       } else {
+                                               last = pt;
+                                       }
+                                       pt = next;
+                               }
+                               this._firstPT = first;
+                       }
+                       return true;
+               };
+
+
+               p.parse = function(target, vars, pt, plugin) {
+                       var style = target.style,
+                               p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
+                       for (p in vars) {
+                               es = vars[p]; //ending value string
+                               sp = _specialProps[p]; //SpecialProp lookup.
+                               if (sp) {
+                                       pt = sp.parse(target, es, p, this, pt, plugin, vars);
+
+                               } else {
+                                       bs = _getStyle(target, p, _cs) + "";
+                                       isStr = (typeof(es) === "string");
+                                       if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor:
+                                               if (!isStr) {
+                                                       es = _parseColor(es);
+                                                       es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
+                                               }
+                                               pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
+
+                                       } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
+                                               pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
+
+                                       } else {
+                                               bn = parseFloat(bs);
+                                               bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case.
+
+                                               if (bs === "" || bs === "auto") {
+                                                       if (p === "width" || p === "height") {
+                                                               bn = _getDimension(target, p, _cs);
+                                                               bsfx = "px";
+                                                       } else if (p === "left" || p === "top") {
+                                                               bn = _calculateOffset(target, p, _cs);
+                                                               bsfx = "px";
+                                                       } else {
+                                                               bn = (p !== "opacity") ? 0 : 1;
+                                                               bsfx = "";
+                                                       }
+                                               }
+
+                                               rel = (isStr && es.charAt(1) === "=");
+                                               if (rel) {
+                                                       en = parseInt(es.charAt(0) + "1", 10);
+                                                       es = es.substr(2);
+                                                       en *= parseFloat(es);
+                                                       esfx = es.replace(_suffixExp, "");
+                                               } else {
+                                                       en = parseFloat(es);
+                                                       esfx = isStr ? es.substr((en + "").length) || "" : "";
+                                               }
+
+                                               if (esfx === "") {
+                                                       esfx = _suffixMap[p] || bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
+                                               }
+
+                                               es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix.
+
+                                               //if the beginning/ending suffixes don't match, normalize them...
+                                               if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn || bn === 0) {
+                                                       bn = _convertToPixels(target, p, bn, bsfx);
+                                                       if (esfx === "%") {
+                                                               bn /= _convertToPixels(target, p, 100, "%") / 100;
+                                                               if (bn > 100) { //extremely rare
+                                                                       bn = 100;
+                                                               }
+                                                               if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens.
+                                                                       bs = bn + "%";
+                                                               }
+
+                                                       } else if (esfx === "em") {
+                                                               bn /= _convertToPixels(target, p, 1, "em");
+
+                                                       //otherwise convert to pixels.
+                                                       } else {
+                                                               en = _convertToPixels(target, p, en, esfx);
+                                                               esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
+                                                       }
+                                                       if (rel) if (en || en === 0) {
+                                                               es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
+                                                       }
+                                               }
+
+                                               if (rel) {
+                                                       en += bn;
+                                               }
+
+                                               if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly.
+                                                       pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
+                                                       pt.xs0 = esfx;
+                                                       //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
+                                               } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
+                                                       _log("invalid " + p + " tween value: " + vars[p]);
+                                               } else {
+                                                       pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
+                                                       pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween.
+                                                       //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
+                                               }
+                                       }
+                               }
+                               if (plugin) if (pt && !pt.plugin) {
+                                       pt.plugin = plugin;
+                               }
+                       }
+                       return pt;
+               };
+
+
+               //gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
+               p.setRatio = function(v) {
+                       var pt = this._firstPT,
+                               min = 0.000001,
+                               val, str, i;
+
+                       //at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards).
+                       if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
+                               while (pt) {
+                                       if (pt.type !== 2) {
+                                               pt.t[pt.p] = pt.e;
+                                       } else {
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+
+                       } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
+                               while (pt) {
+                                       val = pt.c * v + pt.s;
+                                       if (pt.r) {
+                                               val = (val > 0) ? (val + 0.5) | 0 : (val - 0.5) | 0;
+                                       } else if (val < min) if (val > -min) {
+                                               val = 0;
+                                       }
+                                       if (!pt.type) {
+                                               pt.t[pt.p] = val + pt.xs0;
+                                       } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
+                                               i = pt.l;
+                                               if (i === 2) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
+                                               } else if (i === 3) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
+                                               } else if (i === 4) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
+                                               } else if (i === 5) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5;
+                                               } else {
+                                                       str = pt.xs0 + val + pt.xs1;
+                                                       for (i = 1; i < pt.l; i++) {
+                                                               str += pt["xn"+i] + pt["xs"+(i+1)];
+                                                       }
+                                                       pt.t[pt.p] = str;
+                                               }
+
+                                       } else if (pt.type === -1) { //non-tweening value
+                                               pt.t[pt.p] = pt.xs0;
+
+                                       } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+
+                       //if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever).
+                       } else {
+                               while (pt) {
+                                       if (pt.type !== 2) {
+                                               pt.t[pt.p] = pt.b;
+                                       } else {
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+                       }
+               };
+
+               /**
+                * @private
+                * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
+                * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
+                * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
+                * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
+                * doesn't have any transform-related properties of its own. You can call this method as many times as you
+                * want and it won't create duplicate CSSPropTweens.
+                *
+                * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
+                */
+               p._enableTransforms = function(threeD) {
+                       this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
+                       this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
+               };
+
+               /** @private **/
+               p._linkCSSP = function(pt, next, prev, remove) {
+                       if (pt) {
+                               if (next) {
+                                       next._prev = pt;
+                               }
+                               if (pt._next) {
+                                       pt._next._prev = pt._prev;
+                               }
+                               if (prev) {
+                                       prev._next = pt;
+                               } else if (!remove && this._firstPT === null) {
+                                       this._firstPT = pt;
+                               }
+                               if (pt._prev) {
+                                       pt._prev._next = pt._next;
+                               } else if (this._firstPT === pt) {
+                                       this._firstPT = pt._next;
+                               }
+                               pt._next = next;
+                               pt._prev = prev;
+                       }
+                       return pt;
+               };
+
+               //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
+               p._kill = function(lookup) {
+                       var copy = lookup,
+                               pt, p, xfirst;
+                       if (lookup.autoAlpha || lookup.alpha) {
+                               copy = {};
+                               for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
+                                       copy[p] = lookup[p];
+                               }
+                               copy.opacity = 1;
+                               if (copy.autoAlpha) {
+                                       copy.visibility = 1;
+                               }
+                       }
+                       if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst".
+                               xfirst = pt.xfirst;
+                               if (xfirst && xfirst._prev) {
+                                       this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
+                               } else if (xfirst === this._firstPT) {
+                                       this._firstPT = pt._next;
+                               }
+                               if (pt._next) {
+                                       this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
+                               }
+                               this._classNamePT = null;
+                       }
+                       return TweenPlugin.prototype._kill.call(this, copy);
+               };
+
+
+
+
+               //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
+               var _getChildStyles = function(e, props, targets) {
+                               var children, i, child, type;
+                               if (e.slice) {
+                                       i = e.length;
+                                       while (--i > -1) {
+                                               _getChildStyles(e[i], props, targets);
+                                       }
+                                       return;
+                               }
+                               children = e.childNodes;
+                               i = children.length;
+                               while (--i > -1) {
+                                       child = children[i];
+                                       type = child.type;
+                                       if (child.style) {
+                                               props.push(_getAllStyles(child));
+                                               if (targets) {
+                                                       targets.push(child);
+                                               }
+                                       }
+                                       if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
+                                               _getChildStyles(child, props, targets);
+                                       }
+                               }
+                       };
+
+               /**
+                * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
+                * and then compares the style properties of all the target's child elements at the tween's start and end, and
+                * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
+                * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
+                * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
+                * is because it creates entirely new tweens that may have completely different targets than the original tween,
+                * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
+                * and it would create other problems. For example:
+                *  - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted)
+                *  - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others.
+                *  - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed.
+                *
+                * @param {Object} target object to be tweened
+                * @param {number} Duration in seconds (or frames for frames-based tweens)
+                * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
+                * @return {Array} An array of TweenLite instances
+                */
+               CSSPlugin.cascadeTo = function(target, duration, vars) {
+                       var tween = TweenLite.to(target, duration, vars),
+                               results = [tween],
+                               b = [],
+                               e = [],
+                               targets = [],
+                               _reservedProps = TweenLite._internals.reservedProps,
+                               i, difs, p;
+                       target = tween._targets || tween.target;
+                       _getChildStyles(target, b, targets);
+                       tween.render(duration, true);
+                       _getChildStyles(target, e);
+                       tween.render(0, true);
+                       tween._enabled(true);
+                       i = targets.length;
+                       while (--i > -1) {
+                               difs = _cssDif(targets[i], b[i], e[i]);
+                               if (difs.firstMPT) {
+                                       difs = difs.difs;
+                                       for (p in vars) {
+                                               if (_reservedProps[p]) {
+                                                       difs[p] = vars[p];
+                                               }
+                                       }
+                                       results.push( TweenLite.to(targets[i], duration, difs) );
+                               }
+                       }
+                       return results;
+               };
+
+
+               TweenPlugin.activate([CSSPlugin]);
+               return CSSPlugin;
+
+       }, true);
+
+       
+       
+       
+       
+       
+       
+       
+       
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * RoundPropsPlugin
+ * ----------------------------------------------------------------
+ */
+       (function() {
+
+               var RoundPropsPlugin = window._gsDefine.plugin({
+                               propName: "roundProps",
+                               priority: -1,
+                               API: 2,
+
+                               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                               init: function(target, value, tween) {
+                                       this._tween = tween;
+                                       return true;
+                               }
+
+                       }),
+                       p = RoundPropsPlugin.prototype;
+
+               p._onInitAllProps = function() {
+                       var tween = this._tween,
+                               rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
+                               i = rp.length,
+                               lookup = {},
+                               rpt = tween._propLookup.roundProps,
+                               prop, pt, next;
+                       while (--i > -1) {
+                               lookup[rp[i]] = 1;
+                       }
+                       i = rp.length;
+                       while (--i > -1) {
+                               prop = rp[i];
+                               pt = tween._firstPT;
+                               while (pt) {
+                                       next = pt._next; //record here, because it may get removed
+                                       if (pt.pg) {
+                                               pt.t._roundProps(lookup, true);
+                                       } else if (pt.n === prop) {
+                                               this._add(pt.t, prop, pt.s, pt.c);
+                                               //remove from linked list
+                                               if (next) {
+                                                       next._prev = pt._prev;
+                                               }
+                                               if (pt._prev) {
+                                                       pt._prev._next = next;
+                                               } else if (tween._firstPT === pt) {
+                                                       tween._firstPT = next;
+                                               }
+                                               pt._next = pt._prev = null;
+                                               tween._propLookup[prop] = rpt;
+                                       }
+                                       pt = next;
+                               }
+                       }
+                       return false;
+               };
+
+               p._add = function(target, p, s, c) {
+                       this._addTween(target, p, s, s + c, p, true);
+                       this._overwriteProps.push(p);
+               };
+
+       }());
+
+
+
+
+
+
+
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * AttrPlugin
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine.plugin({
+               propName: "attr",
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       var p;
+                       if (typeof(target.setAttribute) !== "function") {
+                               return false;
+                       }
+                       this._target = target;
+                       this._proxy = {};
+                       for (p in value) {
+                               this._addTween(this._proxy, p, parseFloat(target.getAttribute(p)), value[p], p);
+                               this._overwriteProps.push(p);
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(ratio) {
+                       this._super.setRatio.call(this, ratio);
+                       var props = this._overwriteProps,
+                               i = props.length,
+                               p;
+                       while (--i > -1) {
+                               p = props[i];
+                               this._target.setAttribute(p, this._proxy[p] + "");
+                       }
+               }
+
+       });
+
+
+
+
+
+
+
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * DirectionalRotationPlugin
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine.plugin({
+               propName: "directionalRotation",
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       if (typeof(value) !== "object") {
+                               value = {rotation:value};
+                       }
+                       this.finals = {};
+                       var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
+                               min = 0.000001,
+                               p, v, start, end, dif, split;
+                       for (p in value) {
+                               if (p !== "useRadians") {
+                                       split = (value[p] + "").split("_");
+                                       v = split[0];
+                                       start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
+                                       end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
+                                       dif = end - start;
+                                       if (split.length) {
+                                               v = split.join("_");
+                                               if (v.indexOf("short") !== -1) {
+                                                       dif = dif % cap;
+                                                       if (dif !== dif % (cap / 2)) {
+                                                               dif = (dif < 0) ? dif + cap : dif - cap;
+                                                       }
+                                               }
+                                               if (v.indexOf("_cw") !== -1 && dif < 0) {
+                                                       dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               } else if (v.indexOf("ccw") !== -1 && dif > 0) {
+                                                       dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               }
+                                       }
+                                       if (dif > min || dif < -min) {
+                                               this._addTween(target, p, start, start + dif, p);
+                                               this._overwriteProps.push(p);
+                                       }
+                               }
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(ratio) {
+                       var pt;
+                       if (ratio !== 1) {
+                               this._super.setRatio.call(this, ratio);
+                       } else {
+                               pt = this._firstPT;
+                               while (pt) {
+                                       if (pt.f) {
+                                               pt.t[pt.p](this.finals[pt.p]);
+                                       } else {
+                                               pt.t[pt.p] = this.finals[pt.p];
+                                       }
+                                       pt = pt._next;
+                               }
+                       }
+               }
+
+       })._autoCSS = true;
+
+
+
+
+
+
+
+       
+       
+       
+       
+/*
+ * ----------------------------------------------------------------
+ * EasePack
+ * ----------------------------------------------------------------
+ */
+       window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
+               
+               var w = (window.GreenSockGlobals || window),
+                       gs = w.com.greensock,
+                       _2PI = Math.PI * 2,
+                       _HALF_PI = Math.PI / 2,
+                       _class = gs._class,
+                       _create = function(n, f) {
+                               var C = _class("easing." + n, function(){}, true),
+                                       p = C.prototype = new Ease();
+                               p.constructor = C;
+                               p.getRatio = f;
+                               return C;
+                       },
+                       _easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist.
+                       _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
+                               var C = _class("easing."+name, {
+                                       easeOut:new EaseOut(),
+                                       easeIn:new EaseIn(),
+                                       easeInOut:new EaseInOut()
+                               }, true);
+                               _easeReg(C, name);
+                               return C;
+                       },
+                       EasePoint = function(time, value, next) {
+                               this.t = time;
+                               this.v = value;
+                               if (next) {
+                                       this.next = next;
+                                       next.prev = this;
+                                       this.c = next.v - value;
+                                       this.gap = next.t - time;
+                               }
+                       },
+
+                       //Back
+                       _createBack = function(n, f) {
+                               var C = _class("easing." + n, function(overshoot) {
+                                               this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
+                                               this._p2 = this._p1 * 1.525;
+                                       }, true),
+                                       p = C.prototype = new Ease();
+                               p.constructor = C;
+                               p.getRatio = f;
+                               p.config = function(overshoot) {
+                                       return new C(overshoot);
+                               };
+                               return C;
+                       },
+
+                       Back = _wrap("Back",
+                               _createBack("BackOut", function(p) {
+                                       return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
+                               }),
+                               _createBack("BackIn", function(p) {
+                                       return p * p * ((this._p1 + 1) * p - this._p1);
+                               }),
+                               _createBack("BackInOut", function(p) {
+                                       return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2);
+                               })
+                       ),
+
+
+                       //SlowMo
+                       SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
+                               power = (power || power === 0) ? power : 0.7;
+                               if (linearRatio == null) {
+                                       linearRatio = 0.7;
+                               } else if (linearRatio > 1) {
+                                       linearRatio = 1;
+                               }
+                               this._p = (linearRatio !== 1) ? power : 0;
+                               this._p1 = (1 - linearRatio) / 2;
+                               this._p2 = linearRatio;
+                               this._p3 = this._p1 + this._p2;
+                               this._calcEnd = (yoyoMode === true);
+                       }, true),
+                       p = SlowMo.prototype = new Ease(),
+                       SteppedEase, RoughEase, _createElastic;
+
+               p.constructor = SlowMo;
+               p.getRatio = function(p) {
+                       var r = p + (0.5 - p) * this._p;
+                       if (p < this._p1) {
+                               return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
+                       } else if (p > this._p3) {
+                               return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
+                       }
+                       return this._calcEnd ? 1 : r;
+               };
+               SlowMo.ease = new SlowMo(0.7, 0.7);
+
+               p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
+                       return new SlowMo(linearRatio, power, yoyoMode);
+               };
+
+
+               //SteppedEase
+               SteppedEase = _class("easing.SteppedEase", function(steps) {
+                               steps = steps || 1;
+                               this._p1 = 1 / steps;
+                               this._p2 = steps + 1;
+                       }, true);
+               p = SteppedEase.prototype = new Ease();
+               p.constructor = SteppedEase;
+               p.getRatio = function(p) {
+                       if (p < 0) {
+                               p = 0;
+                       } else if (p >= 1) {
+                               p = 0.999999999;
+                       }
+                       return ((this._p2 * p) >> 0) * this._p1;
+               };
+               p.config = SteppedEase.config = function(steps) {
+                       return new SteppedEase(steps);
+               };
+
+
+               //RoughEase
+               RoughEase = _class("easing.RoughEase", function(vars) {
+                       vars = vars || {};
+                       var taper = vars.taper || "none",
+                               a = [],
+                               cnt = 0,
+                               points = (vars.points || 20) | 0,
+                               i = points,
+                               randomize = (vars.randomize !== false),
+                               clamp = (vars.clamp === true),
+                               template = (vars.template instanceof Ease) ? vars.template : null,
+                               strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
+                               x, y, bump, invX, obj, pnt;
+                       while (--i > -1) {
+                               x = randomize ? Math.random() : (1 / points) * i;
+                               y = template ? template.getRatio(x) : x;
+                               if (taper === "none") {
+                                       bump = strength;
+                               } else if (taper === "out") {
+                                       invX = 1 - x;
+                                       bump = invX * invX * strength;
+                               } else if (taper === "in") {
+                                       bump = x * x * strength;
+                               } else if (x < 0.5) {  //"both" (start)
+                                       invX = x * 2;
+                                       bump = invX * invX * 0.5 * strength;
+                               } else {                                //"both" (end)
+                                       invX = (1 - x) * 2;
+                                       bump = invX * invX * 0.5 * strength;
+                               }
+                               if (randomize) {
+                                       y += (Math.random() * bump) - (bump * 0.5);
+                               } else if (i % 2) {
+                                       y += bump * 0.5;
+                               } else {
+                                       y -= bump * 0.5;
+                               }
+                               if (clamp) {
+                                       if (y > 1) {
+                                               y = 1;
+                                       } else if (y < 0) {
+                                               y = 0;
+                                       }
+                               }
+                               a[cnt++] = {x:x, y:y};
+                       }
+                       a.sort(function(a, b) {
+                               return a.x - b.x;
+                       });
+
+                       pnt = new EasePoint(1, 1, null);
+                       i = points;
+                       while (--i > -1) {
+                               obj = a[i];
+                               pnt = new EasePoint(obj.x, obj.y, pnt);
+                       }
+
+                       this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
+               }, true);
+               p = RoughEase.prototype = new Ease();
+               p.constructor = RoughEase;
+               p.getRatio = function(p) {
+                       var pnt = this._prev;
+                       if (p > pnt.t) {
+                               while (pnt.next && p >= pnt.t) {
+                                       pnt = pnt.next;
+                               }
+                               pnt = pnt.prev;
+                       } else {
+                               while (pnt.prev && p <= pnt.t) {
+                                       pnt = pnt.prev;
+                               }
+                       }
+                       this._prev = pnt;
+                       return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
+               };
+               p.config = function(vars) {
+                       return new RoughEase(vars);
+               };
+               RoughEase.ease = new RoughEase();
+
+
+               //Bounce
+               _wrap("Bounce",
+                       _create("BounceOut", function(p) {
+                               if (p < 1 / 2.75) {
+                                       return 7.5625 * p * p;
+                               } else if (p < 2 / 2.75) {
+                                       return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
+                               } else if (p < 2.5 / 2.75) {
+                                       return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
+                               }
+                               return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
+                       }),
+                       _create("BounceIn", function(p) {
+                               if ((p = 1 - p) < 1 / 2.75) {
+                                       return 1 - (7.5625 * p * p);
+                               } else if (p < 2 / 2.75) {
+                                       return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
+                               } else if (p < 2.5 / 2.75) {
+                                       return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
+                               }
+                               return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
+                       }),
+                       _create("BounceInOut", function(p) {
+                               var invert = (p < 0.5);
+                               if (invert) {
+                                       p = 1 - (p * 2);
+                               } else {
+                                       p = (p * 2) - 1;
+                               }
+                               if (p < 1 / 2.75) {
+                                       p = 7.5625 * p * p;
+                               } else if (p < 2 / 2.75) {
+                                       p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
+                               } else if (p < 2.5 / 2.75) {
+                                       p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
+                               } else {
+                                       p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
+                               }
+                               return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
+                       })
+               );
+
+
+               //CIRC
+               _wrap("Circ",
+                       _create("CircOut", function(p) {
+                               return Math.sqrt(1 - (p = p - 1) * p);
+                       }),
+                       _create("CircIn", function(p) {
+                               return -(Math.sqrt(1 - (p * p)) - 1);
+                       }),
+                       _create("CircInOut", function(p) {
+                               return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
+                       })
+               );
+
+
+               //Elastic
+               _createElastic = function(n, f, def) {
+                       var C = _class("easing." + n, function(amplitude, period) {
+                                       this._p1 = amplitude || 1;
+                                       this._p2 = period || def;
+                                       this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
+                               }, true),
+                               p = C.prototype = new Ease();
+                       p.constructor = C;
+                       p.getRatio = f;
+                       p.config = function(amplitude, period) {
+                               return new C(amplitude, period);
+                       };
+                       return C;
+               };
+               _wrap("Elastic",
+                       _createElastic("ElasticOut", function(p) {
+                               return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
+                       }, 0.3),
+                       _createElastic("ElasticIn", function(p) {
+                               return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
+                       }, 0.3),
+                       _createElastic("ElasticInOut", function(p) {
+                               return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ) *0.5 + 1;
+                       }, 0.45)
+               );
+
+
+               //Expo
+               _wrap("Expo",
+                       _create("ExpoOut", function(p) {
+                               return 1 - Math.pow(2, -10 * p);
+                       }),
+                       _create("ExpoIn", function(p) {
+                               return Math.pow(2, 10 * (p - 1)) - 0.001;
+                       }),
+                       _create("ExpoInOut", function(p) {
+                               return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
+                       })
+               );
+
+
+               //Sine
+               _wrap("Sine",
+                       _create("SineOut", function(p) {
+                               return Math.sin(p * _HALF_PI);
+                       }),
+                       _create("SineIn", function(p) {
+                               return -Math.cos(p * _HALF_PI) + 1;
+                       }),
+                       _create("SineInOut", function(p) {
+                               return -0.5 * (Math.cos(Math.PI * p) - 1);
+                       })
+               );
+
+               _class("easing.EaseLookup", {
+                               find:function(s) {
+                                       return Ease.map[s];
+                               }
+                       }, true);
+
+               //register the non-standard eases
+               _easeReg(w.SlowMo, "SlowMo", "ease,");
+               _easeReg(RoughEase, "RoughEase", "ease,");
+               _easeReg(SteppedEase, "SteppedEase", "ease,");
+
+               return Back;
+               
+       }, true);
+
+
+}); 
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc.
+ * ----------------------------------------------------------------
+ */
+(function(window) {
+
+               "use strict";
+               var _globals = window.GreenSockGlobals || window,
+                       _namespace = function(ns) {
+                               var a = ns.split("."),
+                                       p = _globals, i;
+                               for (i = 0; i < a.length; i++) {
+                                       p[a[i]] = p = p[a[i]] || {};
+                               }
+                               return p;
+                       },
+                       gs = _namespace("com.greensock"),
+                       _slice = [].slice,
+                       _emptyFunc = function() {},
+                       a, i, p, _ticker, _tickerActive,
+                       _defLookup = {},
+
+                       /**
+                        * @constructor
+                        * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
+                        * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
+                        * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
+                        * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
+                        *
+                        * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
+                        * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere,
+                        * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
+                        * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
+                        * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
+                        * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could
+                        * sandbox the banner one like:
+                        *
+                        * <script>
+                        *     var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever.
+                        * </script>
+                        * <script src="js/greensock/v1.7/TweenMax.js"></script>
+                        * <script>
+                        *     window.GreenSockGlobals = null; //reset it back to null so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...)
+                        * </script>
+                        * <script src="js/greensock/v1.6/TweenMax.js"></script>
+                        * <script>
+                        *     gs.TweenLite.to(...); //would use v1.7
+                        *     TweenLite.to(...); //would use v1.6
+                        * </script>
+                        *
+                        * @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back".
+                        * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
+                        * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
+                        * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
+                        */
+                       Definition = function(ns, dependencies, func, global) {
+                               this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
+                               _defLookup[ns] = this;
+                               this.gsClass = null;
+                               this.func = func;
+                               var _classes = [];
+                               this.check = function(init) {
+                                       var i = dependencies.length,
+                                               missing = i,
+                                               cur, a, n, cl;
+                                       while (--i > -1) {
+                                               if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
+                                                       _classes[i] = cur.gsClass;
+                                                       missing--;
+                                               } else if (init) {
+                                                       cur.sc.push(this);
+                                               }
+                                       }
+                                       if (missing === 0 && func) {
+                                               a = ("com.greensock." + ns).split(".");
+                                               n = a.pop();
+                                               cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
+
+                                               //exports to multiple environments
+                                               if (global) {
+                                                       _globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.)
+                                                       if (typeof(define) === "function" && define.amd){ //AMD
+                                                               define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").join("/"), [], function() { return cl; });
+                                                       } else if (typeof(module) !== "undefined" && module.exports){ //node
+                                                               module.exports = cl;
+                                                       }
+                                               }
+                                               for (i = 0; i < this.sc.length; i++) {
+                                                       this.sc[i].check();
+                                               }
+                                       }
+                               };
+                               this.check(true);
+                       },
+
+                       //used to create Definition instances (which basically registers a class that has dependencies).
+                       _gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
+                               return new Definition(ns, dependencies, func, global);
+                       },
+
+                       //a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class).
+                       _class = gs._class = function(ns, func, global) {
+                               func = func || function() {};
+                               _gsDefine(ns, [], function(){ return func; }, global);
+                               return func;
+                       };
+
+               _gsDefine.globals = _globals;
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * Ease
+ * ----------------------------------------------------------------
+ */
+               var _baseParams = [0, 0, 1, 1],
+                       _blankArray = [],
+                       Ease = _class("easing.Ease", function(func, extraParams, type, power) {
+                               this._func = func;
+                               this._type = type || 0;
+                               this._power = power || 0;
+                               this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
+                       }, true),
+                       _easeMap = Ease.map = {},
+                       _easeReg = Ease.register = function(ease, names, types, create) {
+                               var na = names.split(","),
+                                       i = na.length,
+                                       ta = (types || "easeIn,easeOut,easeInOut").split(","),
+                                       e, name, j, type;
+                               while (--i > -1) {
+                                       name = na[i];
+                                       e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
+                                       j = ta.length;
+                                       while (--j > -1) {
+                                               type = ta[j];
+                                               _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
+                                       }
+                               }
+                       };
+
+               p = Ease.prototype;
+               p._calcEnd = false;
+               p.getRatio = function(p) {
+                       if (this._func) {
+                               this._params[0] = p;
+                               return this._func.apply(null, this._params);
+                       }
+                       var t = this._type,
+                               pw = this._power,
+                               r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
+                       if (pw === 1) {
+                               r *= r;
+                       } else if (pw === 2) {
+                               r *= r * r;
+                       } else if (pw === 3) {
+                               r *= r * r * r;
+                       } else if (pw === 4) {
+                               r *= r * r * r * r;
+                       }
+                       return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
+               };
+
+               //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
+               a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
+               i = a.length;
+               while (--i > -1) {
+                       p = a[i]+",Power"+i;
+                       _easeReg(new Ease(null,null,1,i), p, "easeOut", true);
+                       _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
+                       _easeReg(new Ease(null,null,3,i), p, "easeInOut");
+               }
+               _easeMap.linear = gs.easing.Linear.easeIn;
+               _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
+
+
+/*
+ * ----------------------------------------------------------------
+ * EventDispatcher
+ * ----------------------------------------------------------------
+ */
+               var EventDispatcher = _class("events.EventDispatcher", function(target) {
+                       this._listeners = {};
+                       this._eventTarget = target || this;
+               });
+               p = EventDispatcher.prototype;
+
+               p.addEventListener = function(type, callback, scope, useParam, priority) {
+                       priority = priority || 0;
+                       var list = this._listeners[type],
+                               index = 0,
+                               listener, i;
+                       if (list == null) {
+                               this._listeners[type] = list = [];
+                       }
+                       i = list.length;
+                       while (--i > -1) {
+                               listener = list[i];
+                               if (listener.c === callback && listener.s === scope) {
+                                       list.splice(i, 1);
+                               } else if (index === 0 && listener.pr < priority) {
+                                       index = i + 1;
+                               }
+                       }
+                       list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
+                       if (this === _ticker && !_tickerActive) {
+                               _ticker.wake();
+                       }
+               };
+
+               p.removeEventListener = function(type, callback) {
+                       var list = this._listeners[type], i;
+                       if (list) {
+                               i = list.length;
+                               while (--i > -1) {
+                                       if (list[i].c === callback) {
+                                               list.splice(i, 1);
+                                               return;
+                                       }
+                               }
+                       }
+               };
+
+               p.dispatchEvent = function(type) {
+                       var list = this._listeners[type],
+                               i, t, listener;
+                       if (list) {
+                               i = list.length;
+                               t = this._eventTarget;
+                               while (--i > -1) {
+                                       listener = list[i];
+                                       if (listener.up) {
+                                               listener.c.call(listener.s || t, {type:type, target:t});
+                                       } else {
+                                               listener.c.call(listener.s || t);
+                                       }
+                               }
+                       }
+               };
+
+
+/*
+ * ----------------------------------------------------------------
+ * Ticker
+ * ----------------------------------------------------------------
+ */
+               var _reqAnimFrame = window.requestAnimationFrame,
+                       _cancelAnimFrame = window.cancelAnimationFrame,
+                       _getTime = Date.now || function() {return new Date().getTime();};
+
+               //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
+               a = ["ms","moz","webkit","o"];
+               i = a.length;
+               while (--i > -1 && !_reqAnimFrame) {
+                       _reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
+                       _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
+               }
+
+               _class("Ticker", function(fps, useRAF) {
+                       var _self = this,
+                               _startTime = _getTime(),
+                               _useRAF = (useRAF !== false && _reqAnimFrame),
+                               _fps, _req, _id, _gap, _nextTime,
+                               _tick = function(manual) {
+                                       _self.time = (_getTime() - _startTime) / 1000;
+                                       var id = _id,
+                                               overlap = _self.time - _nextTime;
+                                       if (!_fps || overlap > 0 || manual === true) {
+                                               _self.frame++;
+                                               _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
+                                               _self.dispatchEvent("tick");
+                                       }
+                                       if (manual !== true && id === _id) { //make sure the ids match in case the "tick" dispatch triggered something that caused the ticker to shut down or change _useRAF or something like that.
+                                               _id = _req(_tick);
+                                       }
+                               };
+
+                       EventDispatcher.call(_self);
+                       this.time = this.frame = 0;
+                       this.tick = function() {
+                               _tick(true);
+                       };
+
+                       this.sleep = function() {
+                               if (_id == null) {
+                                       return;
+                               }
+                               if (!_useRAF || !_cancelAnimFrame) {
+                                       clearTimeout(_id);
+                               } else {
+                                       _cancelAnimFrame(_id);
+                               }
+                               _req = _emptyFunc;
+                               _id = null;
+                               if (_self === _ticker) {
+                                       _tickerActive = false;
+                               }
+                       };
+
+                       this.wake = function() {
+                               if (_id !== null) {
+                                       _self.sleep();
+                               }
+                               _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
+                               if (_self === _ticker) {
+                                       _tickerActive = true;
+                               }
+                               _tick(2);
+                       };
+
+                       this.fps = function(value) {
+                               if (!arguments.length) {
+                                       return _fps;
+                               }
+                               _fps = value;
+                               _gap = 1 / (_fps || 60);
+                               _nextTime = this.time + _gap;
+                               _self.wake();
+                       };
+
+                       this.useRAF = function(value) {
+                               if (!arguments.length) {
+                                       return _useRAF;
+                               }
+                               _self.sleep();
+                               _useRAF = value;
+                               _self.fps(_fps);
+                       };
+                       _self.fps(fps);
+
+                       //a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition.
+                       setTimeout(function() {
+                               if (_useRAF && (!_id || _self.frame < 5)) {
+                                       _self.useRAF(false);
+                               }
+                       }, 1500);
+               });
+
+               p = gs.Ticker.prototype = new gs.events.EventDispatcher();
+               p.constructor = gs.Ticker;
+
+
+/*
+ * ----------------------------------------------------------------
+ * Animation
+ * ----------------------------------------------------------------
+ */
+               var Animation = _class("core.Animation", function(duration, vars) {
+                               this.vars = vars || {};
+                               this._duration = this._totalDuration = duration || 0;
+                               this._delay = Number(this.vars.delay) || 0;
+                               this._timeScale = 1;
+                               this._active = (this.vars.immediateRender === true);
+                               this.data = this.vars.data;
+                               this._reversed = (this.vars.reversed === true);
+
+                               if (!_rootTimeline) {
+                                       return;
+                               }
+                               if (!_tickerActive) {
+                                       _ticker.wake();
+                               }
+
+                               var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
+                               tl.add(this, tl._time);
+
+                               if (this.vars.paused) {
+                                       this.paused(true);
+                               }
+                       });
+
+               _ticker = Animation.ticker = new gs.Ticker();
+               p = Animation.prototype;
+               p._dirty = p._gc = p._initted = p._paused = false;
+               p._totalTime = p._time = 0;
+               p._rawPrevTime = -1;
+               p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
+               p._paused = false;
+
+               p.play = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(from, suppressEvents);
+                       }
+                       return this.reversed(false).paused(false);
+               };
+
+               p.pause = function(atTime, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(atTime, suppressEvents);
+                       }
+                       return this.paused(true);
+               };
+
+               p.resume = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek(from, suppressEvents);
+                       }
+                       return this.paused(false);
+               };
+
+               p.seek = function(time, suppressEvents) {
+                       return this.totalTime(Number(time), suppressEvents !== false);
+               };
+
+               p.restart = function(includeDelay, suppressEvents) {
+                       return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
+               };
+
+               p.reverse = function(from, suppressEvents) {
+                       if (arguments.length) {
+                               this.seek((from || this.totalDuration()), suppressEvents);
+                       }
+                       return this.reversed(true).paused(false);
+               };
+
+               p.render = function() {
+
+               };
+
+               p.invalidate = function() {
+                       return this;
+               };
+
+               p._enabled = function (enabled, ignoreTimeline) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       this._gc = !enabled;
+                       this._active = (enabled && !this._paused && this._totalTime > 0 && this._totalTime < this._totalDuration);
+                       if (ignoreTimeline !== true) {
+                               if (enabled && !this.timeline) {
+                                       this._timeline.add(this, this._startTime - this._delay);
+                               } else if (!enabled && this.timeline) {
+                                       this._timeline._remove(this, true);
+                               }
+                       }
+                       return false;
+               };
+
+
+               p._kill = function(vars, target) {
+                       return this._enabled(false, false);
+               };
+
+               p.kill = function(vars, target) {
+                       this._kill(vars, target);
+                       return this;
+               };
+
+               p._uncache = function(includeSelf) {
+                       var tween = includeSelf ? this : this.timeline;
+                       while (tween) {
+                               tween._dirty = true;
+                               tween = tween.timeline;
+                       }
+                       return this;
+               };
+
+//----Animation getters/setters --------------------------------------------------------
+
+               p.eventCallback = function(type, callback, params, scope) {
+                       if (type == null) {
+                               return null;
+                       } else if (type.substr(0,2) === "on") {
+                               var v = this.vars,
+                                       i;
+                               if (arguments.length === 1) {
+                                       return v[type];
+                               }
+                               if (callback == null) {
+                                       delete v[type];
+                               } else {
+                                       v[type] = callback;
+                                       v[type + "Params"] = params;
+                                       v[type + "Scope"] = scope;
+                                       if (params) {
+                                               i = params.length;
+                                               while (--i > -1) {
+                                                       if (params[i] === "{self}") {
+                                                               params = v[type + "Params"] = params.concat(); //copying the array avoids situations where the same array is passed to multiple tweens/timelines and {self} doesn't correctly point to each individual instance.
+                                                               params[i] = this;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (type === "onUpdate") {
+                                       this._onUpdate = callback;
+                               }
+                       }
+                       return this;
+               };
+
+               p.delay = function(value) {
+                       if (!arguments.length) {
+                               return this._delay;
+                       }
+                       if (this._timeline.smoothChildTiming) {
+                               this.startTime( this._startTime + value - this._delay );
+                       }
+                       this._delay = value;
+                       return this;
+               };
+
+               p.duration = function(value) {
+                       if (!arguments.length) {
+                               this._dirty = false;
+                               return this._duration;
+                       }
+                       this._duration = this._totalDuration = value;
+                       this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
+                       if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
+                               this.totalTime(this._totalTime * (value / this._duration), true);
+                       }
+                       return this;
+               };
+
+               p.totalDuration = function(value) {
+                       this._dirty = false;
+                       return (!arguments.length) ? this._totalDuration : this.duration(value);
+               };
+
+               p.time = function(value, suppressEvents) {
+                       if (!arguments.length) {
+                               return this._time;
+                       }
+                       if (this._dirty) {
+                               this.totalDuration();
+                       }
+                       return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
+               };
+
+               p.totalTime = function(time, suppressEvents, uncapped) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       if (!arguments.length) {
+                               return this._totalTime;
+                       }
+                       if (this._timeline) {
+                               if (time < 0 && !uncapped) {
+                                       time += this.totalDuration();
+                               }
+                               if (this._timeline.smoothChildTiming) {
+                                       if (this._dirty) {
+                                               this.totalDuration();
+                                       }
+                                       var totalDuration = this._totalDuration,
+                                               tl = this._timeline;
+                                       if (time > totalDuration && !uncapped) {
+                                               time = totalDuration;
+                                       }
+                                       this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
+                                       if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the anscestors as dirty too, so skip the function call here.
+                                               this._uncache(false);
+                                       }
+                                       if (!tl._active) {
+                                               //in case any of the anscestors had completed but should now be enabled...
+                                               while (tl._timeline) {
+                                                       tl.totalTime(tl._totalTime, true);
+                                                       tl = tl._timeline;
+                                               }
+                                       }
+                               }
+                               if (this._gc) {
+                                       this._enabled(true, false);
+                               }
+                               if (this._totalTime !== time) {
+                                       this.render(time, suppressEvents, false);
+                               }
+                       }
+                       return this;
+               };
+
+               p.startTime = function(value) {
+                       if (!arguments.length) {
+                               return this._startTime;
+                       }
+                       if (value !== this._startTime) {
+                               this._startTime = value;
+                               if (this.timeline) if (this.timeline._sortChildren) {
+                                       this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
+                               }
+                       }
+                       return this;
+               };
+
+               p.timeScale = function(value) {
+                       if (!arguments.length) {
+                               return this._timeScale;
+                       }
+                       value = value || 0.000001; //can't allow zero because it'll throw the math off
+                       if (this._timeline && this._timeline.smoothChildTiming) {
+                               var pauseTime = this._pauseTime,
+                                       t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
+                               this._startTime = t - ((t - this._startTime) * this._timeScale / value);
+                       }
+                       this._timeScale = value;
+                       return this._uncache(false);
+               };
+
+               p.reversed = function(value) {
+                       if (!arguments.length) {
+                               return this._reversed;
+                       }
+                       if (value != this._reversed) {
+                               this._reversed = value;
+                               this.totalTime(this._totalTime, true);
+                       }
+                       return this;
+               };
+
+               p.paused = function(value) {
+                       if (!arguments.length) {
+                               return this._paused;
+                       }
+                       if (value != this._paused) if (this._timeline) {
+                               if (!_tickerActive && !value) {
+                                       _ticker.wake();
+                               }
+                               var raw = this._timeline.rawTime(),
+                                       elapsed = raw - this._pauseTime;
+                               if (!value && this._timeline.smoothChildTiming) {
+                                       this._startTime += elapsed;
+                                       this._uncache(false);
+                               }
+                               this._pauseTime = value ? raw : null;
+                               this._paused = value;
+                               this._active = (!value && this._totalTime > 0 && this._totalTime < this._totalDuration);
+                               if (!value && elapsed !== 0 && this._duration !== 0) {
+                                       this.render(this._totalTime, true, true);
+                               }
+                       }
+                       if (this._gc && !value) {
+                               this._enabled(true, false);
+                       }
+                       return this;
+               };
+
+
+/*
+ * ----------------------------------------------------------------
+ * SimpleTimeline
+ * ----------------------------------------------------------------
+ */
+               var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
+                       Animation.call(this, 0, vars);
+                       this.autoRemoveChildren = this.smoothChildTiming = true;
+               });
+
+               p = SimpleTimeline.prototype = new Animation();
+               p.constructor = SimpleTimeline;
+               p.kill()._gc = false;
+               p._first = p._last = null;
+               p._sortChildren = false;
+
+               p.add = p.insert = function(child, position, align, stagger) {
+                       var prevTween, st;
+                       child._startTime = Number(position || 0) + child._delay;
+                       if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order).
+                               child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
+                       }
+                       if (child.timeline) {
+                               child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
+                       }
+                       child.timeline = child._timeline = this;
+                       if (child._gc) {
+                               child._enabled(true, true);
+                       }
+                       prevTween = this._last;
+                       if (this._sortChildren) {
+                               st = child._startTime;
+                               while (prevTween && prevTween._startTime > st) {
+                                       prevTween = prevTween._prev;
+                               }
+                       }
+                       if (prevTween) {
+                               child._next = prevTween._next;
+                               prevTween._next = child;
+                       } else {
+                               child._next = this._first;
+                               this._first = child;
+                       }
+                       if (child._next) {
+                               child._next._prev = child;
+                       } else {
+                               this._last = child;
+                       }
+                       child._prev = prevTween;
+                       if (this._timeline) {
+                               this._uncache(true);
+                       }
+                       return this;
+               };
+
+               p._remove = function(tween, skipDisable) {
+                       if (tween.timeline === this) {
+                               if (!skipDisable) {
+                                       tween._enabled(false, true);
+                               }
+                               tween.timeline = null;
+
+                               if (tween._prev) {
+                                       tween._prev._next = tween._next;
+                               } else if (this._first === tween) {
+                                       this._first = tween._next;
+                               }
+                               if (tween._next) {
+                                       tween._next._prev = tween._prev;
+                               } else if (this._last === tween) {
+                                       this._last = tween._prev;
+                               }
+
+                               if (this._timeline) {
+                                       this._uncache(true);
+                               }
+                       }
+                       return this;
+               };
+
+               p.render = function(time, suppressEvents, force) {
+                       var tween = this._first,
+                               next;
+                       this._totalTime = this._time = this._rawPrevTime = time;
+                       while (tween) {
+                               next = tween._next; //record it here because the value could change after rendering...
+                               if (tween._active || (time >= tween._startTime && !tween._paused)) {
+                                       if (!tween._reversed) {
+                                               tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
+                                       } else {
+                                               tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
+                                       }
+                               }
+                               tween = next;
+                       }
+               };
+
+               p.rawTime = function() {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       return this._totalTime;
+               };
+
+
+/*
+ * ----------------------------------------------------------------
+ * TweenLite
+ * ----------------------------------------------------------------
+ */
+               var TweenLite = _class("TweenLite", function(target, duration, vars) {
+                               Animation.call(this, duration, vars);
+
+                               if (target == null) {
+                                       throw "Cannot tween a null target.";
+                               }
+
+                               this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
+
+                               var isSelector = (target.jquery || (target.length && target[0] && target[0].nodeType && target[0].style && !target.nodeType)),
+                                       overwrite = this.vars.overwrite,
+                                       i, targ, targets;
+
+                               this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
+
+                               if ((isSelector || target instanceof Array) && typeof(target[0]) !== "number") {
+                                       this._targets = targets = _slice.call(target, 0);
+                                       this._propLookup = [];
+                                       this._siblings = [];
+                                       for (i = 0; i < targets.length; i++) {
+                                               targ = targets[i];
+                                               if (!targ) {
+                                                       targets.splice(i--, 1);
+                                                       continue;
+                                               } else if (typeof(targ) === "string") {
+                                                       targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
+                                                       if (typeof(targ) === "string") {
+                                                               targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
+                                                       }
+                                                       continue;
+                                               } else if (targ.length && targ[0] && targ[0].nodeType && targ[0].style && !targ.nodeType) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself.
+                                                       targets.splice(i--, 1);
+                                                       this._targets = targets = targets.concat(_slice.call(targ, 0));
+                                                       continue;
+                                               }
+                                               this._siblings[i] = _register(targ, this, false);
+                                               if (overwrite === 1) if (this._siblings[i].length > 1) {
+                                                       _applyOverwrite(targ, this, null, 1, this._siblings[i]);
+                                               }
+                                       }
+
+                               } else {
+                                       this._propLookup = {};
+                                       this._siblings = _register(target, this, false);
+                                       if (overwrite === 1) if (this._siblings.length > 1) {
+                                               _applyOverwrite(target, this, null, 1, this._siblings);
+                                       }
+                               }
+                               if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
+                                       this.render(-this._delay, false, true);
+                               }
+                       }, true),
+                       _isSelector = function(v) {
+                               return (v.length && v[0] && v[0].nodeType && v[0].style && !v.nodeType);
+                       },
+                       _autoCSS = function(vars, target) {
+                               var css = {},
+                                       p;
+                               for (p in vars) {
+                                       if (!_reservedProps[p] && (!(p in target) || p === "x" || p === "y" || p === "width" || p === "height" || p === "className") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties.
+                                               css[p] = vars[p];
+                                               delete vars[p];
+                                       }
+                               }
+                               vars.css = css;
+                       };
+
+               p = TweenLite.prototype = new Animation();
+               p.constructor = TweenLite;
+               p.kill()._gc = false;
+
+//----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
+
+               p.ratio = 0;
+               p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
+               p._notifyPluginsOfEnabled = false;
+
+               TweenLite.version = "1.9.8";
+               TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
+               TweenLite.defaultOverwrite = "auto";
+               TweenLite.ticker = _ticker;
+               TweenLite.autoSleep = true;
+               TweenLite.selector = window.$ || window.jQuery || function(e) { if (window.$) { TweenLite.selector = window.$; return window.$(e); } return window.document ? window.document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e) : e; };
+
+               var _internals = TweenLite._internals = {}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object.
+                       _plugins = TweenLite._plugins = {},
+                       _tweenLookup = TweenLite._tweenLookup = {},
+                       _tweenLookupNum = 0,
+                       _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1},
+                       _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
+                       _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
+                       _rootTimeline = Animation._rootTimeline = new SimpleTimeline();
+
+               _rootTimeline._startTime = _ticker.time;
+               _rootFramesTimeline._startTime = _ticker.frame;
+               _rootTimeline._active = _rootFramesTimeline._active = true;
+
+               Animation._updateRoot = function() {
+                               _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
+                               _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
+                               if (!(_ticker.frame % 120)) { //dump garbage every 120 frames...
+                                       var i, a, p;
+                                       for (p in _tweenLookup) {
+                                               a = _tweenLookup[p].tweens;
+                                               i = a.length;
+                                               while (--i > -1) {
+                                                       if (a[i]._gc) {
+                                                               a.splice(i, 1);
+                                                       }
+                                               }
+                                               if (a.length === 0) {
+                                                       delete _tweenLookup[p];
+                                               }
+                                       }
+                                       //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly
+                                       p = _rootTimeline._first;
+                                       if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
+                                               while (p && p._paused) {
+                                                       p = p._next;
+                                               }
+                                               if (!p) {
+                                                       _ticker.sleep();
+                                               }
+                                       }
+                               }
+                       };
+
+               _ticker.addEventListener("tick", Animation._updateRoot);
+
+               var _register = function(target, tween, scrub) {
+                               var id = target._gsTweenID, a, i;
+                               if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
+                                       _tweenLookup[id] = {target:target, tweens:[]};
+                               }
+                               if (tween) {
+                                       a = _tweenLookup[id].tweens;
+                                       a[(i = a.length)] = tween;
+                                       if (scrub) {
+                                               while (--i > -1) {
+                                                       if (a[i] === tween) {
+                                                               a.splice(i, 1);
+                                                       }
+                                               }
+                                       }
+                               }
+                               return _tweenLookup[id].tweens;
+                       },
+
+                       _applyOverwrite = function(target, tween, props, mode, siblings) {
+                               var i, changed, curTween, l;
+                               if (mode === 1 || mode >= 4) {
+                                       l = siblings.length;
+                                       for (i = 0; i < l; i++) {
+                                               if ((curTween = siblings[i]) !== tween) {
+                                                       if (!curTween._gc) if (curTween._enabled(false, false)) {
+                                                               changed = true;
+                                                       }
+                                               } else if (mode === 5) {
+                                                       break;
+                                               }
+                                       }
+                                       return changed;
+                               }
+                               //NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example)
+                               var startTime = tween._startTime + 0.0000000001,
+                                       overlaps = [],
+                                       oCount = 0,
+                                       zeroDur = (tween._duration === 0),
+                                       globalStart;
+                               i = siblings.length;
+                               while (--i > -1) {
+                                       if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
+                                               //ignore
+                                       } else if (curTween._timeline !== tween._timeline) {
+                                               globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
+                                               if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
+                                                       overlaps[oCount++] = curTween;
+                                               }
+                                       } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale + 0.0000000001 > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
+                                               overlaps[oCount++] = curTween;
+                                       }
+                               }
+
+                               i = oCount;
+                               while (--i > -1) {
+                                       curTween = overlaps[i];
+                                       if (mode === 2) if (curTween._kill(props, target)) {
+                                               changed = true;
+                                       }
+                                       if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
+                                               if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
+                                                       changed = true;
+                                               }
+                                       }
+                               }
+                               return changed;
+                       },
+
+                       _checkOverlap = function(tween, reference, zeroDur) {
+                               var tl = tween._timeline,
+                                       ts = tl._timeScale,
+                                       t = tween._startTime,
+                                       min = 0.0000000001; //we use this to protect from rounding errors.
+                               while (tl._timeline) {
+                                       t += tl._startTime;
+                                       ts *= tl._timeScale;
+                                       if (tl._paused) {
+                                               return -100;
+                                       }
+                                       tl = tl._timeline;
+                               }
+                               t /= ts;
+                               return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * min)) ? min : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + min) ? 0 : t - reference - min;
+                       };
+
+
+//---- TweenLite instance methods -----------------------------------------------------------------------------
+
+               p._init = function() {
+                       var v = this.vars,
+                               op = this._overwrittenProps,
+                               dur = this._duration,
+                               ease = v.ease,
+                               i, initPlugins, pt, p;
+                       if (v.startAt) {
+                               v.startAt.overwrite = 0;
+                               v.startAt.immediateRender = true;
+                               this._startAt = TweenLite.to(this.target, 0, v.startAt);
+                               if (v.immediateRender) {
+                                       this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()).
+                                       if (this._time === 0 && dur !== 0) {
+                                               return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.
+                                       }
+                               }
+                       } else if (v.runBackwards && v.immediateRender && dur !== 0) {
+                               //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)
+                               if (this._startAt) {
+                                       this._startAt.render(-1, true);
+                                       this._startAt = null;
+                               } else if (this._time === 0) {
+                                       pt = {};
+                                       for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through.
+                                               if (!_reservedProps[p] || p === "autoCSS") {
+                                                       pt[p] = v[p];
+                                               }
+                                       }
+                                       pt.overwrite = 0;
+                                       this._startAt = TweenLite.to(this.target, 0, pt);
+                                       return;
+                               }
+                       }
+                       if (!ease) {
+                               this._ease = TweenLite.defaultEase;
+                       } else if (ease instanceof Ease) {
+                               this._ease = (v.easeParams instanceof Array) ? ease.config.apply(ease, v.easeParams) : ease;
+                       } else {
+                               this._ease = (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
+                       }
+                       this._easeType = this._ease._type;
+                       this._easePower = this._ease._power;
+                       this._firstPT = null;
+
+                       if (this._targets) {
+                               i = this._targets.length;
+                               while (--i > -1) {
+                                       if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
+                                               initPlugins = true;
+                                       }
+                               }
+                       } else {
+                               initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
+                       }
+
+                       if (initPlugins) {
+                               TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
+                       }
+                       if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live.
+                               this._enabled(false, false);
+                       }
+                       if (v.runBackwards) {
+                               pt = this._firstPT;
+                               while (pt) {
+                                       pt.s += pt.c;
+                                       pt.c = -pt.c;
+                                       pt = pt._next;
+                               }
+                       }
+                       this._onUpdate = v.onUpdate;
+                       this._initted = true;
+               };
+
+               p._initProps = function(target, propLookup, siblings, overwrittenProps) {
+                       var p, i, initPlugins, plugin, a, pt, v;
+                       if (target == null) {
+                               return false;
+                       }
+                       if (!this.vars.css) if (target.style) if (target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity)
+                               _autoCSS(this.vars, target);
+                       }
+                       for (p in this.vars) {
+                               if (_reservedProps[p]) {
+                                       if (p === "onStartParams" || p === "onUpdateParams" || p === "onCompleteParams" || p === "onReverseCompleteParams" || p === "onRepeatParams") if ((a = this.vars[p])) {
+                                               i = a.length;
+                                               while (--i > -1) {
+                                                       if (a[i] === "{self}") {
+                                                               a = this.vars[p] = a.concat(); //copy the array in case the user referenced the same array in multiple tweens/timelines (each {self} should be unique)
+                                                               a[i] = this;
+                                                       }
+                                               }
+                                       }
+
+                               } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
+
+                                       //t - target            [object]
+                                       //p - property          [string]
+                                       //s - start                     [number]
+                                       //c - change            [number]
+                                       //f - isFunction        [boolean]
+                                       //n - name                      [string]
+                                       //pg - isPlugin         [boolean]
+                                       //pr - priority         [number]
+                                       this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority};
+                                       i = plugin._overwriteProps.length;
+                                       while (--i > -1) {
+                                               propLookup[plugin._overwriteProps[i]] = this._firstPT;
+                                       }
+                                       if (plugin._priority || plugin._onInitAllProps) {
+                                               initPlugins = true;
+                                       }
+                                       if (plugin._onDisable || plugin._onEnable) {
+                                               this._notifyPluginsOfEnabled = true;
+                                       }
+
+                               } else {
+                                       this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0};
+                                       pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
+                                       v = this.vars[p];
+                                       pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0;
+                               }
+                               if (pt) if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                       }
+
+                       if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first)
+                               return this._initProps(target, propLookup, siblings, overwrittenProps);
+                       }
+                       if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
+                               this._kill(propLookup, target);
+                               return this._initProps(target, propLookup, siblings, overwrittenProps);
+                       }
+                       return initPlugins;
+               };
+
+               p.render = function(time, suppressEvents, force) {
+                       var prevTime = this._time,
+                               isComplete, callback, pt;
+                       if (time >= this._duration) {
+                               this._totalTime = this._time = this._duration;
+                               this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
+                               if (!this._reversed) {
+                                       isComplete = true;
+                                       callback = "onComplete";
+                               }
+                               if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                       if (time === 0 || this._rawPrevTime < 0) if (this._rawPrevTime !== time) {
+                                               force = true;
+                                               if (this._rawPrevTime > 0) {
+                                                       callback = "onReverseComplete";
+                                                       if (suppressEvents) {
+                                                               time = -1; //when a callback is placed at the VERY beginning of a timeline and it repeats (or if timeline.seek(0) is called), events are normally suppressed during those behaviors (repeat or seek()) and without adjusting the _rawPrevTime back slightly, the onComplete wouldn't get called on the next render. This only applies to zero-duration tweens/callbacks of course.
+                                                       }
+                                               }
+                                       }
+                                       this._rawPrevTime = time;
+                               }
+
+                       } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
+                               this._totalTime = this._time = 0;
+                               this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
+                               if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime > 0)) {
+                                       callback = "onReverseComplete";
+                                       isComplete = this._reversed;
+                               }
+                               if (time < 0) {
+                                       this._active = false;
+                                       if (this._duration === 0) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
+                                               if (this._rawPrevTime >= 0) {
+                                                       force = true;
+                                               }
+                                               this._rawPrevTime = time;
+                                       }
+                               } else if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
+                                       force = true;
+                               }
+
+                       } else {
+                               this._totalTime = this._time = time;
+
+                               if (this._easeType) {
+                                       var r = time / this._duration, type = this._easeType, pow = this._easePower;
+                                       if (type === 1 || (type === 3 && r >= 0.5)) {
+                                               r = 1 - r;
+                                       }
+                                       if (type === 3) {
+                                               r *= 2;
+                                       }
+                                       if (pow === 1) {
+                                               r *= r;
+                                       } else if (pow === 2) {
+                                               r *= r * r;
+                                       } else if (pow === 3) {
+                                               r *= r * r * r;
+                                       } else if (pow === 4) {
+                                               r *= r * r * r * r;
+                                       }
+
+                                       if (type === 1) {
+                                               this.ratio = 1 - r;
+                                       } else if (type === 2) {
+                                               this.ratio = r;
+                                       } else if (time / this._duration < 0.5) {
+                                               this.ratio = r / 2;
+                                       } else {
+                                               this.ratio = 1 - (r / 2);
+                                       }
+
+                               } else {
+                                       this.ratio = this._ease.getRatio(time / this._duration);
+                               }
+
+                       }
+
+                       if (this._time === prevTime && !force) {
+                               return;
+                       } else if (!this._initted) {
+                               this._init();
+                               if (!this._initted) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that overwriting occurs properly.
+                                       return;
+                               }
+                               //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
+                               if (this._time && !isComplete) {
+                                       this.ratio = this._ease.getRatio(this._time / this._duration);
+                               } else if (isComplete && this._ease._calcEnd) {
+                                       this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
+                               }
+                       }
+
+                       if (!this._active) if (!this._paused) {
+                               this._active = true;  //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
+                       }
+                       if (prevTime === 0) {
+                               if (this._startAt) {
+                                       if (time >= 0) {
+                                               this._startAt.render(time, suppressEvents, force);
+                                       } else if (!callback) {
+                                               callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
+                                       }
+                               }
+                               if (this.vars.onStart) if (this._time !== 0 || this._duration === 0) if (!suppressEvents) {
+                                       this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
+                               }
+                       }
+
+                       pt = this._firstPT;
+                       while (pt) {
+                               if (pt.f) {
+                                       pt.t[pt.p](pt.c * this.ratio + pt.s);
+                               } else {
+                                       pt.t[pt.p] = pt.c * this.ratio + pt.s;
+                               }
+                               pt = pt._next;
+                       }
+
+                       if (this._onUpdate) {
+                               if (time < 0) if (this._startAt) {
+                                       this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
+                               }
+                               if (!suppressEvents) {
+                                       this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
+                               }
+                       }
+
+                       if (callback) if (!this._gc) { //check _gc because there's a chance that kill() could be called in an onUpdate
+                               if (time < 0 && this._startAt && !this._onUpdate) {
+                                       this._startAt.render(time, suppressEvents, force);
+                               }
+                               if (isComplete) {
+                                       if (this._timeline.autoRemoveChildren) {
+                                               this._enabled(false, false);
+                                       }
+                                       this._active = false;
+                               }
+                               if (!suppressEvents && this.vars[callback]) {
+                                       this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
+                               }
+                       }
+
+               };
+
+               p._kill = function(vars, target) {
+                       if (vars === "all") {
+                               vars = null;
+                       }
+                       if (vars == null) if (target == null || target === this.target) {
+                               return this._enabled(false, false);
+                       }
+                       target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
+                       var i, overwrittenProps, p, pt, propLookup, changed, killProps, record;
+                       if ((target instanceof Array || _isSelector(target)) && typeof(target[0]) !== "number") {
+                               i = target.length;
+                               while (--i > -1) {
+                                       if (this._kill(vars, target[i])) {
+                                               changed = true;
+                                       }
+                               }
+                       } else {
+                               if (this._targets) {
+                                       i = this._targets.length;
+                                       while (--i > -1) {
+                                               if (target === this._targets[i]) {
+                                                       propLookup = this._propLookup[i] || {};
+                                                       this._overwrittenProps = this._overwrittenProps || [];
+                                                       overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
+                                                       break;
+                                               }
+                                       }
+                               } else if (target !== this.target) {
+                                       return false;
+                               } else {
+                                       propLookup = this._propLookup;
+                                       overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
+                               }
+
+                               if (propLookup) {
+                                       killProps = vars || propLookup;
+                                       record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (vars == null || vars._tempKill !== true)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin)
+                                       for (p in killProps) {
+                                               if ((pt = propLookup[p])) {
+                                                       if (pt.pg && pt.t._kill(killProps)) {
+                                                               changed = true; //some plugins need to be notified so they can perform cleanup tasks first
+                                                       }
+                                                       if (!pt.pg || pt.t._overwriteProps.length === 0) {
+                                                               if (pt._prev) {
+                                                                       pt._prev._next = pt._next;
+                                                               } else if (pt === this._firstPT) {
+                                                                       this._firstPT = pt._next;
+                                                               }
+                                                               if (pt._next) {
+                                                                       pt._next._prev = pt._prev;
+                                                               }
+                                                               pt._next = pt._prev = null;
+                                                       }
+                                                       delete propLookup[p];
+                                               }
+                                               if (record) {
+                                                       overwrittenProps[p] = 1;
+                                               }
+                                       }
+                                       if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.
+                                               this._enabled(false, false);
+                                       }
+                               }
+                       }
+                       return changed;
+               };
+
+               p.invalidate = function() {
+                       if (this._notifyPluginsOfEnabled) {
+                               TweenLite._onPluginEvent("_onDisable", this);
+                       }
+                       this._firstPT = null;
+                       this._overwrittenProps = null;
+                       this._onUpdate = null;
+                       this._startAt = null;
+                       this._initted = this._active = this._notifyPluginsOfEnabled = false;
+                       this._propLookup = (this._targets) ? {} : [];
+                       return this;
+               };
+
+               p._enabled = function(enabled, ignoreTimeline) {
+                       if (!_tickerActive) {
+                               _ticker.wake();
+                       }
+                       if (enabled && this._gc) {
+                               var targets = this._targets,
+                                       i;
+                               if (targets) {
+                                       i = targets.length;
+                                       while (--i > -1) {
+                                               this._siblings[i] = _register(targets[i], this, true);
+                                       }
+                               } else {
+                                       this._siblings = _register(this.target, this, true);
+                               }
+                       }
+                       Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
+                       if (this._notifyPluginsOfEnabled) if (this._firstPT) {
+                               return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
+                       }
+                       return false;
+               };
+
+
+//----TweenLite static methods -----------------------------------------------------
+
+               TweenLite.to = function(target, duration, vars) {
+                       return new TweenLite(target, duration, vars);
+               };
+
+               TweenLite.from = function(target, duration, vars) {
+                       vars.runBackwards = true;
+                       vars.immediateRender = (vars.immediateRender != false);
+                       return new TweenLite(target, duration, vars);
+               };
+
+               TweenLite.fromTo = function(target, duration, fromVars, toVars) {
+                       toVars.startAt = fromVars;
+                       toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
+                       return new TweenLite(target, duration, toVars);
+               };
+
+               TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
+                       return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0});
+               };
+
+               TweenLite.set = function(target, vars) {
+                       return new TweenLite(target, 0, vars);
+               };
+
+               TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, vars) {
+                       var a = TweenLite.getTweensOf(target),
+                               i = a.length;
+                       while (--i > -1) {
+                               a[i]._kill(vars, target);
+                       }
+               };
+
+               TweenLite.getTweensOf = function(target) {
+                       if (target == null) { return []; }
+                       target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
+                       var i, a, j, t;
+                       if ((target instanceof Array || _isSelector(target)) && typeof(target[0]) !== "number") {
+                               i = target.length;
+                               a = [];
+                               while (--i > -1) {
+                                       a = a.concat(TweenLite.getTweensOf(target[i]));
+                               }
+                               i = a.length;
+                               //now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
+                               while (--i > -1) {
+                                       t = a[i];
+                                       j = i;
+                                       while (--j > -1) {
+                                               if (t === a[j]) {
+                                                       a.splice(i, 1);
+                                               }
+                                       }
+                               }
+                       } else {
+                               a = _register(target).concat();
+                               i = a.length;
+                               while (--i > -1) {
+                                       if (a[i]._gc) {
+                                               a.splice(i, 1);
+                                       }
+                               }
+                       }
+                       return a;
+               };
+
+
+
+/*
+ * ----------------------------------------------------------------
+ * TweenPlugin   (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another <script> call before loading plugins which is easy to forget)
+ * ----------------------------------------------------------------
+ */
+               var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
+                                       this._overwriteProps = (props || "").split(",");
+                                       this._propName = this._overwriteProps[0];
+                                       this._priority = priority || 0;
+                                       this._super = TweenPlugin.prototype;
+                               }, true);
+
+               p = TweenPlugin.prototype;
+               TweenPlugin.version = "1.9.1";
+               TweenPlugin.API = 2;
+               p._firstPT = null;
+
+               p._addTween = function(target, prop, start, end, overwriteProp, round) {
+                       var c, pt;
+                       if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0)+"1", 10) * Number(end.substr(2)))) {
+                               this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round};
+                               if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                       }
+               };
+
+               p.setRatio = function(v) {
+                       var pt = this._firstPT,
+                               min = 0.000001,
+                               val;
+                       while (pt) {
+                               val = pt.c * v + pt.s;
+                               if (pt.r) {
+                                       val = (val + ((val > 0) ? 0.5 : -0.5)) >> 0; //about 4x faster than Math.round()
+                               } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser
+                                       val = 0;
+                               }
+                               if (pt.f) {
+                                       pt.t[pt.p](val);
+                               } else {
+                                       pt.t[pt.p] = val;
+                               }
+                               pt = pt._next;
+                       }
+               };
+
+               p._kill = function(lookup) {
+                       var a = this._overwriteProps,
+                               pt = this._firstPT,
+                               i;
+                       if (lookup[this._propName] != null) {
+                               this._overwriteProps = [];
+                       } else {
+                               i = a.length;
+                               while (--i > -1) {
+                                       if (lookup[a[i]] != null) {
+                                               a.splice(i, 1);
+                                       }
+                               }
+                       }
+                       while (pt) {
+                               if (lookup[pt.n] != null) {
+                                       if (pt._next) {
+                                               pt._next._prev = pt._prev;
+                                       }
+                                       if (pt._prev) {
+                                               pt._prev._next = pt._next;
+                                               pt._prev = null;
+                                       } else if (this._firstPT === pt) {
+                                               this._firstPT = pt._next;
+                                       }
+                               }
+                               pt = pt._next;
+                       }
+                       return false;
+               };
+
+               p._roundProps = function(lookup, value) {
+                       var pt = this._firstPT;
+                       while (pt) {
+                               if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here.
+                                       pt.r = value;
+                               }
+                               pt = pt._next;
+                       }
+               };
+
+               TweenLite._onPluginEvent = function(type, tween) {
+                       var pt = tween._firstPT,
+                               changed, pt2, first, last, next;
+                       if (type === "_onInitAllProps") {
+                               //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame.
+                               while (pt) {
+                                       next = pt._next;
+                                       pt2 = first;
+                                       while (pt2 && pt2.pr > pt.pr) {
+                                               pt2 = pt2._next;
+                                       }
+                                       if ((pt._prev = pt2 ? pt2._prev : last)) {
+                                               pt._prev._next = pt;
+                                       } else {
+                                               first = pt;
+                                       }
+                                       if ((pt._next = pt2)) {
+                                               pt2._prev = pt;
+                                       } else {
+                                               last = pt;
+                                       }
+                                       pt = next;
+                               }
+                               pt = tween._firstPT = first;
+                       }
+                       while (pt) {
+                               if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
+                                       changed = true;
+                               }
+                               pt = pt._next;
+                       }
+                       return changed;
+               };
+
+               TweenPlugin.activate = function(plugins) {
+                       var i = plugins.length;
+                       while (--i > -1) {
+                               if (plugins[i].API === TweenPlugin.API) {
+                                       _plugins[(new plugins[i]())._propName] = plugins[i];
+                               }
+                       }
+                       return true;
+               };
+
+               //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations.
+               _gsDefine.plugin = function(config) {
+                       if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
+                       var propName = config.propName,
+                               priority = config.priority || 0,
+                               overwriteProps = config.overwriteProps,
+                               map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
+                               Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
+                                       function() {
+                                               TweenPlugin.call(this, propName, priority);
+                                               this._overwriteProps = overwriteProps || [];
+                                       }, (config.global === true)),
+                               p = Plugin.prototype = new TweenPlugin(propName),
+                               prop;
+                       p.constructor = Plugin;
+                       Plugin.API = config.API;
+                       for (prop in map) {
+                               if (typeof(config[prop]) === "function") {
+                                       p[map[prop]] = config[prop];
+                               }
+                       }
+                       Plugin.version = config.version;
+                       TweenPlugin.activate([Plugin]);
+                       return Plugin;
+               };
+
+
+               //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you.
+               a = window._gsQueue;
+               if (a) {
+                       for (i = 0; i < a.length; i++) {
+                               a[i]();
+                       }
+                       for (p in _defLookup) {
+                               if (!_defLookup[p].func) {
+                                       window.console.log("GSAP encountered missing dependency: com.greensock." + p);
+                               }
+                       }
+               }
+
+               _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
+
+})(window);
\ No newline at end of file
diff --git a/js/libs/gsap/easing/EasePack.js b/js/libs/gsap/easing/EasePack.js
new file mode 100644 (file)
index 0000000..28aa4b7
--- /dev/null
@@ -0,0 +1,343 @@
+/*!
+ * VERSION: beta 1.9.3
+ * DATE: 2013-04-02
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
+               
+               var w = (window.GreenSockGlobals || window),
+                       gs = w.com.greensock,
+                       _2PI = Math.PI * 2,
+                       _HALF_PI = Math.PI / 2,
+                       _class = gs._class,
+                       _create = function(n, f) {
+                               var C = _class("easing." + n, function(){}, true),
+                                       p = C.prototype = new Ease();
+                               p.constructor = C;
+                               p.getRatio = f;
+                               return C;
+                       },
+                       _easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist.
+                       _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
+                               var C = _class("easing."+name, {
+                                       easeOut:new EaseOut(),
+                                       easeIn:new EaseIn(),
+                                       easeInOut:new EaseInOut()
+                               }, true);
+                               _easeReg(C, name);
+                               return C;
+                       },
+                       EasePoint = function(time, value, next) {
+                               this.t = time;
+                               this.v = value;
+                               if (next) {
+                                       this.next = next;
+                                       next.prev = this;
+                                       this.c = next.v - value;
+                                       this.gap = next.t - time;
+                               }
+                       },
+
+                       //Back
+                       _createBack = function(n, f) {
+                               var C = _class("easing." + n, function(overshoot) {
+                                               this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
+                                               this._p2 = this._p1 * 1.525;
+                                       }, true), 
+                                       p = C.prototype = new Ease();
+                               p.constructor = C;
+                               p.getRatio = f;
+                               p.config = function(overshoot) {
+                                       return new C(overshoot);
+                               };
+                               return C;
+                       },
+
+                       Back = _wrap("Back",
+                               _createBack("BackOut", function(p) {
+                                       return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
+                               }),
+                               _createBack("BackIn", function(p) {
+                                       return p * p * ((this._p1 + 1) * p - this._p1);
+                               }),
+                               _createBack("BackInOut", function(p) {
+                                       return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2);
+                               })
+                       ),
+
+
+                       //SlowMo
+                       SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
+                               power = (power || power === 0) ? power : 0.7;
+                               if (linearRatio == null) {
+                                       linearRatio = 0.7;
+                               } else if (linearRatio > 1) {
+                                       linearRatio = 1;
+                               }
+                               this._p = (linearRatio !== 1) ? power : 0;
+                               this._p1 = (1 - linearRatio) / 2;
+                               this._p2 = linearRatio;
+                               this._p3 = this._p1 + this._p2;
+                               this._calcEnd = (yoyoMode === true);
+                       }, true),
+                       p = SlowMo.prototype = new Ease(),
+                       SteppedEase, RoughEase, _createElastic;
+                       
+               p.constructor = SlowMo;
+               p.getRatio = function(p) {
+                       var r = p + (0.5 - p) * this._p;
+                       if (p < this._p1) {
+                               return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
+                       } else if (p > this._p3) {
+                               return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
+                       }
+                       return this._calcEnd ? 1 : r;
+               };
+               SlowMo.ease = new SlowMo(0.7, 0.7);
+               
+               p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
+                       return new SlowMo(linearRatio, power, yoyoMode);
+               };
+
+
+               //SteppedEase
+               SteppedEase = _class("easing.SteppedEase", function(steps) {
+                               steps = steps || 1;
+                               this._p1 = 1 / steps;
+                               this._p2 = steps + 1;
+                       }, true);
+               p = SteppedEase.prototype = new Ease(); 
+               p.constructor = SteppedEase;
+               p.getRatio = function(p) {
+                       if (p < 0) {
+                               p = 0;
+                       } else if (p >= 1) {
+                               p = 0.999999999;
+                       }
+                       return ((this._p2 * p) >> 0) * this._p1;
+               };
+               p.config = SteppedEase.config = function(steps) {
+                       return new SteppedEase(steps);
+               };
+
+
+               //RoughEase
+               RoughEase = _class("easing.RoughEase", function(vars) {
+                       vars = vars || {};
+                       var taper = vars.taper || "none",
+                               a = [],
+                               cnt = 0,
+                               points = (vars.points || 20) | 0,
+                               i = points,
+                               randomize = (vars.randomize !== false),
+                               clamp = (vars.clamp === true),
+                               template = (vars.template instanceof Ease) ? vars.template : null,
+                               strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
+                               x, y, bump, invX, obj, pnt;
+                       while (--i > -1) {
+                               x = randomize ? Math.random() : (1 / points) * i;
+                               y = template ? template.getRatio(x) : x;
+                               if (taper === "none") {
+                                       bump = strength;
+                               } else if (taper === "out") {
+                                       invX = 1 - x;
+                                       bump = invX * invX * strength;
+                               } else if (taper === "in") {
+                                       bump = x * x * strength;
+                               } else if (x < 0.5) {  //"both" (start)
+                                       invX = x * 2;
+                                       bump = invX * invX * 0.5 * strength;
+                               } else {                                //"both" (end)
+                                       invX = (1 - x) * 2;
+                                       bump = invX * invX * 0.5 * strength;
+                               }
+                               if (randomize) {
+                                       y += (Math.random() * bump) - (bump * 0.5);
+                               } else if (i % 2) {
+                                       y += bump * 0.5;
+                               } else {
+                                       y -= bump * 0.5;
+                               }
+                               if (clamp) {
+                                       if (y > 1) {
+                                               y = 1;
+                                       } else if (y < 0) {
+                                               y = 0;
+                                       }
+                               }
+                               a[cnt++] = {x:x, y:y};
+                       }
+                       a.sort(function(a, b) {
+                               return a.x - b.x;
+                       });
+
+                       pnt = new EasePoint(1, 1, null);
+                       i = points;
+                       while (--i > -1) {
+                               obj = a[i];
+                               pnt = new EasePoint(obj.x, obj.y, pnt);
+                       }
+
+                       this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
+               }, true);
+               p = RoughEase.prototype = new Ease();
+               p.constructor = RoughEase;
+               p.getRatio = function(p) {
+                       var pnt = this._prev;
+                       if (p > pnt.t) {
+                               while (pnt.next && p >= pnt.t) {
+                                       pnt = pnt.next;
+                               }
+                               pnt = pnt.prev;
+                       } else {
+                               while (pnt.prev && p <= pnt.t) {
+                                       pnt = pnt.prev;
+                               }
+                       }
+                       this._prev = pnt;
+                       return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
+               };
+               p.config = function(vars) {
+                       return new RoughEase(vars);
+               };
+               RoughEase.ease = new RoughEase();
+
+
+               //Bounce
+               _wrap("Bounce",
+                       _create("BounceOut", function(p) {
+                               if (p < 1 / 2.75) {
+                                       return 7.5625 * p * p;
+                               } else if (p < 2 / 2.75) {
+                                       return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
+                               } else if (p < 2.5 / 2.75) {
+                                       return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
+                               }
+                               return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
+                       }),
+                       _create("BounceIn", function(p) {
+                               if ((p = 1 - p) < 1 / 2.75) {
+                                       return 1 - (7.5625 * p * p);
+                               } else if (p < 2 / 2.75) {
+                                       return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
+                               } else if (p < 2.5 / 2.75) {
+                                       return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
+                               }
+                               return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
+                       }),
+                       _create("BounceInOut", function(p) {
+                               var invert = (p < 0.5);
+                               if (invert) {
+                                       p = 1 - (p * 2);
+                               } else {
+                                       p = (p * 2) - 1;
+                               }
+                               if (p < 1 / 2.75) {
+                                       p = 7.5625 * p * p;
+                               } else if (p < 2 / 2.75) {
+                                       p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
+                               } else if (p < 2.5 / 2.75) {
+                                       p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
+                               } else {
+                                       p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
+                               }
+                               return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
+                       })
+               );
+
+
+               //CIRC
+               _wrap("Circ",
+                       _create("CircOut", function(p) {
+                               return Math.sqrt(1 - (p = p - 1) * p);
+                       }),
+                       _create("CircIn", function(p) {
+                               return -(Math.sqrt(1 - (p * p)) - 1);
+                       }),
+                       _create("CircInOut", function(p) {
+                               return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
+                       })
+               );
+
+
+               //Elastic
+               _createElastic = function(n, f, def) {
+                       var C = _class("easing." + n, function(amplitude, period) {
+                                       this._p1 = amplitude || 1;
+                                       this._p2 = period || def;
+                                       this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
+                               }, true),
+                               p = C.prototype = new Ease();
+                       p.constructor = C;
+                       p.getRatio = f;
+                       p.config = function(amplitude, period) {
+                               return new C(amplitude, period);
+                       };
+                       return C;
+               };
+               _wrap("Elastic",
+                       _createElastic("ElasticOut", function(p) {
+                               return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1;
+                       }, 0.3),
+                       _createElastic("ElasticIn", function(p) {
+                               return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ));
+                       }, 0.3),
+                       _createElastic("ElasticInOut", function(p) {
+                               return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ) *0.5 + 1;
+                       }, 0.45)
+               );
+
+
+               //Expo
+               _wrap("Expo",
+                       _create("ExpoOut", function(p) {
+                               return 1 - Math.pow(2, -10 * p);
+                       }),
+                       _create("ExpoIn", function(p) {
+                               return Math.pow(2, 10 * (p - 1)) - 0.001;
+                       }),
+                       _create("ExpoInOut", function(p) {
+                               return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
+                       })
+               );
+
+
+               //Sine
+               _wrap("Sine",
+                       _create("SineOut", function(p) {
+                               return Math.sin(p * _HALF_PI);
+                       }),
+                       _create("SineIn", function(p) {
+                               return -Math.cos(p * _HALF_PI) + 1;
+                       }),
+                       _create("SineInOut", function(p) {
+                               return -0.5 * (Math.cos(Math.PI * p) - 1);
+                       })
+               );
+
+               _class("easing.EaseLookup", {
+                               find:function(s) {
+                                       return Ease.map[s];
+                               }
+                       }, true);
+
+               //register the non-standard eases
+               _easeReg(w.SlowMo, "SlowMo", "ease,");
+               _easeReg(RoughEase, "RoughEase", "ease,");
+               _easeReg(SteppedEase, "SteppedEase", "ease,");
+               
+               return Back;
+               
+       }, true);
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/jquery.gsap.js b/js/libs/gsap/jquery.gsap.js
new file mode 100644 (file)
index 0000000..493bd2d
--- /dev/null
@@ -0,0 +1,167 @@
+/*!
+ * VERSION: 0.1.6
+ * DATE: 2013-02-13
+ * UPDATES AND DOCS AT: http://www.greensock.com/jquery-gsap-plugin/
+ *
+ * Requires TweenLite version 1.8.0 or higher and CSSPlugin.
+ *
+ * @license Copyright (c) 2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ *
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(function($) {
+       "use strict";
+
+       var     _animate = $.fn.animate,
+               _stop = $.fn.stop,
+               _enabled = true,
+               TweenLite, CSSPlugin, _warned,
+               _dequeue = function(func, next) {
+                       if (typeof(func) === "function") {
+                               this.each(func);
+                       }
+                       next();
+               },
+               _addCallback = function(type, func, obj, vars, next) {
+                       next = (typeof(next) === "function") ? next : null;
+                       func = (typeof(func) === "function") ? func : null;
+                       if (!func && !next) {
+                               return;
+                       }
+                       vars[type] = next ? _dequeue : obj.each;
+                       vars[type + "Scope"] = obj;
+                       vars[type + "Params"] = next ? [func, next] : [func];
+               },
+               _reserved = {overwrite:1, delay:1, useFrames:1, runBackwards:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, autoCSS:1},
+               _copyCriticalReserved = function(main, sub) {
+                       for (var p in _reserved) {
+                               if (_reserved[p] && main[p] !== undefined) {
+                                       sub[p] = main[p];
+                               }
+                       }
+               },
+               _createEase = function(ease) {
+                       return function(p) {
+                               return ease.getRatio(p);
+                       };
+               },
+               _easeMap = {},
+               _init = function() {
+                       var globals = window.GreenSockGlobals || window,
+                               version, stale, p;
+                       TweenLite = globals.TweenMax || globals.TweenLite; //we prioritize TweenMax if it's loaded so that we can accommodate special features like repeat, yoyo, repeatDelay, etc.
+                       if (TweenLite) {
+                               version = (TweenLite.version + ".0.0").split("."); //in case an old version of TweenLite is used that had a numeric version like 1.68 instead of a string like "1.6.8"
+                               stale = !(Number(version[0]) > 0 && Number(version[1]) > 7);
+                               globals = globals.com.greensock;
+                               CSSPlugin = globals.plugins.CSSPlugin;
+                               _easeMap = globals.easing.Ease.map || {}; //don't do just window.Ease or window.CSSPlugin because some other libraries like EaselJS/TweenJS use those same names and there could be a collision.
+                       }
+                       if (!TweenLite || !CSSPlugin || stale) {
+                               TweenLite = null;
+                               if (!_warned && window.console) {
+                                       window.console.log("The jquery.gsap.js plugin requires the TweenMax (or at least TweenLite and CSSPlugin) JavaScript file(s)." + (stale ? " Version " + version.join(".") + " is too old." : ""));
+                                       _warned = true;
+                               }
+                               return;
+                       }
+                       if ($.easing) {
+                               for (p in _easeMap) {
+                                       $.easing[p] = _createEase(_easeMap[p]);
+                               }
+                               _init = false;
+                       }
+               };
+
+       $.fn.animate = function(prop, speed, easing, callback) {
+               prop = prop || {};
+               if (_init) {
+                       _init();
+                       if (!TweenLite || !CSSPlugin) {
+                               return _animate.call(this, prop, speed, easing, callback);
+                       }
+               }
+               if (!_enabled || prop.skipGSAP === true || (typeof(speed) === "object" && typeof(speed.step) === "function") || prop.scrollTop != null || prop.scrollLeft != null) { //we don't support the "step" feature because it's too costly performance-wise, so fall back to the native animate() call if we sense one. Same with scrollTop and scrollLeft which are handled in a special way in jQuery.
+                       return _animate.call(this, prop, speed, easing, callback);
+               }
+               var config = $.speed(speed, easing, callback),
+                       vars = {ease:(_easeMap[config.easing] || ((config.easing === false) ? _easeMap.linear : _easeMap.swing))},
+                       obj = this,
+                       specEasing = (typeof(speed) === "object") ? speed.specialEasing : null,
+                       val, p, doAnimation, specEasingVars;
+
+               for (p in prop) {
+                       val = prop[p];
+                       if (val instanceof Array && _easeMap[val[1]]) {
+                               specEasing = specEasing || {};
+                               specEasing[p] = val[1];
+                               val = val[0];
+                       }
+                       if (val === "toggle" || val === "hide" || val === "show") {
+                               return _animate.call(this, prop, speed, easing, callback);
+                       } else {
+                               vars[(p.indexOf("-") === -1) ? p : $.camelCase(p)] = val;
+                       }
+               }
+
+               if (specEasing) {
+                       specEasingVars = [];
+                       for (p in specEasing) {
+                               val = specEasingVars[specEasingVars.length] = {};
+                               _copyCriticalReserved(vars, val);
+                               val.ease = (_easeMap[specEasing[p]] || vars.ease);
+                               if (p.indexOf("-") !== -1) {
+                                       p = $.camelCase(p);
+                               }
+                               val[p] = vars[p];
+                       }
+                       if (specEasingVars.length === 0) {
+                               specEasingVars = null;
+                       }
+               }
+
+               doAnimation = function(next) {
+                       if (specEasingVars) {
+                               var i = specEasingVars.length;
+                               while (--i > -1) {
+                                       TweenLite.to(obj, $.fx.off ? 0 : config.duration / 1000, specEasingVars[i]);
+                               }
+                       }
+                       _addCallback("onComplete", config.old, obj, vars, next);
+                       TweenLite.to(obj, $.fx.off ? 0 : config.duration / 1000, vars);
+               };
+
+               if (config.queue !== false) {
+                       obj.queue(config.queue, doAnimation);
+               } else {
+                       doAnimation();
+               }
+
+               return obj;
+       };
+
+
+       $.fn.stop = function(clearQueue, gotoEnd) {
+               _stop.call(this, clearQueue, gotoEnd);
+               if (TweenLite) {
+                       if (gotoEnd) {
+                               var tweens = TweenLite.getTweensOf(this),
+                                       i = tweens.length,
+                                       progress;
+                               while (--i > -1) {
+                                       progress = tweens[i].totalTime() / tweens[i].totalDuration();
+                                       if (progress > 0 && progress < 1) {
+                                               tweens[i].seek(tweens[i].totalDuration());
+                                       }
+                               }
+                       }
+                       TweenLite.killTweensOf(this);
+               }
+               return this;
+       };
+
+       $.gsap = {enabled:function(value) {_enabled = value;}, version:"0.1.6"};
+
+}(jQuery));
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/AttrPlugin.js b/js/libs/gsap/plugins/AttrPlugin.js
new file mode 100644 (file)
index 0000000..2b8c8f4
--- /dev/null
@@ -0,0 +1,49 @@
+/*!
+ * VERSION: 0.1.0
+ * DATE: 2013-02-22
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+       
+       "use strict";
+
+       window._gsDefine.plugin({
+               propName: "attr",
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       var p;
+                       if (typeof(target.setAttribute) !== "function") {
+                               return false;
+                       }
+                       this._target = target;
+                       this._proxy = {};
+                       for (p in value) {
+                               this._addTween(this._proxy, p, parseFloat(target.getAttribute(p)), value[p], p);
+                               this._overwriteProps.push(p);
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(ratio) {
+                       this._super.setRatio.call(this, ratio);
+                       var props = this._overwriteProps,
+                               i = props.length,
+                               p;
+                       while (--i > -1) {
+                               p = props[i];
+                               this._target.setAttribute(p, this._proxy[p] + "");
+                       }
+               }
+
+       });
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/BezierPlugin.js b/js/libs/gsap/plugins/BezierPlugin.js
new file mode 100644 (file)
index 0000000..68abffa
--- /dev/null
@@ -0,0 +1,575 @@
+/*!
+ * VERSION: beta 1.2.4
+ * DATE: 2013-04-19
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+               var _RAD2DEG = 180 / Math.PI,
+                       _DEG2RAD = Math.PI / 180,
+                       _r1 = [],
+                       _r2 = [],
+                       _r3 = [],
+                       _corProps = {},
+                       Segment = function(a, b, c, d) {
+                               this.a = a;
+                               this.b = b;
+                               this.c = c;
+                               this.d = d;
+                               this.da = d - a;
+                               this.ca = c - a;
+                               this.ba = b - a;
+                       },
+                       _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",
+                       cubicToQuadratic = function(a, b, c, d) {
+                               var q1 = {a:a},
+                                       q2 = {},
+                                       q3 = {},
+                                       q4 = {c:d},
+                                       mab = (a + b) / 2,
+                                       mbc = (b + c) / 2,
+                                       mcd = (c + d) / 2,
+                                       mabc = (mab + mbc) / 2,
+                                       mbcd = (mbc + mcd) / 2,
+                                       m8 = (mbcd - mabc) / 8;
+                               q1.b = mab + (a - mab) / 4;
+                               q2.b = mabc + m8;
+                               q1.c = q2.a = (q1.b + q2.b) / 2;
+                               q2.c = q3.a = (mabc + mbcd) / 2;
+                               q3.b = mbcd - m8;
+                               q4.b = mcd + (d - mcd) / 4;
+                               q3.c = q4.a = (q3.b + q4.b) / 2;
+                               return [q1, q2, q3, q4];
+                       },
+                       _calculateControlPoints = function(a, curviness, quad, basic, correlate) {
+                               var l = a.length - 1,
+                                       ii = 0,
+                                       cp1 = a[0].a,
+                                       i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
+                               for (i = 0; i < l; i++) {
+                                       seg = a[ii];
+                                       p1 = seg.a;
+                                       p2 = seg.d;
+                                       p3 = a[ii+1].d;
+
+                                       if (correlate) {
+                                               r1 = _r1[i];
+                                               r2 = _r2[i];
+                                               tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5);
+                                               m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0));
+                                               m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0));
+                                               mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0));
+                                       } else {
+                                               m1 = p2 - (p2 - p1) * curviness * 0.5;
+                                               m2 = p2 + (p3 - p2) * curviness * 0.5;
+                                               mm = p2 - (m1 + m2) / 2;
+                                       }
+                                       m1 += mm;
+                                       m2 += mm;
+
+                                       seg.c = cp2 = m1;
+                                       if (i !== 0) {
+                                               seg.b = cp1;
+                                       } else {
+                                               seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly.
+                                       }
+
+                                       seg.da = p2 - p1;
+                                       seg.ca = cp2 - p1;
+                                       seg.ba = cp1 - p1;
+
+                                       if (quad) {
+                                               qb = cubicToQuadratic(p1, cp1, cp2, p2);
+                                               a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
+                                               ii += 4;
+                                       } else {
+                                               ii++;
+                                       }
+
+                                       cp1 = m2;
+                               }
+                               seg = a[ii];
+                               seg.b = cp1;
+                               seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly.
+                               seg.da = seg.d - seg.a;
+                               seg.ca = seg.c - seg.a;
+                               seg.ba = cp1 - seg.a;
+                               if (quad) {
+                                       qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d);
+                                       a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]);
+                               }
+                       },
+                       _parseAnchors = function(values, p, correlate, prepend) {
+                               var a = [],
+                                       l, i, p1, p2, p3, tmp;
+                               if (prepend) {
+                                       values = [prepend].concat(values);
+                                       i = values.length;
+                                       while (--i > -1) {
+                                               if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") {
+                                                       values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons
+                                               }
+                                       }
+                               }
+                               l = values.length - 2;
+                               if (l < 0) {
+                                       a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
+                                       return a;
+                               }
+                               for (i = 0; i < l; i++) {
+                                       p1 = values[i][p];
+                                       p2 = values[i+1][p];
+                                       a[i] = new Segment(p1, 0, 0, p2);
+                                       if (correlate) {
+                                               p3 = values[i+2][p];
+                                               _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
+                                               _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
+                                       }
+                               }
+                               a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]);
+                               return a;
+                       },
+                       bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) {
+                               var obj = {},
+                                       props = [],
+                                       first = prepend || values[0],
+                                       i, p, a, j, r, l, seamless, last;
+                               correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate;
+                               if (curviness == null) {
+                                       curviness = 1;
+                               }
+                               for (p in values[0]) {
+                                       props.push(p);
+                               }
+                               //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later)
+                               if (values.length > 1) {
+                                       last = values[values.length - 1];
+                                       seamless = true;
+                                       i = props.length;
+                                       while (--i > -1) {
+                                               p = props[i];
+                                               if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9
+                                                       seamless = false;
+                                                       break;
+                                               }
+                                       }
+                                       if (seamless) {
+                                               values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
+                                               if (prepend) {
+                                                       values.unshift(prepend);
+                                               }
+                                               values.push(values[1]);
+                                               prepend = values[values.length - 3];
+                                       }
+                               }
+                               _r1.length = _r2.length = _r3.length = 0;
+                               i = props.length;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       _corProps[p] = (correlate.indexOf(","+p+",") !== -1);
+                                       obj[p] = _parseAnchors(values, p, _corProps[p], prepend);
+                               }
+                               i = _r1.length;
+                               while (--i > -1) {
+                                       _r1[i] = Math.sqrt(_r1[i]);
+                                       _r2[i] = Math.sqrt(_r2[i]);
+                               }
+                               if (!basic) {
+                                       i = props.length;
+                                       while (--i > -1) {
+                                               if (_corProps[p]) {
+                                                       a = obj[props[i]];
+                                                       l = a.length - 1;
+                                                       for (j = 0; j < l; j++) {
+                                                               r = a[j+1].da / _r2[j] + a[j].da / _r1[j];
+                                                               _r3[j] = (_r3[j] || 0) + r * r;
+                                                       }
+                                               }
+                                       }
+                                       i = _r3.length;
+                                       while (--i > -1) {
+                                               _r3[i] = Math.sqrt(_r3[i]);
+                                       }
+                               }
+                               i = props.length;
+                               j = quadratic ? 4 : 1;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       a = obj[p];
+                                       _calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties
+                                       if (seamless) {
+                                               a.splice(0, j);
+                                               a.splice(a.length - j, j);
+                                       }
+                               }
+                               return obj;
+                       },
+                       _parseBezierData = function(values, type, prepend) {
+                               type = type || "soft";
+                               var obj = {},
+                                       inc = (type === "cubic") ? 3 : 2,
+                                       soft = (type === "soft"),
+                                       props = [],
+                                       a, b, c, d, cur, i, j, l, p, cnt, tmp;
+                               if (soft && prepend) {
+                                       values = [prepend].concat(values);
+                               }
+                               if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; }
+                               for (p in values[0]) {
+                                       props.push(p);
+                               }
+                               i = props.length;
+                               while (--i > -1) {
+                                       p = props[i];
+                                       obj[p] = cur = [];
+                                       cnt = 0;
+                                       l = values.length;
+                                       for (j = 0; j < l; j++) {
+                                               a = (prepend == null) ? values[j][p] : (typeof( (tmp = values[j][p]) ) === "string" && tmp.charAt(1) === "=") ? prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)) : Number(tmp);
+                                               if (soft) if (j > 1) if (j < l - 1) {
+                                                       cur[cnt++] = (a + cur[cnt-2]) / 2;
+                                               }
+                                               cur[cnt++] = a;
+                                       }
+                                       l = cnt - inc + 1;
+                                       cnt = 0;
+                                       for (j = 0; j < l; j += inc) {
+                                               a = cur[j];
+                                               b = cur[j+1];
+                                               c = cur[j+2];
+                                               d = (inc === 2) ? 0 : cur[j+3];
+                                               cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
+                                       }
+                                       cur.length = cnt;
+                               }
+                               return obj;
+                       },
+                       _addCubicLengths = function(a, steps, resolution) {
+                               var inc = 1 / resolution,
+                                       j = a.length,
+                                       d, d1, s, da, ca, ba, p, i, inv, bez, index;
+                               while (--j > -1) {
+                                       bez = a[j];
+                                       s = bez.a;
+                                       da = bez.d - s;
+                                       ca = bez.c - s;
+                                       ba = bez.b - s;
+                                       d = d1 = 0;
+                                       for (i = 1; i <= resolution; i++) {
+                                               p = inc * i;
+                                               inv = 1 - p;
+                                               d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p);
+                                               index = j * resolution + i - 1;
+                                               steps[index] = (steps[index] || 0) + d * d;
+                                       }
+                               }
+                       },
+                       _parseLengthData = function(obj, resolution) {
+                               resolution = resolution >> 0 || 6;
+                               var a = [],
+                                       lengths = [],
+                                       d = 0,
+                                       total = 0,
+                                       threshold = resolution - 1,
+                                       segments = [],
+                                       curLS = [], //current length segments array
+                                       p, i, l, index;
+                               for (p in obj) {
+                                       _addCubicLengths(obj[p], a, resolution);
+                               }
+                               l = a.length;
+                               for (i = 0; i < l; i++) {
+                                       d += Math.sqrt(a[i]);
+                                       index = i % resolution;
+                                       curLS[index] = d;
+                                       if (index === threshold) {
+                                               total += d;
+                                               index = (i / resolution) >> 0;
+                                               segments[index] = curLS;
+                                               lengths[index] = total;
+                                               d = 0;
+                                               curLS = [];
+                                       }
+                               }
+                               return {length:total, lengths:lengths, segments:segments};
+                       },
+
+
+
+                       BezierPlugin = window._gsDefine.plugin({
+                                       propName: "bezier",
+                                       priority: -1,
+                                       API: 2,
+                                       global:true,
+
+                                       //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                                       init: function(target, vars, tween) {
+                                               this._target = target;
+                                               if (vars instanceof Array) {
+                                                       vars = {values:vars};
+                                               }
+                                               this._func = {};
+                                               this._round = {};
+                                               this._props = [];
+                                               this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10);
+                                               var values = vars.values || [],
+                                                       first = {},
+                                                       second = values[0],
+                                                       autoRotate = vars.autoRotate || tween.vars.orientToBezier,
+                                                       p, isFunc, i, j, prepend;
+
+                                               this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null;
+                                               for (p in second) {
+                                                       this._props.push(p);
+                                               }
+
+                                               i = this._props.length;
+                                               while (--i > -1) {
+                                                       p = this._props[i];
+
+                                                       this._overwriteProps.push(p);
+                                                       isFunc = this._func[p] = (typeof(target[p]) === "function");
+                                                       first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
+                                                       if (!prepend) if (first[p] !== values[0][p]) {
+                                                               prepend = first;
+                                                       }
+                                               }
+                                               this._beziers = (vars.type !== "cubic" && vars.type !== "quadratic" && vars.type !== "soft") ? bezierThrough(values, isNaN(vars.curviness) ? 1 : vars.curviness, false, (vars.type === "thruBasic"), vars.correlate, prepend) : _parseBezierData(values, vars.type, first);
+                                               this._segCount = this._beziers[p].length;
+
+                                               if (this._timeRes) {
+                                                       var ld = _parseLengthData(this._beziers, this._timeRes);
+                                                       this._length = ld.length;
+                                                       this._lengths = ld.lengths;
+                                                       this._segments = ld.segments;
+                                                       this._l1 = this._li = this._s1 = this._si = 0;
+                                                       this._l2 = this._lengths[0];
+                                                       this._curSeg = this._segments[0];
+                                                       this._s2 = this._curSeg[0];
+                                                       this._prec = 1 / this._curSeg.length;
+                                               }
+
+                                               if ((autoRotate = this._autoRotate)) {
+                                                       if (!(autoRotate[0] instanceof Array)) {
+                                                               this._autoRotate = autoRotate = [autoRotate];
+                                                       }
+                                                       i = autoRotate.length;
+                                                       while (--i > -1) {
+                                                               for (j = 0; j < 3; j++) {
+                                                                       p = autoRotate[i][j];
+                                                                       this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
+                                                               }
+                                                       }
+                                               }
+                                               return true;
+                                       },
+
+                                       //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+                                       set: function(v) {
+                                               var segments = this._segCount,
+                                                       func = this._func,
+                                                       target = this._target,
+                                                       curIndex, inv, i, p, b, t, val, l, lengths, curSeg;
+                                               if (!this._timeRes) {
+                                                       curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0;
+                                                       t = (v - (curIndex * (1 / segments))) * segments;
+                                               } else {
+                                                       lengths = this._lengths;
+                                                       curSeg = this._curSeg;
+                                                       v *= this._length;
+                                                       i = this._li;
+                                                       //find the appropriate segment (if the currently cached one isn't correct)
+                                                       if (v > this._l2 && i < segments - 1) {
+                                                               l = segments - 1;
+                                                               while (i < l && (this._l2 = lengths[++i]) <= v) {       }
+                                                               this._l1 = lengths[i-1];
+                                                               this._li = i;
+                                                               this._curSeg = curSeg = this._segments[i];
+                                                               this._s2 = curSeg[(this._s1 = this._si = 0)];
+                                                       } else if (v < this._l1 && i > 0) {
+                                                               while (i > 0 && (this._l1 = lengths[--i]) >= v) { }
+                                                               if (i === 0 && v < this._l1) {
+                                                                       this._l1 = 0;
+                                                               } else {
+                                                                       i++;
+                                                               }
+                                                               this._l2 = lengths[i];
+                                                               this._li = i;
+                                                               this._curSeg = curSeg = this._segments[i];
+                                                               this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0;
+                                                               this._s2 = curSeg[this._si];
+                                                       }
+                                                       curIndex = i;
+                                                       //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one)
+                                                       v -= this._l1;
+                                                       i = this._si;
+                                                       if (v > this._s2 && i < curSeg.length - 1) {
+                                                               l = curSeg.length - 1;
+                                                               while (i < l && (this._s2 = curSeg[++i]) <= v) {        }
+                                                               this._s1 = curSeg[i-1];
+                                                               this._si = i;
+                                                       } else if (v < this._s1 && i > 0) {
+                                                               while (i > 0 && (this._s1 = curSeg[--i]) >= v) {        }
+                                                               if (i === 0 && v < this._s1) {
+                                                                       this._s1 = 0;
+                                                               } else {
+                                                                       i++;
+                                                               }
+                                                               this._s2 = curSeg[i];
+                                                               this._si = i;
+                                                       }
+                                                       t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec;
+                                               }
+                                               inv = 1 - t;
+
+                                               i = this._props.length;
+                                               while (--i > -1) {
+                                                       p = this._props[i];
+                                                       b = this._beziers[p][curIndex];
+                                                       val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a;
+                                                       if (this._round[p]) {
+                                                               val = (val + ((val > 0) ? 0.5 : -0.5)) >> 0;
+                                                       }
+                                                       if (func[p]) {
+                                                               target[p](val);
+                                                       } else {
+                                                               target[p] = val;
+                                                       }
+                                               }
+
+                                               if (this._autoRotate) {
+                                                       var ar = this._autoRotate,
+                                                               b2, x1, y1, x2, y2, add, conv;
+                                                       i = ar.length;
+                                                       while (--i > -1) {
+                                                               p = ar[i][2];
+                                                               add = ar[i][3] || 0;
+                                                               conv = (ar[i][4] === true) ? 1 : _RAD2DEG;
+                                                               b = this._beziers[ar[i][0]];
+                                                               b2 = this._beziers[ar[i][1]];
+
+                                                               if (b && b2) { //in case one of the properties got overwritten.
+                                                                       b = b[curIndex];
+                                                                       b2 = b2[curIndex];
+
+                                                                       x1 = b.a + (b.b - b.a) * t;
+                                                                       x2 = b.b + (b.c - b.b) * t;
+                                                                       x1 += (x2 - x1) * t;
+                                                                       x2 += ((b.c + (b.d - b.c) * t) - x2) * t;
+
+                                                                       y1 = b2.a + (b2.b - b2.a) * t;
+                                                                       y2 = b2.b + (b2.c - b2.b) * t;
+                                                                       y1 += (y2 - y1) * t;
+                                                                       y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t;
+
+                                                                       val = Math.atan2(y2 - y1, x2 - x1) * conv + add;
+
+                                                                       if (func[p]) {
+                                                                               target[p](val);
+                                                                       } else {
+                                                                               target[p] = val;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                       }),
+                       p = BezierPlugin.prototype;
+
+
+               BezierPlugin.bezierThrough = bezierThrough;
+               BezierPlugin.cubicToQuadratic = cubicToQuadratic;
+               BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
+               BezierPlugin.quadraticToCubic = function(a, b, c) {
+                       return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c);
+               };
+
+               BezierPlugin._cssRegister = function() {
+                       var CSSPlugin = window._gsDefine.globals.CSSPlugin;
+                       if (!CSSPlugin) {
+                               return;
+                       }
+                       var _internals = CSSPlugin._internals,
+                               _parseToProxy = _internals._parseToProxy,
+                               _setPluginRatio = _internals._setPluginRatio,
+                               CSSPropTween = _internals.CSSPropTween;
+                       _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) {
+                               if (e instanceof Array) {
+                                       e = {values:e};
+                               }
+                               plugin = new BezierPlugin();
+                               var values = e.values,
+                                       l = values.length - 1,
+                                       pluginValues = [],
+                                       v = {},
+                                       i, p, data;
+                               if (l < 0) {
+                                       return pt;
+                               }
+                               for (i = 0; i <= l; i++) {
+                                       data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i));
+                                       pluginValues[i] = data.end;
+                               }
+                               for (p in e) {
+                                       v[p] = e[p]; //duplicate the vars object because we need to alter some things which would cause problems if the user plans to reuse the same vars object for another tween.
+                               }
+                               v.values = pluginValues;
+                               pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2);
+                               pt.data = data;
+                               pt.plugin = plugin;
+                               pt.setRatio = _setPluginRatio;
+                               if (v.autoRotate === 0) {
+                                       v.autoRotate = true;
+                               }
+                               if (v.autoRotate && !(v.autoRotate instanceof Array)) {
+                                       i = (v.autoRotate === true) ? 0 : Number(v.autoRotate) * _DEG2RAD;
+                                       v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,true]] : (data.end.x != null) ? [["x","y","rotation",i,true]] : false;
+                               }
+                               if (v.autoRotate) {
+                                       if (!cssp._transform) {
+                                               cssp._enableTransforms(false);
+                                       }
+                                       data.autoRotate = cssp._target._gsTransform;
+                               }
+                               plugin._onInitTween(data.proxy, v, cssp._tween);
+                               return pt;
+                       }});
+               };
+
+               p._roundProps = function(lookup, value) {
+                       var op = this._overwriteProps,
+                               i = op.length;
+                       while (--i > -1) {
+                               if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) {
+                                       this._round[op[i]] = value;
+                               }
+                       }
+               };
+
+               p._kill = function(lookup) {
+                       var a = this._props,
+                               p, i;
+                       for (p in this._beziers) {
+                               if (p in lookup) {
+                                       delete this._beziers[p];
+                                       delete this._func[p];
+                                       i = a.length;
+                                       while (--i > -1) {
+                                               if (a[i] === p) {
+                                                       a.splice(i, 1);
+                                               }
+                                       }
+                               }
+                       }
+                       return this._super._kill.call(this, lookup);
+               };
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/CSSPlugin.js b/js/libs/gsap/plugins/CSSPlugin.js
new file mode 100644 (file)
index 0000000..a1a2783
--- /dev/null
@@ -0,0 +1,2213 @@
+/*!
+ * VERSION: beta 1.9.8
+ * DATE: 2013-06-05
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
+
+               /** @constructor **/
+               var CSSPlugin = function() {
+                               TweenPlugin.call(this, "css");
+                               this._overwriteProps.length = 0;
+                       },
+                       _hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called.
+                       _suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance
+                       _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
+                       _overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification.
+                       _specialProps = {},
+                       p = CSSPlugin.prototype = new TweenPlugin("css");
+
+               p.constructor = CSSPlugin;
+               CSSPlugin.version = "1.9.8";
+               CSSPlugin.API = 2;
+               CSSPlugin.defaultTransformPerspective = 0;
+               p = "px"; //we'll reuse the "p" variable to keep file size down
+               CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p};
+
+
+               var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
+                       _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
+                       _valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
+                       //_clrNumExp = /(?:\b(?:(?:rgb|rgba|hsl|hsla)\(.+?\))|\B#.+?\b)/, //only finds rgb(), rgba(), hsl(), hsla() and # (hexadecimal) values but NOT color names like red, blue, etc.
+                       //_tinyNumExp = /\b\d+?e\-\d+?\b/g, //finds super small numbers in a string like 1e-20. could be used in matrix3d() to fish out invalid numbers and replace them with 0. After performing speed tests, however, we discovered it was slightly faster to just cut the numbers at 5 decimal places with a particular algorithm.
+                       _NaNExp = /[^\d\-\.]/g,
+                       _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
+                       _opacityExp = /opacity *= *([^)]*)/,
+                       _opacityValExp = /opacity:([^;]*)/,
+                       _alphaFilterExp = /alpha\(opacity *=.+?\)/i,
+                       _rgbhslExp = /^(rgb|hsl)/,
+                       _capsExp = /([A-Z])/g,
+                       _camelExp = /-([a-z])/gi,
+                       _urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage)
+                       _camelFunc = function(s, g) { return g.toUpperCase(); },
+                       _horizExp = /(?:Left|Right|Width)/i,
+                       _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
+                       _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
+                       _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
+                       _DEG2RAD = Math.PI / 180,
+                       _RAD2DEG = 180 / Math.PI,
+                       _forcePT = {},
+                       _doc = document,
+                       _tempDiv = _doc.createElement("div"),
+                       _tempImg = _doc.createElement("img"),
+                       _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
+                       _agent = navigator.userAgent,
+                       _autoRound,
+                       _reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance).
+
+                       _isSafari,
+                       _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
+                       _isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!)
+                       _ieVers,
+                       _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
+                               var i = _agent.indexOf("Android"),
+                                       d = _doc.createElement("div"), a;
+
+                               _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
+                               _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
+                               _isFirefox = (_agent.indexOf("Firefox") !== -1);
+
+                               (/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent);
+                               _ieVers = parseFloat( RegExp.$1 );
+
+                               d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>";
+                               a = d.getElementsByTagName("a")[0];
+                               return a ? /^0.55/.test(a.style.opacity) : false;
+                       }()),
+                       _getIEOpacity = function(v) {
+                               return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
+                       },
+                       _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
+                               if (window.console) {
+                                       console.log(s);
+                               }
+                       },
+                       _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
+                       _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
+
+                       //@private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all)
+                       _checkPropPrefix = function(p, e) {
+                               e = e || _tempDiv;
+                               var s = e.style,
+                                       a, i;
+                               if (s[p] !== undefined) {
+                                       return p;
+                               }
+                               p = p.charAt(0).toUpperCase() + p.substr(1);
+                               a = ["O","Moz","ms","Ms","Webkit"];
+                               i = 5;
+                               while (--i > -1 && s[a[i]+p] === undefined) { }
+                               if (i >= 0) {
+                                       _prefix = (i === 3) ? "ms" : a[i];
+                                       _prefixCSS = "-" + _prefix.toLowerCase() + "-";
+                                       return _prefix + p;
+                               }
+                               return null;
+                       },
+
+                       _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
+
+                       /**
+                        * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do:
+                        * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
+                        *
+                        * @param {!Object} t Target element whose style property you want to query
+                        * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
+                        * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call.
+                        * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value.
+                        * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
+                        * @return {?string} The current property value
+                        */
+                       _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
+                               var rv;
+                               if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here.
+                                       return _getIEOpacity(t);
+                               }
+                               if (!calc && t.style[p]) {
+                                       rv = t.style[p];
+                               } else if ((cs = cs || _getComputedStyle(t, null))) {
+                                       t = cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
+                                       rv = (t || cs.length) ? t : cs[p]; //Opera behaves VERY strangely - length is usually 0 and cs[p] is the only way to get accurate results EXCEPT when checking for -o-transform which only works with cs.getPropertyValue()!
+                               } else if (t.currentStyle) {
+                                       cs = t.currentStyle;
+                                       rv = cs[p];
+                               }
+                               return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
+                       },
+
+                       /**
+                        * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number.
+                        * @param {!Object} t Target element
+                        * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
+                        * @param {!number} v Value
+                        * @param {string=} sfx Suffix (like "px" or "%" or "em")
+                        * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect.
+                        * @return {number} value in pixels
+                        */
+                       _convertToPixels = function(t, p, v, sfx, recurse) {
+                               if (sfx === "px" || !sfx) { return v; }
+                               if (sfx === "auto" || !v) { return 0; }
+                               var horiz = _horizExp.test(p),
+                                       node = t,
+                                       style = _tempDiv.style,
+                                       neg = (v < 0),
+                                       pix;
+                               if (neg) {
+                                       v = -v;
+                               }
+                               if (sfx === "%" && p.indexOf("border") !== -1) {
+                                       pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
+                               } else {
+                                       style.cssText = "border-style:solid; border-width:0; position:absolute; line-height:0;";
+                                       if (sfx === "%" || !node.appendChild) {
+                                               node = t.parentNode || _doc.body;
+                                               style[(horiz ? "width" : "height")] = v + sfx;
+                                       } else {
+                                               style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
+                                       }
+                                       node.appendChild(_tempDiv);
+                                       pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
+                                       node.removeChild(_tempDiv);
+                                       if (pix === 0 && !recurse) {
+                                               pix = _convertToPixels(t, p, v, sfx, true);
+                                       }
+                               }
+                               return neg ? -pix : pix;
+                       },
+                       _calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop
+                               if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
+                               var dim = ((p === "left") ? "Left" : "Top"),
+                                       v = _getStyle(t, "margin" + dim, cs);
+                               return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
+                       },
+
+                       //@private returns at object containing ALL of the style properties in camelCase and their associated values.
+                       _getAllStyles = function(t, cs) {
+                               var s = {},
+                                       i, tr;
+                               if ((cs = cs || _getComputedStyle(t, null))) {
+                                       if ((i = cs.length)) {
+                                               while (--i > -1) {
+                                                       s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]);
+                                               }
+                                       } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop.
+                                               for (i in cs) {
+                                                       s[i] = cs[i];
+                                               }
+                                       }
+                               } else if ((cs = t.currentStyle || t.style)) {
+                                       for (i in cs) {
+                                               s[i.replace(_camelExp, _camelFunc)] = cs[i];
+                                       }
+                               }
+                               if (!_supportsOpacity) {
+                                       s.opacity = _getIEOpacity(t);
+                               }
+                               tr = _getTransform(t, cs, false);
+                               s.rotation = tr.rotation * _RAD2DEG;
+                               s.skewX = tr.skewX * _RAD2DEG;
+                               s.scaleX = tr.scaleX;
+                               s.scaleY = tr.scaleY;
+                               s.x = tr.x;
+                               s.y = tr.y;
+                               if (_supports3D) {
+                                       s.z = tr.z;
+                                       s.rotationX = tr.rotationX * _RAD2DEG;
+                                       s.rotationY = tr.rotationY * _RAD2DEG;
+                                       s.scaleZ = tr.scaleZ;
+                               }
+                               if (s.filters) {
+                                       delete s.filters;
+                               }
+                               return s;
+                       },
+
+                       //@private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object containing only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details.
+                       _cssDif = function(t, s1, s2, vars, forceLookup) {
+                               var difs = {},
+                                       style = t.style,
+                                       val, p, mpt;
+                               for (p in s2) {
+                                       if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") {
+                                               difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween.
+                                               if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes.
+                                                       mpt = new MiniPropTween(style, p, style[p], mpt);
+                                               }
+                                       }
+                               }
+                               if (vars) {
+                                       for (p in vars) { //copy properties (except className)
+                                               if (p !== "className") {
+                                                       difs[p] = vars[p];
+                                               }
+                                       }
+                               }
+                               return {difs:difs, firstMPT:mpt};
+                       },
+                       _dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
+                       _margins = ["marginLeft","marginRight","marginTop","marginBottom"],
+
+                       /**
+                        * @private Gets the width or height of an element
+                        * @param {!Object} t Target element
+                        * @param {!string} p Property name ("width" or "height")
+                        * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
+                        * @return {number} Dimension (in pixels)
+                        */
+                       _getDimension = function(t, p, cs) {
+                               var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
+                                       a = _dimensions[p],
+                                       i = a.length;
+                               cs = cs || _getComputedStyle(t, null);
+                               while (--i > -1) {
+                                       v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
+                                       v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
+                               }
+                               return v;
+                       },
+
+                       //@private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value)
+                       _parsePosition = function(v, recObj) {
+                               if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
+                                       v = "0 0";
+                               }
+                               var a = v.split(" "),
+                                       x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
+                                       y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
+                               if (y == null) {
+                                       y = "0";
+                               } else if (y === "center") {
+                                       y = "50%";
+                               }
+                               if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
+                                       x = "50%";
+                               }
+                               if (recObj) {
+                                       recObj.oxp = (x.indexOf("%") !== -1);
+                                       recObj.oyp = (y.indexOf("%") !== -1);
+                                       recObj.oxr = (x.charAt(1) === "=");
+                                       recObj.oyr = (y.charAt(1) === "=");
+                                       recObj.ox = parseFloat(x.replace(_NaNExp, ""));
+                                       recObj.oy = parseFloat(y.replace(_NaNExp, ""));
+                               }
+                               return x + " " + y + ((a.length > 2) ? " " + a[2] : "");
+                       },
+
+                       /**
+                        * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!)
+                        * @param {(number|string)} e End value which is typically a string, but could be a number
+                        * @param {(number|string)} b Beginning value which is typically a string but could be a number
+                        * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
+                        */
+                       _parseChange = function(e, b) {
+                               return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
+                       },
+
+                       /**
+                        * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
+                        * @param {Object} v Value to be parsed
+                        * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
+                        * @return {number} Parsed value
+                        */
+                       _parseVal = function(v, d) {
+                               return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) + d : parseFloat(v);
+                       },
+
+                       /**
+                        * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly.
+                        * @param {Object} v Value to be parsed
+                        * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
+                        * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY"
+                        * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation.
+                        * @return {number} parsed angle in radians
+                        */
+                       _parseAngle = function(v, d, p, directionalEnd) {
+                               var min = 0.000001,
+                                       cap, split, dif, result;
+                               if (v == null) {
+                                       result = d;
+                               } else if (typeof(v) === "number") {
+                                       result = v * _DEG2RAD;
+                               } else {
+                                       cap = Math.PI * 2;
+                                       split = v.split("_");
+                                       dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? _DEG2RAD : 1) - ((v.charAt(1) === "=") ? 0 : d);
+                                       if (split.length) {
+                                               if (directionalEnd) {
+                                                       directionalEnd[p] = d + dif;
+                                               }
+                                               if (v.indexOf("short") !== -1) {
+                                                       dif = dif % cap;
+                                                       if (dif !== dif % (cap / 2)) {
+                                                               dif = (dif < 0) ? dif + cap : dif - cap;
+                                                       }
+                                               }
+                                               if (v.indexOf("_cw") !== -1 && dif < 0) {
+                                                       dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               } else if (v.indexOf("ccw") !== -1 && dif > 0) {
+                                                       dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               }
+                                       }
+                                       result = d + dif;
+                               }
+                               if (result < min && result > -min) {
+                                       result = 0;
+                               }
+                               return result;
+                       },
+
+                       _colorLookup = {aqua:[0,255,255],
+                               lime:[0,255,0],
+                               silver:[192,192,192],
+                               black:[0,0,0],
+                               maroon:[128,0,0],
+                               teal:[0,128,128],
+                               blue:[0,0,255],
+                               navy:[0,0,128],
+                               white:[255,255,255],
+                               fuchsia:[255,0,255],
+                               olive:[128,128,0],
+                               yellow:[255,255,0],
+                               orange:[255,165,0],
+                               gray:[128,128,128],
+                               purple:[128,0,128],
+                               green:[0,128,0],
+                               red:[255,0,0],
+                               pink:[255,192,203],
+                               cyan:[0,255,255],
+                               transparent:[255,255,255,0]},
+
+                       _hue = function(h, m1, m2) {
+                               h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
+                               return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
+                       },
+
+                       /**
+                        * @private Parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course)
+                        * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc.
+                        * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order.
+                        */
+                       _parseColor = function(v) {
+                               var c1, c2, c3, h, s, l;
+                               if (!v || v === "") {
+                                       return _colorLookup.black;
+                               }
+                               if (typeof(v) === "number") {
+                                       return [v >> 16, (v >> 8) & 255, v & 255];
+                               }
+                               if (v.charAt(v.length - 1) === ",") { //sometimes a trailing commma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.
+                                       v = v.substr(0, v.length - 1);
+                               }
+                               if (_colorLookup[v]) {
+                                       return _colorLookup[v];
+                               }
+                               if (v.charAt(0) === "#") {
+                                       if (v.length === 4) { //for shorthand like #9F0
+                                               c1 = v.charAt(1),
+                                               c2 = v.charAt(2),
+                                               c3 = v.charAt(3);
+                                               v = "#" + c1 + c1 + c2 + c2 + c3 + c3;
+                                       }
+                                       v = parseInt(v.substr(1), 16);
+                                       return [v >> 16, (v >> 8) & 255, v & 255];
+                               }
+                               if (v.substr(0, 3) === "hsl") {
+                                       v = v.match(_numExp);
+                                       h = (Number(v[0]) % 360) / 360;
+                                       s = Number(v[1]) / 100;
+                                       l = Number(v[2]) / 100;
+                                       c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
+                                       c1 = l * 2 - c2;
+                                       if (v.length > 3) {
+                                               v[3] = Number(v[3]);
+                                       }
+                                       v[0] = _hue(h + 1 / 3, c1, c2);
+                                       v[1] = _hue(h, c1, c2);
+                                       v[2] = _hue(h - 1 / 3, c1, c2);
+                                       return v;
+                               }
+                               v = v.match(_numExp) || _colorLookup.transparent;
+                               v[0] = Number(v[0]);
+                               v[1] = Number(v[1]);
+                               v[2] = Number(v[2]);
+                               if (v.length > 3) {
+                                       v[3] = Number(v[3]);
+                               }
+                               return v;
+                       },
+                       _colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.
+
+               for (p in _colorLookup) {
+                       _colorExp += "|" + p + "\\b";
+               }
+               _colorExp = new RegExp(_colorExp+")", "gi");
+
+               /**
+                * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned.
+                * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned.
+                * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't.
+                * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc.
+                * @return {Function} formatter function
+                */
+               var _getFormatter = function(dflt, clr, collapsible, multi) {
+                               if (dflt == null) {
+                                       return function(v) {return v;};
+                               }
+                               var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
+                                       dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
+                                       pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
+                                       sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
+                                       delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
+                                       numVals = dVals.length,
+                                       dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
+                                       formatter;
+                               if (!numVals) {
+                                       return function(v) {return v;};
+                               }
+                               if (clr) {
+                                       formatter = function(v) {
+                                               var color, vals, i, a;
+                                               if (typeof(v) === "number") {
+                                                       v += dSfx;
+                                               } else if (multi && _commasOutsideParenExp.test(v)) {
+                                                       a = v.replace(_commasOutsideParenExp, "|").split("|");
+                                                       for (i = 0; i < a.length; i++) {
+                                                               a[i] = formatter(a[i]);
+                                                       }
+                                                       return a.join(",");
+                                               }
+                                               color = (v.match(_colorExp) || [dColor])[0];
+                                               vals = v.split(color).join("").match(_valuesExp) || [];
+                                               i = vals.length;
+                                               if (numVals > i--) {
+                                                       while (++i < numVals) {
+                                                               vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
+                                                       }
+                                               }
+                                               return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
+                                       };
+                                       return formatter;
+
+                               }
+                               formatter = function(v) {
+                                       var vals, a, i;
+                                       if (typeof(v) === "number") {
+                                               v += dSfx;
+                                       } else if (multi && _commasOutsideParenExp.test(v)) {
+                                               a = v.replace(_commasOutsideParenExp, "|").split("|");
+                                               for (i = 0; i < a.length; i++) {
+                                                       a[i] = formatter(a[i]);
+                                               }
+                                               return a.join(",");
+                                       }
+                                       vals = v.match(_valuesExp) || [];
+                                       i = vals.length;
+                                       if (numVals > i--) {
+                                               while (++i < numVals) {
+                                                       vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
+                                               }
+                                       }
+                                       return pfx + vals.join(delim) + sfx;
+                               };
+                               return formatter;
+                       },
+
+                       /**
+                        * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges.
+                        * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
+                        * @return {Function} a formatter function
+                        */
+                       _getEdgeParser = function(props) {
+                               props = props.split(",");
+                               return function(t, e, p, cssp, pt, plugin, vars) {
+                                       var a = (e + "").split(" "),
+                                               i;
+                                       vars = {};
+                                       for (i = 0; i < 4; i++) {
+                                               vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
+                                       }
+                                       return cssp.parse(t, vars, pt, plugin);
+                               };
+                       },
+
+                       //@private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens  which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color.
+                       _setPluginRatio = _internals._setPluginRatio = function(v) {
+                               this.plugin.setRatio(v);
+                               var d = this.data,
+                                       proxy = d.proxy,
+                                       mpt = d.firstMPT,
+                                       min = 0.000001,
+                                       val, pt, i, str;
+                               while (mpt) {
+                                       val = proxy[mpt.v];
+                                       if (mpt.r) {
+                                               val = (val > 0) ? (val + 0.5) | 0 : (val - 0.5) | 0;
+                                       } else if (val < min && val > -min) {
+                                               val = 0;
+                                       }
+                                       mpt.t[mpt.p] = val;
+                                       mpt = mpt._next;
+                               }
+                               if (d.autoRotate) {
+                                       d.autoRotate.rotation = proxy.rotation;
+                               }
+                               //at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method.
+                               if (v === 1) {
+                                       mpt = d.firstMPT;
+                                       while (mpt) {
+                                               pt = mpt.t;
+                                               if (!pt.type) {
+                                                       pt.e = pt.s + pt.xs0;
+                                               } else if (pt.type === 1) {
+                                                       str = pt.xs0 + pt.s + pt.xs1;
+                                                       for (i = 1; i < pt.l; i++) {
+                                                               str += pt["xn"+i] + pt["xs"+(i+1)];
+                                                       }
+                                                       pt.e = str;
+                                               }
+                                               mpt = mpt._next;
+                                       }
+                               }
+                       },
+
+                       /**
+                        * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value.
+                        * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
+                        * @param {!string} p property name
+                        * @param {(number|string|object)} v value
+                        * @param {MiniPropTween=} next next MiniPropTween in the linked list
+                        * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
+                        */
+                       MiniPropTween = function(t, p, v, next, r) {
+                               this.t = t;
+                               this.p = p;
+                               this.v = v;
+                               this.r = r;
+                               if (next) {
+                                       next._prev = this;
+                                       this._next = next;
+                               }
+                       },
+
+                       /**
+                        * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be rounded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element.
+                        * This method returns an object that has the following properties:
+                        *  - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin.  This is what we feed to the external _onInitTween() as the target
+                        *  - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values
+                        *  - firstMPT: the first MiniPropTween in the linked list
+                        *  - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter.
+                        * @param {!Object} t target object to be tweened
+                        * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
+                        * @param {!CSSPlugin} cssp The CSSPlugin instance
+                        * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
+                        * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
+                        * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter.
+                        * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
+                        */
+                       _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
+                               var bpt = pt,
+                                       start = {},
+                                       end = {},
+                                       transform = cssp._transform,
+                                       oldForce = _forcePT,
+                                       i, p, xp, mpt, firstPT;
+                               cssp._transform = null;
+                               _forcePT = vars;
+                               pt = firstPT = cssp.parse(t, vars, pt, plugin);
+                               _forcePT = oldForce;
+                               //break off from the linked list so the new ones are isolated.
+                               if (shallow) {
+                                       cssp._transform = transform;
+                                       if (bpt) {
+                                               bpt._prev = null;
+                                               if (bpt._prev) {
+                                                       bpt._prev._next = null;
+                                               }
+                                       }
+                               }
+                               while (pt && pt !== bpt) {
+                                       if (pt.type <= 1) {
+                                               p = pt.p;
+                                               end[p] = pt.s + pt.c;
+                                               start[p] = pt.s;
+                                               if (!shallow) {
+                                                       mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
+                                                       pt.c = 0;
+                                               }
+                                               if (pt.type === 1) {
+                                                       i = pt.l;
+                                                       while (--i > 0) {
+                                                               xp = "xn" + i;
+                                                               p = pt.p + "_" + xp;
+                                                               end[p] = pt.data[xp];
+                                                               start[p] = pt[xp];
+                                                               if (!shallow) {
+                                                                       mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       pt = pt._next;
+                               }
+                               return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
+                       },
+
+
+
+                       /**
+                        * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory.
+                        * CSSPropTweens have the following optional properties as well (not defined through the constructor):
+                        *  - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc.
+                        *  - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list)
+                        *  - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subtweens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request.
+                        *  - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target.
+                        *  - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible.
+                        * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
+                        * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
+                        * @param {number} s Starting numeric value
+                        * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95.
+                        * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it.
+                        * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update.
+                        * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip"
+                        * @param {boolean=} r If true, the value(s) should be rounded
+                        * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
+                        * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues.
+                        * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues.
+                        */
+                       CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
+                               this.t = t; //target
+                               this.p = p; //property
+                               this.s = s; //starting value
+                               this.c = c; //change value
+                               this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at)
+                               if (!(t instanceof CSSPropTween)) {
+                                       _overwriteProps.push(this.n);
+                               }
+                               this.r = r; //round (boolean)
+                               this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work
+                               if (pr) {
+                                       this.pr = pr;
+                                       _hasPriority = true;
+                               }
+                               this.b = (b === undefined) ? s : b;
+                               this.e = (e === undefined) ? s + c : e;
+                               if (next) {
+                                       this._next = next;
+                                       next._prev = this;
+                               }
+                       },
+
+                       /**
+                        * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
+                        * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
+                        * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio().
+                        * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method.
+                        *
+                        * @param {!Object} t Target whose property will be tweened
+                        * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
+                        * @param {string} b Beginning value
+                        * @param {string} e Ending value
+                        * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization)
+                        * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match
+                        * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
+                        * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
+                        * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300}
+                        * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here.
+                        * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
+                        */
+                       _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
+                               //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
+                               b = b || dflt || "";
+                               pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
+                               e += ""; //ensures it's a string
+                               var ba = b.split(", ").join(",").split(" "), //beginning array
+                                       ea = e.split(", ").join(",").split(" "), //ending array
+                                       l = ba.length,
+                                       autoRound = (_autoRound !== false),
+                                       i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str;
+                               if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
+                                       ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
+                                       ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
+                                       l = ba.length;
+                               }
+                               if (l !== ea.length) {
+                                       //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
+                                       ba = (dflt || "").split(" ");
+                                       l = ba.length;
+                               }
+                               pt.plugin = plugin;
+                               pt.setRatio = setRatio;
+                               for (i = 0; i < l; i++) {
+                                       bv = ba[i];
+                                       ev = ea[i];
+                                       bn = parseFloat(bv);
+
+                                       //if the value begins with a number (most common). It's fine if it has a suffix like px
+                                       if (bn || bn === 0) {
+                                               pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
+
+                                       //if the value is a color
+                                       } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) {
+                                               str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
+                                               bv = _parseColor(bv);
+                                               ev = _parseColor(ev);
+                                               rgba = (bv.length + ev.length > 6);
+                                               if (rgba && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color
+                                                       pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
+                                                       pt.e = pt.e.split(ea[i]).join("transparent");
+                                               } else {
+                                                       if (!_supportsOpacity) { //old versions of IE don't support rgba().
+                                                               rgba = false;
+                                                       }
+                                                       pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
+                                                               .appendXtra("", bv[1], ev[1] - bv[1], ",", true)
+                                                               .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true);
+                                                       if (rgba) {
+                                                               bv = (bv.length < 4) ? 1 : bv[3];
+                                                               pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
+                                                       }
+                                               }
+
+                                       } else {
+                                               bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
+
+                                               //if no number is found, treat it as a non-tweening value and just append the string to the current xs.
+                                               if (!bnums) {
+                                                       pt["xs" + pt.l] += pt.l ? " " + bv : bv;
+
+                                               //loop through all the numbers that are found and construct the extra values on the pt.
+                                               } else {
+                                                       enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5
+                                                       if (!enums || enums.length !== bnums.length) {
+                                                               //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
+                                                               return pt;
+                                                       }
+                                                       ni = 0;
+                                                       for (xi = 0; xi < bnums.length; xi++) {
+                                                               cv = bnums[xi];
+                                                               temp = bv.indexOf(cv, ni);
+                                                               pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
+                                                               ni = temp + cv.length;
+                                                       }
+                                                       pt["xs" + pt.l] += bv.substr(ni);
+                                               }
+                                       }
+                               }
+                               //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
+                               if (e.indexOf("=") !== -1) if (pt.data) {
+                                       str = pt.xs0 + pt.data.s;
+                                       for (i = 1; i < pt.l; i++) {
+                                               str += pt["xs" + i] + pt.data["xn" + i];
+                                       }
+                                       pt.e = str + pt["xs" + i];
+                               }
+                               if (!pt.l) {
+                                       pt.type = -1;
+                                       pt.xs0 = pt.e;
+                               }
+                               return pt.xfirst || pt;
+                       },
+                       i = 9;
+
+
+               p = CSSPropTween.prototype;
+               p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
+               while (--i > 0) {
+                       p["xn" + i] = 0;
+                       p["xs" + i] = "";
+               }
+               p.xs0 = "";
+               p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
+
+
+               /**
+                * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this:
+                * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
+                * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
+                * @param {string=} pfx Prefix (if any)
+                * @param {!number} s Starting value
+                * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95.
+                * @param {string=} sfx Suffix (if any)
+                * @param {boolean=} r Round (if true).
+                * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space.
+                * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
+                */
+               p.appendXtra = function(pfx, s, c, sfx, r, pad) {
+                       var pt = this,
+                               l = pt.l;
+                       pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
+                       if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value!
+                               pt["xs" + l] += s + (sfx || "");
+                               return pt;
+                       }
+                       pt.l++;
+                       pt.type = pt.setRatio ? 2 : 1;
+                       pt["xs" + pt.l] = sfx || "";
+                       if (l > 0) {
+                               pt.data["xn" + l] = s + c;
+                               pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
+                               pt["xn" + l] = s;
+                               if (!pt.plugin) {
+                                       pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
+                                       pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly.
+                               }
+                               return pt;
+                       }
+                       pt.data = {s:s + c};
+                       pt.rxp = {};
+                       pt.s = s;
+                       pt.c = c;
+                       pt.r = r;
+                       return pt;
+               };
+
+               /**
+                * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly.
+                * @param {!string} p Property name (like "boxShadow" or "throwProps")
+                * @param {Object=} options An object containing any of the following configuration options:
+                *                      - defaultValue: the default value
+                *                      - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker)
+                *                      - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.)
+                *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
+                *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
+                *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
+                *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
+                *                      - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc.
+                *                      - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default).
+                */
+               var SpecialProp = function(p, options) {
+                               options = options || {};
+                               this.p = options.prefix ? _checkPropPrefix(p) || p : p;
+                               _specialProps[p] = _specialProps[this.p] = this;
+                               this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
+                               if (options.parser) {
+                                       this.parse = options.parser;
+                               }
+                               this.clrs = options.color;
+                               this.multi = options.multi;
+                               this.keyword = options.keyword;
+                               this.dflt = options.defaultValue;
+                               this.pr = options.priority || 0;
+                       },
+
+                       //shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin.
+                       _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
+                               if (typeof(options) !== "object") {
+                                       options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
+                               }
+                               var a = p.split(","),
+                                       d = options.defaultValue,
+                                       i, temp;
+                               defaults = defaults || [d];
+                               for (i = 0; i < a.length; i++) {
+                                       options.prefix = (i === 0 && options.prefix);
+                                       options.defaultValue = defaults[i] || d;
+                                       temp = new SpecialProp(a[i], options);
+                               }
+                       },
+
+                       //creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file.
+                       _registerPluginProp = function(p) {
+                               if (!_specialProps[p]) {
+                                       var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
+                                       _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                                               var pluginClass = (window.GreenSockGlobals || window).com.greensock.plugins[pluginName];
+                                               if (!pluginClass) {
+                                                       _log("Error: " + pluginName + " js file not loaded.");
+                                                       return pt;
+                                               }
+                                               pluginClass._cssRegister();
+                                               return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
+                                       }});
+                               }
+                       };
+
+
+               p = SpecialProp.prototype;
+
+               /**
+                * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxShadow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list)
+                * @param {!Object} t target element
+                * @param {(string|number|object)} b beginning value
+                * @param {(string|number|object)} e ending (destination) value
+                * @param {CSSPropTween=} pt next CSSPropTween in the linked list
+                * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
+                * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
+                * @return {CSSPropTween=} First CSSPropTween in the linked list
+                */
+               p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
+                       var kwd = this.keyword,
+                               i, ba, ea, l, bi, ei;
+                       //if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example)
+                       if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
+                               ba = b.replace(_commasOutsideParenExp, "|").split("|");
+                               ea = e.replace(_commasOutsideParenExp, "|").split("|");
+                       } else if (kwd) {
+                               ba = [b];
+                               ea = [e];
+                       }
+                       if (ea) {
+                               l = (ea.length > ba.length) ? ea.length : ba.length;
+                               for (i = 0; i < l; i++) {
+                                       b = ba[i] = ba[i] || this.dflt;
+                                       e = ea[i] = ea[i] || this.dflt;
+                                       if (kwd) {
+                                               bi = b.indexOf(kwd);
+                                               ei = e.indexOf(kwd);
+                                               if (bi !== ei) {
+                                                       e = (ei === -1) ? ea : ba;
+                                                       e[i] += " " + kwd;
+                                               }
+                                       }
+                               }
+                               b = ba.join(", ");
+                               e = ea.join(", ");
+                       }
+                       return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
+               };
+
+               /**
+                * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call:
+                * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
+                * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that).
+                * @param {!Object) t Target object whose property is being tweened
+                * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
+                * @param {!string} p Property name
+                * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
+                * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
+                * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
+                * @param {Object=} vars Original vars object that contains the data for parsing.
+                * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
+                */
+               p.parse = function(t, e, p, cssp, pt, plugin, vars) {
+                       return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
+               };
+
+               /**
+                * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters:
+                *  1) Target object whose property should be tweened (typically a DOM element)
+                *  2) The end/destination value (could be a string, number, object, or whatever you want)
+                *  3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration)
+                *
+                * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example:
+                *
+                * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
+                *      var start = target.style.width;
+                *      return function(ratio) {
+                *              target.style.width = (start + value * ratio) + "px";
+                *              console.log("set width to " + target.style.width);
+                *          }
+                * }, 0);
+                *
+                * Then, when I do this tween, it will trigger my special property:
+                *
+                * TweenLite.to(element, 1, {css:{myCustomProp:100}});
+                *
+                * In the example, of course, we're just changing the width, but you can do anything you want.
+                *
+                * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}})
+                * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function.
+                * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones.
+                */
+               CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
+                       _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                               var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
+                               rv.plugin = plugin;
+                               rv.setRatio = onInitTween(t, e, cssp._tween, p);
+                               return rv;
+                       }, priority:priority});
+               };
+               
+               
+
+
+
+
+
+
+               //transform-related methods and properties
+               var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,rotation,rotationX,rotationY,perspective").split(","),
+                       _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
+                       _transformPropCSS = _prefixCSS + "transform",
+                       _transformOriginProp = _checkPropPrefix("transformOrigin"),
+                       _supports3D = (_checkPropPrefix("perspective") !== null),
+
+                       /**
+                        * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
+                        * @param {!Object} t target element
+                        * @param {Object=} cs computed style object (optional)
+                        * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...}
+                        * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style)
+                        * @return {object} object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
+                        */
+                       _getTransform = function(t, cs, rec, parse) {
+                               if (t._gsTransform && rec && !parse) {
+                                       return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things.
+                               }
+                               var tm = rec ? t._gsTransform || {skewY:0} : {skewY:0},
+                                       invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
+                                       min = 0.00002,
+                                       rnd = 100000,
+                                       minPI = -Math.PI + 0.0001,
+                                       maxPI = Math.PI - 0.0001,
+                                       zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
+                                       s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS;
+                               if (_transformProp) {
+                                       s = _getStyle(t, _transformPropCSS, cs, true);
+                               } else if (t.currentStyle) {
+                                       //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
+                                       s = t.currentStyle.filter.match(_ieGetMatrixExp);
+                                       s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
+                               }
+                               //split the matrix values out into an array (m for matrix)
+                               m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
+                               i = m.length;
+                               while (--i > -1) {
+                                       n = Number(m[i]);
+                                       m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
+                               }
+                               if (m.length === 16) {
+
+                                       //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
+                                       var a13 = m[8], a23 = m[9], a33 = m[10],
+                                               a14 = m[12], a24 = m[13], a34 = m[14];
+
+                                       //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
+                                       if (tm.zOrigin) {
+                                               a34 = -tm.zOrigin;
+                                               a14 = a13*a34-m[12];
+                                               a24 = a23*a34-m[13];
+                                               a34 = a33*a34+tm.zOrigin-m[14];
+                                       }
+
+                                       //only parse from the matrix if we MUST because not only is it usually unnecessary due to the fact that we store the values in the _gsTransform object, but also because it's impossible to accurately interpret rotationX, rotationY, and rotationZ if all are applied, so it's much better to rely on what we store. However, we must parse the first time that an object is tweened. We also assume that if the position has changed, the user must have done some styling changes outside of CSSPlugin, thus we force a parse in that scenario.
+                                       if (!rec || parse || tm.rotationX == null) {
+                                               var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
+                                                       a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
+                                                       a43 = m[11],
+                                                       angle = tm.rotationX = Math.atan2(a32, a33),
+                                                       xFlip = (angle < minPI || angle > maxPI),
+                                                       t1, t2, t3, cos, sin, yFlip, zFlip;
+                                               //rotationX
+                                               if (angle) {
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       t1 = a12*cos+a13*sin;
+                                                       t2 = a22*cos+a23*sin;
+                                                       t3 = a32*cos+a33*sin;
+                                                       //t4 = a42*cos+a43*sin;
+                                                       a13 = a12*-sin+a13*cos;
+                                                       a23 = a22*-sin+a23*cos;
+                                                       a33 = a32*-sin+a33*cos;
+                                                       a43 = a42*-sin+a43*cos;
+                                                       a12 = t1;
+                                                       a22 = t2;
+                                                       a32 = t3;
+                                                       //a42 = t4;
+                                               }
+                                               //rotationY
+                                               angle = tm.rotationY = Math.atan2(a13, a11);
+                                               if (angle) {
+                                                       yFlip = (angle < minPI || angle > maxPI);
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       t1 = a11*cos-a13*sin;
+                                                       t2 = a21*cos-a23*sin;
+                                                       t3 = a31*cos-a33*sin;
+                                                       //t4 = a41*cos-a43*sin;
+                                                       //a13 = a11*sin+a13*cos;
+                                                       a23 = a21*sin+a23*cos;
+                                                       a33 = a31*sin+a33*cos;
+                                                       a43 = a41*sin+a43*cos;
+                                                       a11 = t1;
+                                                       a21 = t2;
+                                                       a31 = t3;
+                                                       //a41 = t4;
+                                               }
+                                               //rotationZ
+                                               angle = tm.rotation = Math.atan2(a21, a22);
+                                               if (angle) {
+                                                       zFlip = (angle < minPI || angle > maxPI);
+                                                       cos = Math.cos(-angle);
+                                                       sin = Math.sin(-angle);
+                                                       a11 = a11*cos+a12*sin;
+                                                       t2 = a21*cos+a22*sin;
+                                                       a22 = a21*-sin+a22*cos;
+                                                       a32 = a31*-sin+a32*cos;
+                                                       a21 = t2;
+                                               }
+
+                                               if (zFlip && xFlip) {
+                                                       tm.rotation = tm.rotationX = 0;
+                                               } else if (zFlip && yFlip) {
+                                                       tm.rotation = tm.rotationY = 0;
+                                               } else if (yFlip && xFlip) {
+                                                       tm.rotationY = tm.rotationX = 0;
+                                               }
+
+                                               tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
+                                               tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
+                                               tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
+                                               tm.skewX = 0;
+                                               tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
+                                               tm.x = a14;
+                                               tm.y = a24;
+                                               tm.z = a34;
+                                       }
+
+                               } else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those.
+                                       var k = (m.length >= 6),
+                                               a = k ? m[0] : 1,
+                                               b = m[1] || 0,
+                                               c = m[2] || 0,
+                                               d = k ? m[3] : 1;
+                                       tm.x = m[4] || 0;
+                                       tm.y = m[5] || 0;
+                                       scaleX = Math.sqrt(a * a + b * b);
+                                       scaleY = Math.sqrt(d * d + c * c);
+                                       rotation = (a || b) ? Math.atan2(b, a) : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
+                                       skewX = (c || d) ? Math.atan2(c, d) + rotation : tm.skewX || 0;
+                                       difX = scaleX - Math.abs(tm.scaleX || 0);
+                                       difY = scaleY - Math.abs(tm.scaleY || 0);
+                                       if (Math.abs(skewX) > Math.PI / 2 && Math.abs(skewX) < Math.PI * 1.5) {
+                                               if (invX) {
+                                                       scaleX *= -1;
+                                                       skewX += (rotation <= 0) ? Math.PI : -Math.PI;
+                                                       rotation += (rotation <= 0) ? Math.PI : -Math.PI;
+                                               } else {
+                                                       scaleY *= -1;
+                                                       skewX += (skewX <= 0) ? Math.PI : -Math.PI;
+                                               }
+                                       }
+                                       difR = (rotation - tm.rotation) % Math.PI; //note: matching ranges would be very small (+/-0.0001) or very close to Math.PI (+/-3.1415).
+                                       difS = (skewX - tm.skewX) % Math.PI;
+                                       //if there's already a recorded _gsTransform in place for the target, we should leave those values in place unless we know things changed for sure (beyond a super small amount). This gets around ambiguous interpretations, like if scaleX and scaleY are both -1, the matrix would be the same as if the rotation was 180 with normal scaleX/scaleY. If the user tweened to particular values, those must be prioritized to ensure animation is consistent.
+                                       if (tm.skewX === undefined || difX > min || difX < -min || difY > min || difY < -min || (difR > minPI && difR < maxPI && (difR * rnd) | 0 !== 0) || (difS > minPI && difS < maxPI && (difS * rnd) | 0 !== 0)) {
+                                               tm.scaleX = scaleX;
+                                               tm.scaleY = scaleY;
+                                               tm.rotation = rotation;
+                                               tm.skewX = skewX;
+                                       }
+                                       if (_supports3D) {
+                                               tm.rotationX = tm.rotationY = tm.z = 0;
+                                               tm.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
+                                               tm.scaleZ = 1;
+                                       }
+                               }
+                               tm.zOrigin = zOrigin;
+
+                               //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate.
+                               for (i in tm) {
+                                       if (tm[i] < min) if (tm[i] > -min) {
+                                               tm[i] = 0;
+                                       }
+                               }
+                               //DEBUG: _log("parsed rotation: "+(tm.rotationX*_RAD2DEG)+", "+(tm.rotationY*_RAD2DEG)+", "+(tm.rotation*_RAD2DEG)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective);
+                               if (rec) {
+                                       t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
+                               }
+                               return tm;
+                       },
+                       //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
+                       _setIETransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       ang = -t.rotation,
+                                       skew = ang + t.skewX,
+                                       rnd = 100000,
+                                       a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
+                                       b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
+                                       c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
+                                       d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
+                                       style = this.t.style,
+                                       cs = this.t.currentStyle,
+                                       filters, val;
+                               if (!cs) {
+                                       return;
+                               }
+                               val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted)
+                               b = -c;
+                               c = -val;
+                               filters = cs.filter;
+                               style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
+                               var w = this.t.offsetWidth,
+                                       h = this.t.offsetHeight,
+                                       clip = (cs.position !== "absolute"),
+                                       m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
+                                       ox = t.x,
+                                       oy = t.y,
+                                       dx, dy;
+
+                               //if transformOrigin is being used, adjust the offset x and y
+                               if (t.ox != null) {
+                                       dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
+                                       dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
+                                       ox += dx - (dx * a + dy * b);
+                                       oy += dy - (dx * c + dy * d);
+                               }
+
+                               if (!clip) {
+                                       var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom
+                                               marg, prop, dif;
+                                       dx = t.ieOffsetX || 0;
+                                       dy = t.ieOffsetY || 0;
+                                       t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
+                                       t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
+                                       for (i = 0; i < 4; i++) {
+                                               prop = _margins[i];
+                                               marg = cs[prop];
+                                               //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
+                                               val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
+                                               if (val !== t[prop]) {
+                                                       dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible.
+                                               } else {
+                                                       dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
+                                               }
+                                               style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
+                                       }
+                                       m += ", sizingMethod='auto expand')";
+                               } else {
+                                       dx = (w / 2);
+                                       dy = (h / 2);
+                                       //translate to ensure that transformations occur around the correct origin (default is center).
+                                       m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
+                               }
+                               if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
+                                       style.filter = filters.replace(_ieSetMatrixExp, m);
+                               } else {
+                                       style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha.
+                               }
+
+                               //at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance.
+                               if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(") === -1) {
+                                       style.removeAttribute("filter");
+                               }
+                       },
+                       _set3DTransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       style = this.t.style,
+                                       perspective = t.perspective,
+                                       a11 = t.scaleX, a12 = 0, a13 = 0, a14 = 0,
+                                       a21 = 0, a22 = t.scaleY, a23 = 0, a24 = 0,
+                                       a31 = 0, a32 = 0, a33 = t.scaleZ, a34 = 0,
+                                       a41 = 0, a42 = 0, a43 = (perspective) ? -1 / perspective : 0,
+                                       angle = t.rotation,
+                                       zOrigin = t.zOrigin,
+                                       rnd = 100000,
+                                       cos, sin, t1, t2, t3, t4, ffProp, n, sfx;
+
+                               if (_isFirefox) { //Firefox has a bug that causes 3D elements to randomly disappear during animation unless a repaint is forced. One way to do this is change "top" or "bottom" by 0.05 which is imperceptible, so we go back and forth. Another way is to change the display to "none", read the clientTop, and then revert the display but that is much slower.
+                                       ffProp = style.top ? "top" : style.bottom ? "bottom" : parseFloat(_getStyle(this.t, "top", null, false)) ? "bottom" : "top";
+                                       t1 = _getStyle(this.t, ffProp, null, false);
+                                       n = parseFloat(t1) || 0;
+                                       sfx = t1.substr((n + "").length) || "px";
+                                       t._ffFix = !t._ffFix;
+                                       style[ffProp] = (t._ffFix ? n + 0.05 : n - 0.05) + sfx;
+                               }
+
+                               if (angle || t.skewX) {
+                                       t1 = a11*Math.cos(angle);
+                                       t2 = a22*Math.sin(angle);
+                                       angle -= t.skewX;
+                                       a12 = a11*-Math.sin(angle);
+                                       a22 = a22*Math.cos(angle);
+                                       a11 = t1;
+                                       a21 = t2;
+                               } else if (!t.rotationY && !t.rotationX && a33 === 1) { //if we're only translating and/or 2D scaling, this is faster...
+                                       style[_transformProp] = "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px)" + ((a11 !== 1 || a22 !== 1) ? " scale(" + a11 + "," + a22 + ")" : "");
+                                       return;
+                               }
+                               angle = t.rotationY;
+                               if (angle) {
+                                       cos = Math.cos(angle);
+                                       sin = Math.sin(angle);
+                                       t1 = a11*cos;
+                                       t2 = a21*cos;
+                                       t3 = a33*-sin;
+                                       t4 = a43*-sin;
+                                       a13 = a11*sin;
+                                       a23 = a21*sin;
+                                       a33 = a33*cos;
+                                       a43 *= cos;
+                                       a11 = t1;
+                                       a21 = t2;
+                                       a31 = t3;
+                                       a41 = t4;
+                               }
+                               angle = t.rotationX;
+                               if (angle) {
+                                       cos = Math.cos(angle);
+                                       sin = Math.sin(angle);
+                                       t1 = a12*cos+a13*sin;
+                                       t2 = a22*cos+a23*sin;
+                                       t3 = a32*cos+a33*sin;
+                                       t4 = a42*cos+a43*sin;
+                                       a13 = a12*-sin+a13*cos;
+                                       a23 = a22*-sin+a23*cos;
+                                       a33 = a32*-sin+a33*cos;
+                                       a43 = a42*-sin+a43*cos;
+                                       a12 = t1;
+                                       a22 = t2;
+                                       a32 = t3;
+                                       a42 = t4;
+                               }
+                               if (zOrigin) {
+                                       a34 -= zOrigin;
+                                       a14 = a13*a34;
+                                       a24 = a23*a34;
+                                       a34 = a33*a34+zOrigin;
+                               }
+                               //we round the x, y, and z slightly differently to allow even larger values.
+                               a14 = (t1 = (a14 += t.x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14;
+                               a24 = (t1 = (a24 += t.y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24;
+                               a34 = (t1 = (a34 += t.z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34;
+                               style[_transformProp] = "matrix3d(" + [ (((a11 * rnd) | 0) / rnd), (((a21 * rnd) | 0) / rnd), (((a31 * rnd) | 0) / rnd), (((a41 * rnd) | 0) / rnd), (((a12 * rnd) | 0) / rnd), (((a22 * rnd) | 0) / rnd), (((a32 * rnd) | 0) / rnd), (((a42 * rnd) | 0) / rnd), (((a13 * rnd) | 0) / rnd), (((a23 * rnd) | 0) / rnd), (((a33 * rnd) | 0) / rnd), (((a43 * rnd) | 0) / rnd), a14, a24, a34, (perspective ? (1 + (-a34 / perspective)) : 1) ].join(",") + ")";
+                       },
+                       _set2DTransformRatio = function(v) {
+                               var t = this.data, //refers to the element's _gsTransform object
+                                       targ = this.t,
+                                       style = targ.style,
+                                       ffProp, t1, n, sfx, ang, skew, rnd, sx, sy;
+                               if (_isFirefox) { //Firefox has a bug that causes elements to randomly disappear during animation unless a repaint is forced. One way to do this is change "top" or "bottom" by 0.05 which is imperceptible, so we go back and forth. Another way is to change the display to "none", read the clientTop, and then revert the display but that is much slower.
+                                       ffProp = style.top ? "top" : style.bottom ? "bottom" : parseFloat(_getStyle(targ, "top", null, false)) ? "bottom" : "top";
+                                       t1 = _getStyle(targ, ffProp, null, false);
+                                       n = parseFloat(t1) || 0;
+                                       sfx = t1.substr((n + "").length) || "px";
+                                       t._ffFix = !t._ffFix;
+                                       style[ffProp] = (t._ffFix ? n + 0.05 : n - 0.05) + sfx;
+                               }
+                               if (!t.rotation && !t.skewX) {
+                                       style[_transformProp] = "matrix(" + t.scaleX + ",0,0," + t.scaleY + "," + t.x + "," + t.y + ")";
+                               } else {
+                                       ang = t.rotation;
+                                       skew = ang - t.skewX;
+                                       rnd = 100000;
+                                       sx = t.scaleX * rnd;
+                                       sy = t.scaleY * rnd;
+                                       //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places.
+                                       style[_transformProp] = "matrix(" + (((Math.cos(ang) * sx) | 0) / rnd) + "," + (((Math.sin(ang) * sx) | 0) / rnd) + "," + (((Math.sin(skew) * -sy) | 0) / rnd) + "," + (((Math.cos(skew) * sy) | 0) / rnd) + "," + t.x + "," + t.y + ")";
+                               }
+                       };
+
+               _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform", {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                       if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it.
+                       var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
+                               style = t.style,
+                               min = 0.000001,
+                               i = _transformProps.length,
+                               v = vars,
+                               endRotations = {},
+                               m2, skewY, copy, orig, has3D, hasChange, dr;
+
+                       if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
+                               copy = style.cssText;
+                               style[_transformProp] = v.transform;
+                               style.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
+                               m2 = _getTransform(t, null, false);
+                               style.cssText = copy;
+                       } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
+                               m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
+                                       scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
+                                       scaleZ:_parseVal((v.scaleZ != null) ? v.scaleZ : v.scale, m1.scaleZ),
+                                       x:_parseVal(v.x, m1.x),
+                                       y:_parseVal(v.y, m1.y),
+                                       z:_parseVal(v.z, m1.z),
+                                       perspective:_parseVal(v.transformPerspective, m1.perspective)};
+                               dr = v.directionalRotation;
+                               if (dr != null) {
+                                       if (typeof(dr) === "object") {
+                                               for (copy in dr) {
+                                                       v[copy] = dr[copy];
+                                               }
+                                       } else {
+                                               v.rotation = dr;
+                                       }
+                               }
+                               m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : (m1.rotation * _RAD2DEG), m1.rotation, "rotation", endRotations);
+                               if (_supports3D) {
+                                       m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : (m1.rotationX * _RAD2DEG) || 0, m1.rotationX, "rotationX", endRotations);
+                                       m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : (m1.rotationY * _RAD2DEG) || 0, m1.rotationY, "rotationY", endRotations);
+                               }
+                               m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
+
+                               //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
+                               m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
+                               if ((skewY = m2.skewY - m1.skewY)) {
+                                       m2.skewX += skewY;
+                                       m2.rotation += skewY;
+                               }
+                       }
+
+                       has3D = (m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
+                       if (!has3D && v.scale != null) {
+                               m2.scaleZ = 1; //no need to tween scaleZ.
+                       }
+
+                       while (--i > -1) {
+                               p = _transformProps[i];
+                               orig = m2[p] - m1[p];
+                               if (orig > min || orig < -min || _forcePT[p] != null) {
+                                       hasChange = true;
+                                       pt = new CSSPropTween(m1, p, m1[p], orig, pt);
+                                       if (p in endRotations) {
+                                               pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested
+                                       }
+                                       pt.xs0 = 0; //ensures the value stays numeric in setRatio()
+                                       pt.plugin = plugin;
+                                       cssp._overwriteProps.push(pt.n);
+                               }
+                       }
+
+                       orig = v.transformOrigin;
+                       if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
+                               if (_transformProp) {
+                                       hasChange = true;
+                                       orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
+                                       p = _transformOriginProp;
+                                       pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
+                                       pt.b = style[p];
+                                       pt.plugin = plugin;
+                                       if (_supports3D) {
+                                               copy = m1.zOrigin;
+                                               orig = orig.split(" ");
+                                               m1.zOrigin = ((orig.length > 2) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method.
+                                               pt.xs0 = pt.e = style[p] = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)!
+                                               pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here)
+                                               pt.b = copy;
+                                               pt.xs0 = pt.e = m1.zOrigin;
+                                       } else {
+                                               pt.xs0 = pt.e = style[p] = orig;
+                                       }
+
+                               //for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp).
+                               } else {
+                                       _parsePosition(orig + "", m1);
+                               }
+                       }
+
+                       if (hasChange) {
+                               cssp._transformType = (has3D || this._transformType === 3) ? 3 : 2; //quicker than calling cssp._enableTransforms();
+                       }
+                       return pt;
+               }, prefix:true});
+
+               _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
+
+               _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
+                       e = this.format(e);
+                       var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
+                               style = t.style,
+                               ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
+                       w = parseFloat(t.offsetWidth);
+                       h = parseFloat(t.offsetHeight);
+                       ea1 = e.split(" ");
+                       for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
+                               if (this.p.indexOf("border")) { //older browsers used a prefix
+                                       props[i] = _checkPropPrefix(props[i]);
+                               }
+                               bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
+                               if (bs.indexOf(" ") !== -1) {
+                                       bs2 = bs.split(" ");
+                                       bs = bs2[0];
+                                       bs2 = bs2[1];
+                               }
+                               es = es2 = ea1[i];
+                               bn = parseFloat(bs);
+                               bsfx = bs.substr((bn + "").length);
+                               rel = (es.charAt(1) === "=");
+                               if (rel) {
+                                       en = parseInt(es.charAt(0)+"1", 10);
+                                       es = es.substr(2);
+                                       en *= parseFloat(es);
+                                       esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
+                               } else {
+                                       en = parseFloat(es);
+                                       esfx = es.substr((en + "").length);
+                               }
+                               if (esfx === "") {
+                                       esfx = _suffixMap[p] || bsfx;
+                               }
+                               if (esfx !== bsfx) {
+                                       hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent.
+                                       vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
+                                       if (esfx === "%") {
+                                               bs = (hn / w * 100) + "%";
+                                               bs2 = (vn / h * 100) + "%";
+                                       } else if (esfx === "em") {
+                                               em = _convertToPixels(t, "borderLeft", 1, "em");
+                                               bs = (hn / em) + "em";
+                                               bs2 = (vn / em) + "em";
+                                       } else {
+                                               bs = hn + "px";
+                                               bs2 = vn + "px";
+                                       }
+                                       if (rel) {
+                                               es = (parseFloat(bs) + en) + esfx;
+                                               es2 = (parseFloat(bs2) + en) + esfx;
+                                       }
+                               }
+                               pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
+                       }
+                       return pt;
+               }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
+               _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
+                       var bp = "background-position",
+                               cs = (_cs || _getComputedStyle(t, null)),
+                               bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase
+                               es = this.format(e),
+                               ba, ea, i, pct, overlap, src;
+                       if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
+                               src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
+                               if (src && src !== "none") {
+                                       ba = bs.split(" ");
+                                       ea = es.split(" ");
+                                       _tempImg.setAttribute("src", src); //set the temp <img>'s src to the background-image so that we can measure its width/height
+                                       i = 2;
+                                       while (--i > -1) {
+                                               bs = ba[i];
+                                               pct = (bs.indexOf("%") !== -1);
+                                               if (pct !== (ea[i].indexOf("%") !== -1)) {
+                                                       overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
+                                                       ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
+                                               }
+                                       }
+                                       bs = ba.join(" ");
+                               }
+                       }
+                       return this.parseComplex(t.style, bs, es, pt, plugin);
+               }, formatter:_parsePosition});
+               _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
+               _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
+               _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
+               _registerComplexSpecialProp("transformStyle", {prefix:true});
+               _registerComplexSpecialProp("backfaceVisibility", {prefix:true});
+               _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
+               _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
+               _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
+                       var b, cs, delim;
+                       if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited.
+                               cs = t.currentStyle;
+                               delim = _ieVers < 8 ? " " : ",";
+                               b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
+                               e = this.format(e).split(",").join(delim);
+                       } else {
+                               b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
+                               e = this.format(e);
+                       }
+                       return this.parseComplex(t.style, b, e, pt, plugin);
+               }});
+               _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
+               _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
+               _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
+                               return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin);
+                       }, color:true, formatter:function(v) {
+                               var a = v.split(" ");
+                               return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
+                       }});
+               _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
+                       var s = t.style,
+                               prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
+                       return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
+               }});
+
+               //opacity-related
+               var _setIEOpacityRatio = function(v) {
+                               var t = this.t, //refers to the element's style property
+                                       filters = t.filter,
+                                       val = (this.s + this.c * v) | 0,
+                                       skip;
+                               if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters.
+                                       if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1) {
+                                               t.removeAttribute("filter");
+                                               skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check.
+                                       } else {
+                                               t.filter = filters.replace(_alphaFilterExp, "");
+                                               skip = true;
+                                       }
+                               }
+                               if (!skip) {
+                                       if (this.xn1) {
+                                               t.filter = filters = filters || "alpha(opacity=100)"; //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame.
+                                       }
+                                       if (filters.indexOf("opacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8)
+                                               t.filter += " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
+                                       } else {
+                                               t.filter = filters.replace(_opacityExp, "opacity=" + val);
+                                       }
+                               }
+                       };
+               _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
+                       var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
+                               style = t.style,
+                               vb;
+                       e = parseFloat(e);
+                       if (p === "autoAlpha") {
+                               vb = _getStyle(t, "visibility", _cs);
+                               if (b === 1 && vb === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience)
+                                       b = 0;
+                               }
+                               pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "visible" : "hidden"), ((e === 0) ? "hidden" : "visible"));
+                               pt.xs0 = "visible";
+                               cssp._overwriteProps.push(pt.n);
+                       }
+                       if (_supportsOpacity) {
+                               pt = new CSSPropTween(style, "opacity", b, e - b, pt);
+                       } else {
+                               pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
+                               pt.xn1 = (p === "autoAlpha") ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug.
+                               style.zoom = 1; //helps correct an IE issue.
+                               pt.type = 2;
+                               pt.b = "alpha(opacity=" + pt.s + ")";
+                               pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
+                               pt.data = t;
+                               pt.plugin = plugin;
+                               pt.setRatio = _setIEOpacityRatio;
+                       }
+                       return pt;
+               }});
+
+
+               var _removeProp = function(s, p) {
+                               if (p) {
+                                       if (s.removeProperty) {
+                                               s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
+                                       } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
+                                               s.removeAttribute(p);
+                                       }
+                               }
+                       },
+                       _setClassNameRatio = function(v) {
+                               this.t._gsClassPT = this;
+                               if (v === 1 || v === 0) {
+                                       this.t.className = (v === 0) ? this.b : this.e;
+                                       var mpt = this.data, //first MiniPropTween
+                                               s = this.t.style;
+                                       while (mpt) {
+                                               if (!mpt.v) {
+                                                       _removeProp(s, mpt.p);
+                                               } else {
+                                                       s[mpt.p] = mpt.v;
+                                               }
+                                               mpt = mpt._next;
+                                       }
+                                       if (v === 1 && this.t._gsClassPT === this) {
+                                               this.t._gsClassPT = null;
+                                       }
+                               } else if (this.t.className !== this.e) {
+                                       this.t.className = this.e;
+                               }
+                       };
+               _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
+                       var b = t.className,
+                               cssText = t.style.cssText,
+                               difData, bs, cnpt, cnptLookup, mpt;
+                       pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
+                       pt.setRatio = _setClassNameRatio;
+                       pt.pr = -11;
+                       _hasPriority = true;
+                       pt.b = b;
+                       bs = _getAllStyles(t, _cs);
+                       //if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfering that were there just for class-specific values)
+                       cnpt = t._gsClassPT;
+                       if (cnpt) {
+                               cnptLookup = {};
+                               mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned.
+                               while (mpt) {
+                                       cnptLookup[mpt.p] = 1;
+                                       mpt = mpt._next;
+                               }
+                               cnpt.setRatio(1);
+                       }
+                       t._gsClassPT = pt;
+                       pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
+                       if (cssp._tween._duration) { //if it's a zero-duration tween, there's no need to tween anything or parse the data. In fact, if we switch classes temporarily (which we must do for proper parsing) and the class has a transition applied, it could cause a quick flash to the end state and back again initially in some browsers.
+                               t.className = pt.e;
+                               difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
+                               t.className = b;
+                               pt.data = difData.firstMPT;
+                               t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
+                               pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
+                       }
+                       return pt;
+               }});
+
+
+               var _setClearPropsRatio = function(v) {
+                       if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration) { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that).
+                               var all = (this.e === "all"),
+                                       s = this.t.style,
+                                       a = all ? s.cssText.split(";") : this.e.split(","),
+                                       i = a.length,
+                                       transformParse = _specialProps.transform.parse,
+                                       p;
+                               while (--i > -1) {
+                                       p = a[i];
+                                       if (all) {
+                                               p = p.substr(0, p.indexOf(":")).split(" ").join("");
+                                       }
+                                       if (_specialProps[p]) {
+                                               p = (_specialProps[p].parse === transformParse) ? _transformProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow"
+                                       }
+                                       _removeProp(s, p);
+                               }
+                       }
+               };
+               _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
+                       pt = new CSSPropTween(t, p, 0, 0, pt, 2);
+                       pt.setRatio = _setClearPropsRatio;
+                       pt.e = e;
+                       pt.pr = -10;
+                       pt.data = cssp._tween;
+                       _hasPriority = true;
+                       return pt;
+               }});
+
+               p = "bezier,throwProps,physicsProps,physics2D".split(",");
+               i = p.length;
+               while (i--) {
+                       _registerPluginProp(p[i]);
+               }
+
+
+
+
+
+
+
+
+               p = CSSPlugin.prototype;
+               p._firstPT = null;
+               
+               //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc. 
+               p._onInitTween = function(target, vars, tween) {
+                       if (!target.nodeType) { //css is only for dom elements
+                               return false;
+                       }
+                       this._target = target;
+                       this._tween = tween;
+                       this._vars = vars;
+                       _autoRound = vars.autoRound;
+                       _hasPriority = false;
+                       _suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
+                       _cs = _getComputedStyle(target, "");
+                       _overwriteProps = this._overwriteProps;
+                       var style = target.style,
+                               v, pt, pt2, first, last, next, zIndex, tpt, threeD;
+                       
+                       if (_reqSafariFix) if (style.zIndex === "") {
+                               v = _getStyle(target, "zIndex", _cs);
+                               if (v === "auto" || v === "") {
+                                       //corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive.
+                                       style.zIndex = 0;
+                               }
+                       }
+                       
+                       if (typeof(vars) === "string") {
+                               first = style.cssText;
+                               v = _getAllStyles(target, _cs);
+                               style.cssText = first + ";" + vars;
+                               v = _cssDif(target, v, _getAllStyles(target)).difs;
+                               if (!_supportsOpacity && _opacityValExp.test(vars)) {
+                                       v.opacity = parseFloat( RegExp.$1 );
+                               }
+                               vars = v;
+                               style.cssText = first;
+                       }
+                       this._firstPT = pt = this.parse(target, vars, null);
+
+                       if (this._transformType) {
+                               threeD = (this._transformType === 3);
+                               if (!_transformProp) {
+                                       style.zoom = 1; //helps correct an IE issue.
+                               } else if (_isSafari) {
+                                       _reqSafariFix = true;
+                                       //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
+                                       if (style.zIndex === "") {
+                                               zIndex = _getStyle(target, "zIndex", _cs);
+                                               if (zIndex === "auto" || zIndex === "") {
+                                                       style.zIndex = 0;
+                                               }
+                                       }
+                                       //Setting WebkitBackfaceVisibility corrects 3 bugs:
+                                       // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
+                                       // 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly.
+                                       // 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug.
+                                       //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
+                                       if (_isSafariLT6) {
+                                               style.WebkitBackfaceVisibility = this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden");
+                                       }
+                               }
+                               pt2 = pt;
+                               while (pt2 && pt2._next) {
+                                       pt2 = pt2._next;
+                               }
+                               tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
+                               this._linkCSSP(tpt, null, pt2);
+                               tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio;
+                               tpt.data = this._transform || _getTransform(target, _cs, true);
+                               _overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here.
+                       }
+
+                       if (_hasPriority) {
+                               //reorders the linked list in order of pr (priority)
+                               while (pt) {
+                                       next = pt._next;
+                                       pt2 = first;
+                                       while (pt2 && pt2.pr > pt.pr) {
+                                               pt2 = pt2._next;
+                                       }
+                                       if ((pt._prev = pt2 ? pt2._prev : last)) {
+                                               pt._prev._next = pt;
+                                       } else {
+                                               first = pt;
+                                       }
+                                       if ((pt._next = pt2)) {
+                                               pt2._prev = pt;
+                                       } else {
+                                               last = pt;
+                                       }
+                                       pt = next;
+                               }
+                               this._firstPT = first;
+                       }
+                       return true;
+               };
+
+
+               p.parse = function(target, vars, pt, plugin) {
+                       var style = target.style,
+                               p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
+                       for (p in vars) {
+                               es = vars[p]; //ending value string
+                               sp = _specialProps[p]; //SpecialProp lookup.
+                               if (sp) {
+                                       pt = sp.parse(target, es, p, this, pt, plugin, vars);
+
+                               } else {
+                                       bs = _getStyle(target, p, _cs) + "";
+                                       isStr = (typeof(es) === "string");
+                                       if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor:
+                                               if (!isStr) {
+                                                       es = _parseColor(es);
+                                                       es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
+                                               }
+                                               pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
+
+                                       } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
+                                               pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
+
+                                       } else {
+                                               bn = parseFloat(bs);
+                                               bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case.
+
+                                               if (bs === "" || bs === "auto") {
+                                                       if (p === "width" || p === "height") {
+                                                               bn = _getDimension(target, p, _cs);
+                                                               bsfx = "px";
+                                                       } else if (p === "left" || p === "top") {
+                                                               bn = _calculateOffset(target, p, _cs);
+                                                               bsfx = "px";
+                                                       } else {
+                                                               bn = (p !== "opacity") ? 0 : 1;
+                                                               bsfx = "";
+                                                       }
+                                               }
+
+                                               rel = (isStr && es.charAt(1) === "=");
+                                               if (rel) {
+                                                       en = parseInt(es.charAt(0) + "1", 10);
+                                                       es = es.substr(2);
+                                                       en *= parseFloat(es);
+                                                       esfx = es.replace(_suffixExp, "");
+                                               } else {
+                                                       en = parseFloat(es);
+                                                       esfx = isStr ? es.substr((en + "").length) || "" : "";
+                                               }
+
+                                               if (esfx === "") {
+                                                       esfx = _suffixMap[p] || bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
+                                               }
+
+                                               es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix.
+
+                                               //if the beginning/ending suffixes don't match, normalize them...
+                                               if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn || bn === 0) {
+                                                       bn = _convertToPixels(target, p, bn, bsfx);
+                                                       if (esfx === "%") {
+                                                               bn /= _convertToPixels(target, p, 100, "%") / 100;
+                                                               if (bn > 100) { //extremely rare
+                                                                       bn = 100;
+                                                               }
+                                                               if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens.
+                                                                       bs = bn + "%";
+                                                               }
+
+                                                       } else if (esfx === "em") {
+                                                               bn /= _convertToPixels(target, p, 1, "em");
+
+                                                       //otherwise convert to pixels.
+                                                       } else {
+                                                               en = _convertToPixels(target, p, en, esfx);
+                                                               esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
+                                                       }
+                                                       if (rel) if (en || en === 0) {
+                                                               es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
+                                                       }
+                                               }
+
+                                               if (rel) {
+                                                       en += bn;
+                                               }
+
+                                               if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly.
+                                                       pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
+                                                       pt.xs0 = esfx;
+                                                       //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
+                                               } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
+                                                       _log("invalid " + p + " tween value: " + vars[p]);
+                                               } else {
+                                                       pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
+                                                       pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween.
+                                                       //DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
+                                               }
+                                       }
+                               }
+                               if (plugin) if (pt && !pt.plugin) {
+                                       pt.plugin = plugin;
+                               }
+                       }
+                       return pt;
+               };
+               
+               
+               //gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
+               p.setRatio = function(v) {
+                       var pt = this._firstPT,
+                               min = 0.000001,
+                               val, str, i;
+
+                       //at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards).
+                       if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
+                               while (pt) {
+                                       if (pt.type !== 2) {
+                                               pt.t[pt.p] = pt.e;
+                                       } else {
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+
+                       } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
+                               while (pt) {
+                                       val = pt.c * v + pt.s;
+                                       if (pt.r) {
+                                               val = (val > 0) ? (val + 0.5) | 0 : (val - 0.5) | 0;
+                                       } else if (val < min) if (val > -min) {
+                                               val = 0;
+                                       }
+                                       if (!pt.type) {
+                                               pt.t[pt.p] = val + pt.xs0;
+                                       } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
+                                               i = pt.l;
+                                               if (i === 2) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
+                                               } else if (i === 3) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
+                                               } else if (i === 4) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
+                                               } else if (i === 5) {
+                                                       pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5;
+                                               } else {
+                                                       str = pt.xs0 + val + pt.xs1;
+                                                       for (i = 1; i < pt.l; i++) {
+                                                               str += pt["xn"+i] + pt["xs"+(i+1)];
+                                                       }
+                                                       pt.t[pt.p] = str;
+                                               }
+
+                                       } else if (pt.type === -1) { //non-tweening value
+                                               pt.t[pt.p] = pt.xs0;
+
+                                       } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+
+                       //if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever).
+                       } else {
+                               while (pt) {
+                                       if (pt.type !== 2) {
+                                               pt.t[pt.p] = pt.b;
+                                       } else {
+                                               pt.setRatio(v);
+                                       }
+                                       pt = pt._next;
+                               }
+                       }
+               };
+
+               /**
+                * @private
+                * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
+                * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
+                * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
+                * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
+                * doesn't have any transform-related properties of its own. You can call this method as many times as you
+                * want and it won't create duplicate CSSPropTweens.
+                *
+                * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
+                */
+               p._enableTransforms = function(threeD) {
+                       this._transformType = (threeD || this._transformType === 3) ? 3 : 2;
+                       this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
+               };
+
+               /** @private **/
+               p._linkCSSP = function(pt, next, prev, remove) {
+                       if (pt) {
+                               if (next) {
+                                       next._prev = pt;
+                               }
+                               if (pt._next) {
+                                       pt._next._prev = pt._prev;
+                               }
+                               if (prev) {
+                                       prev._next = pt;
+                               } else if (!remove && this._firstPT === null) {
+                                       this._firstPT = pt;
+                               }
+                               if (pt._prev) {
+                                       pt._prev._next = pt._next;
+                               } else if (this._firstPT === pt) {
+                                       this._firstPT = pt._next;
+                               }
+                               pt._next = next;
+                               pt._prev = prev;
+                       }
+                       return pt;
+               };
+               
+               //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
+               p._kill = function(lookup) {
+                       var copy = lookup,
+                               pt, p, xfirst;
+                       if (lookup.autoAlpha || lookup.alpha) {
+                               copy = {};
+                               for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
+                                       copy[p] = lookup[p];
+                               }
+                               copy.opacity = 1;
+                               if (copy.autoAlpha) {
+                                       copy.visibility = 1;
+                               }
+                       }
+                       if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst".
+                               xfirst = pt.xfirst;
+                               if (xfirst && xfirst._prev) {
+                                       this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
+                               } else if (xfirst === this._firstPT) {
+                                       this._firstPT = pt._next;
+                               }
+                               if (pt._next) {
+                                       this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
+                               }
+                               this._classNamePT = null;
+                       }
+                       return TweenPlugin.prototype._kill.call(this, copy);
+               };
+
+
+
+
+               //used by cascadeTo() for gathering all the style properties of each child element into an array for comparison.
+               var _getChildStyles = function(e, props, targets) {
+                               var children, i, child, type;
+                               if (e.slice) {
+                                       i = e.length;
+                                       while (--i > -1) {
+                                               _getChildStyles(e[i], props, targets);
+                                       }
+                                       return;
+                               }
+                               children = e.childNodes;
+                               i = children.length;
+                               while (--i > -1) {
+                                       child = children[i];
+                                       type = child.type;
+                                       if (child.style) {
+                                               props.push(_getAllStyles(child));
+                                               if (targets) {
+                                                       targets.push(child);
+                                               }
+                                       }
+                                       if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
+                                               _getChildStyles(child, props, targets);
+                                       }
+                               }
+                       };
+
+               /**
+                * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
+                * and then compares the style properties of all the target's child elements at the tween's start and end, and
+                * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
+                * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
+                * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
+                * is because it creates entirely new tweens that may have completely different targets than the original tween,
+                * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
+                * and it would create other problems. For example:
+                *  - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted)
+                *  - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others.
+                *  - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed.
+                *
+                * @param {Object} target object to be tweened
+                * @param {number} Duration in seconds (or frames for frames-based tweens)
+                * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
+                * @return {Array} An array of TweenLite instances
+                */
+               CSSPlugin.cascadeTo = function(target, duration, vars) {
+                       var tween = TweenLite.to(target, duration, vars),
+                               results = [tween],
+                               b = [],
+                               e = [],
+                               targets = [],
+                               _reservedProps = TweenLite._internals.reservedProps,
+                               i, difs, p;
+                       target = tween._targets || tween.target;
+                       _getChildStyles(target, b, targets);
+                       tween.render(duration, true);
+                       _getChildStyles(target, e);
+                       tween.render(0, true);
+                       tween._enabled(true);
+                       i = targets.length;
+                       while (--i > -1) {
+                               difs = _cssDif(targets[i], b[i], e[i]);
+                               if (difs.firstMPT) {
+                                       difs = difs.difs;
+                                       for (p in vars) {
+                                               if (_reservedProps[p]) {
+                                                       difs[p] = vars[p];
+                                               }
+                                       }
+                                       results.push( TweenLite.to(targets[i], duration, difs) );
+                               }
+                       }
+                       return results;
+               };
+
+               
+               TweenPlugin.activate([CSSPlugin]);
+               return CSSPlugin;
+               
+       }, true);
+       
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/CSSRulePlugin.js b/js/libs/gsap/plugins/CSSRulePlugin.js
new file mode 100644 (file)
index 0000000..36dfe9a
--- /dev/null
@@ -0,0 +1,94 @@
+/*!
+ * VERSION: beta 0.5
+ * DATE: 2012-12-20
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine("plugins.CSSRulePlugin", ["plugins.TweenPlugin","TweenLite","plugins.CSSPlugin"], function(TweenPlugin, TweenLite, CSSPlugin) {
+
+               /** @constructor **/
+               var CSSRulePlugin = function() {
+                               TweenPlugin.call(this, "cssRule");
+                               this._overwriteProps.length = 0;
+                       },
+                       _doc = window.document,
+                       _superSetRatio = CSSPlugin.prototype.setRatio,
+                       p = CSSRulePlugin.prototype = new CSSPlugin();
+
+               p._propName = "cssRule";
+               p.constructor = CSSRulePlugin;
+               CSSRulePlugin.API = 2;
+
+               /**
+                * Searches the style sheets in the document for a particular selector like ".myClass" or "a" or "a:hover" or ":after" and
+                * returns a reference to that style sheet (or an array of them in the case of a pseudo selector like ":after"). Then you
+                * can animate the individual properties of the style sheet.
+                *
+                * @param {!string} selector a string describing the selector, like ".myClass" or "a" or "a:hover" or ":after"
+                * @return a reference to the style sheet (or an array of them in the case of a pseudo selector). If none was found, null is returned (or an empty array for a pseudo selector)
+                */
+               CSSRulePlugin.getRule = function(selector) {
+                       var ruleProp = _doc.all ? 'rules' : 'cssRules',
+                               ss = _doc.styleSheets,
+                               i = ss.length,
+                               pseudo = (selector.charAt(0) === ":"),
+                               j, curSS, cs, a;
+                       selector = (pseudo ? "" : ",") + selector.toLowerCase() + ","; //note: old versions of IE report tag name selectors as upper case, so we just change everything to lowercase.
+                       if (pseudo) {
+                               a = [];
+                       }
+                       while (--i > -1) {
+                               curSS = ss[i][ruleProp];
+                               j = curSS.length;
+                               while (--j > -1) {
+                                       cs = curSS[j];
+                                       if (cs.selectorText && ("," + cs.selectorText.split("::").join(":").toLowerCase() + ",").indexOf(selector) !== -1) { //note: IE adds an extra ":" to pseudo selectors, so .myClass:after becomes .myClass::after, so we need to strip the extra one out.
+                                               if (pseudo) {
+                                                       a.push(cs.style);
+                                               } else {
+                                                       return cs.style;
+                                               }
+                                       }
+                               }
+                       }
+                       return a;
+               };
+                                                       
+               
+               //@private gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
+               p._onInitTween = function(target, value, tween) {
+                       if (target.cssText === undefined) {
+                               return false;
+                       }
+                       var div = _doc.createElement("div");
+                       this._ss = target;
+                       this._proxy = div.style;
+                       div.style.cssText = target.cssText;
+                       CSSPlugin.prototype._onInitTween.call(this, div, value, tween); //we just offload all the work to the regular CSSPlugin and then copy the cssText back over to the rule in the setRatio() method. This allows us to have all of the updates to CSSPlugin automatically flow through to CSSRulePlugin instead of having to maintain both
+                       return true;
+               };
+
+               
+               
+               //@private gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
+               p.setRatio = function(v) {
+                       _superSetRatio.call(this, v);
+                       this._ss.cssText = this._proxy.cssText;
+               };
+               
+               
+               TweenPlugin.activate([CSSRulePlugin]);
+               return CSSRulePlugin;
+               
+       }, true);
+       
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/ColorPropsPlugin.js b/js/libs/gsap/plugins/ColorPropsPlugin.js
new file mode 100644 (file)
index 0000000..86213b9
--- /dev/null
@@ -0,0 +1,122 @@
+/*!
+ * VERSION: beta 1.2.0
+ * DATE: 2013-03-01
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       var _numExp = /(\d|\.)+/g,
+               _colorLookup = {aqua:[0,255,255],
+                       lime:[0,255,0],
+                       silver:[192,192,192],
+                       black:[0,0,0],
+                       maroon:[128,0,0],
+                       teal:[0,128,128],
+                       blue:[0,0,255],
+                       navy:[0,0,128],
+                       white:[255,255,255],
+                       fuchsia:[255,0,255],
+                       olive:[128,128,0],
+                       yellow:[255,255,0],
+                       orange:[255,165,0],
+                       gray:[128,128,128],
+                       purple:[128,0,128],
+                       green:[0,128,0],
+                       red:[255,0,0],
+                       pink:[255,192,203],
+                       cyan:[0,255,255],
+                       transparent:[255,255,255,0]},
+               _hue = function(h, m1, m2) {
+                       h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
+                       return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
+               },
+               _parseColor = function(color) {
+                       if (color === "" || color == null || color === "none") {
+                               return _colorLookup.transparent;
+                       }
+                       if (_colorLookup[color]) {
+                               return _colorLookup[color];
+                       }
+                       if (typeof(color) === "number") {
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       if (color.charAt(0) === "#") {
+                               if (color.length === 4) { //for shorthand like #9F0
+                                       color = "#" + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2) + color.charAt(3) + color.charAt(3);
+                               }
+                               color = parseInt(color.substr(1), 16);
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       if (color.substr(0, 3) === "hsl") {
+                               color = color.match(_numExp);
+                               var h = (Number(color[0]) % 360) / 360,
+                                       s = Number(color[1]) / 100,
+                                       l = Number(color[2]) / 100,
+                                       m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s,
+                                       m1 = l * 2 - m2;
+                               if (color.length > 3) {
+                                       color[3] = Number(color[3]);
+                               }
+                               color[0] = _hue(h + 1 / 3, m1, m2);
+                               color[1] = _hue(h, m1, m2);
+                               color[2] = _hue(h - 1 / 3, m1, m2);
+                               return color;
+                       }
+                       return color.match(_numExp) || _colorLookup.transparent;
+               };
+
+       window._gsDefine.plugin({
+               propName: "colorProps",
+               priority: -1,
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       this._target = target;
+                       var p, s, c, pt;
+                       for (p in value) {
+                               c = _parseColor(value[p]);
+                               this._firstPT = pt = {_next:this._firstPT, p:p, f:(typeof(target[p]) === "function"), n:p, r:false};
+                               s = _parseColor( (!pt.f) ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
+                               pt.s = Number(s[0]);
+                               pt.c = Number(c[0]) - pt.s;
+                               pt.gs = Number(s[1]);
+                               pt.gc = Number(c[1]) - pt.gs;
+                               pt.bs = Number(s[2]);
+                               pt.bc = Number(c[2]) - pt.bs;
+                               if ((pt.rgba = (s.length > 3 || c.length > 3))) { //detect an rgba() value
+                                       pt.as = (s.length < 4) ? 1 : Number(s[3]);
+                                       pt.ac = ((c.length < 4) ? 1 : Number(c[3])) - pt.as;
+                               }
+                               if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(v) {
+                       var pt = this._firstPT, val;
+                       while (pt) {
+                               val = (pt.rgba ? "rgba(" : "rgb(") + ((pt.s + (v * pt.c)) >> 0) + ", " + ((pt.gs + (v * pt.gc)) >> 0) + ", " + ((pt.bs + (v * pt.bc)) >> 0) + (pt.rgba ? ", " + (pt.as + (v * pt.ac)) : "") + ")";
+                               if (pt.f) {
+                                       this._target[pt.p](val);
+                               } else {
+                                       this._target[pt.p] = val;
+                               }
+                               pt = pt._next;
+                       }
+               }
+       });
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
diff --git a/js/libs/gsap/plugins/DirectionalRotationPlugin.js b/js/libs/gsap/plugins/DirectionalRotationPlugin.js
new file mode 100644 (file)
index 0000000..5e2d2ec
--- /dev/null
@@ -0,0 +1,79 @@
+/*!
+ * VERSION: beta 0.2.0
+ * DATE: 2013-05-07
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       window._gsDefine.plugin({
+               propName: "directionalRotation",
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       if (typeof(value) !== "object") {
+                               value = {rotation:value};
+                       }
+                       this.finals = {};
+                       var cap = (value.useRadians === true) ? Math.PI * 2 : 360,
+                               min = 0.000001,
+                               p, v, start, end, dif, split;
+                       for (p in value) {
+                               if (p !== "useRadians") {
+                                       split = (value[p] + "").split("_");
+                                       v = split[0];
+                                       start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() );
+                                       end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0;
+                                       dif = end - start;
+                                       if (split.length) {
+                                               v = split.join("_");
+                                               if (v.indexOf("short") !== -1) {
+                                                       dif = dif % cap;
+                                                       if (dif !== dif % (cap / 2)) {
+                                                               dif = (dif < 0) ? dif + cap : dif - cap;
+                                                       }
+                                               }
+                                               if (v.indexOf("_cw") !== -1 && dif < 0) {
+                                                       dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               } else if (v.indexOf("ccw") !== -1 && dif > 0) {
+                                                       dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
+                                               }
+                                       }
+                                       if (dif > min || dif < -min) {
+                                               this._addTween(target, p, start, start + dif, p);
+                                               this._overwriteProps.push(p);
+                                       }
+                               }
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(ratio) {
+                       var pt;
+                       if (ratio !== 1) {
+                               this._super.setRatio.call(this, ratio);
+                       } else {
+                               pt = this._firstPT;
+                               while (pt) {
+                                       if (pt.f) {
+                                               pt.t[pt.p](this.finals[pt.p]);
+                                       } else {
+                                               pt.t[pt.p] = this.finals[pt.p];
+                                       }
+                                       pt = pt._next;
+                               }
+                       }
+               }
+
+       })._autoCSS = true;
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/EaselPlugin.js b/js/libs/gsap/plugins/EaselPlugin.js
new file mode 100644 (file)
index 0000000..358c140
--- /dev/null
@@ -0,0 +1,291 @@
+/*!
+ * VERSION: beta 0.1.4
+ * DATE: 2013-02-28
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       var _numExp = /(\d|\.)+/g,
+               _ColorFilter, _ColorMatrixFilter,
+               _colorProps = ["redMultiplier","greenMultiplier","blueMultiplier","alphaMultiplier","redOffset","greenOffset","blueOffset","alphaOffset"],
+               _colorLookup = {aqua:[0,255,255],
+                       lime:[0,255,0],
+                       silver:[192,192,192],
+                       black:[0,0,0],
+                       maroon:[128,0,0],
+                       teal:[0,128,128],
+                       blue:[0,0,255],
+                       navy:[0,0,128],
+                       white:[255,255,255],
+                       fuchsia:[255,0,255],
+                       olive:[128,128,0],
+                       yellow:[255,255,0],
+                       orange:[255,165,0],
+                       gray:[128,128,128],
+                       purple:[128,0,128],
+                       green:[0,128,0],
+                       red:[255,0,0],
+                       pink:[255,192,203],
+                       cyan:[0,255,255],
+                       transparent:[255,255,255,0]},
+               _parseColor = function(color) {
+                       if (color === "" || color == null || color === "none") {
+                               return _colorLookup.transparent;
+                       } else if (_colorLookup[color]) {
+                               return _colorLookup[color];
+                       } else if (typeof(color) === "number") {
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       } else if (color.charAt(0) === "#") {
+                               if (color.length === 4) { //for shorthand like #9F0
+                                       color = "#" + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2) + color.charAt(3) + color.charAt(3);
+                               }
+                               color = parseInt(color.substr(1), 16);
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       return color.match(_numExp) || _colorLookup.transparent;
+               },
+               _parseColorFilter = function(t, v, pg) {
+                       if (!_ColorFilter) {
+                               _ColorFilter = (window.ColorFilter || window.createjs.ColorFilter);
+                               if (!_ColorFilter) {
+                                       throw("EaselPlugin error: The EaselJS ColorFilter JavaScript file wasn't loaded.");
+                               }
+                       }
+                       var filters = t.filters || [],
+                               i = filters.length,
+                               c, s, e, a, p;
+                       while (--i > -1) {
+                               if (filters[i] instanceof _ColorFilter) {
+                                       s = filters[i];
+                                       break;
+                               }
+                       }
+                       if (!s) {
+                               s = new _ColorFilter();
+                               filters.push(s);
+                               t.filters = filters;
+                       }
+                       e = s.clone();
+                       if (v.tint != null) {
+                               c = _parseColor(v.tint);
+                               a = (v.tintAmount != null) ? Number(v.tintAmount) : 1;
+                               e.redOffset = Number(c[0]) * a;
+                               e.greenOffset = Number(c[1]) * a;
+                               e.blueOffset = Number(c[2]) * a;
+                               e.redMultiplier = e.greenMultiplier = e.blueMultiplier = 1 - a;
+                       } else {
+                               for (p in v) {
+                                       if (p !== "exposure") if (p !== "brightness") {
+                                               e[p] = Number(v[p]);
+                                       }
+                               }
+                       }
+                       if (v.exposure != null) {
+                               e.redOffset = e.greenOffset = e.blueOffset = 255 * (Number(v.exposure) - 1);
+                               e.redMultiplier = e.greenMultiplier = e.blueMultiplier = 1;
+                       } else if (v.brightness != null) {
+                               a = Number(v.brightness) - 1;
+                               e.redOffset = e.greenOffset = e.blueOffset = (a > 0) ? a * 255 : 0;
+                               e.redMultiplier = e.greenMultiplier = e.blueMultiplier = 1 - Math.abs(a);
+                       }
+                       i = 8;
+                       while (--i > -1) {
+                               p = _colorProps[i];
+                               if (s[p] !== e[p]) {
+                                       pg._addTween(s, p, s[p], e[p], "easel_colorFilter");
+                               }
+                       }
+                       pg._overwriteProps.push("easel_colorFilter");
+                       if (!t.cacheID) {
+                               throw("EaselPlugin warning: for filters to display in EaselJS, you must call the object's cache() method first. " + t);
+                       }
+               },
+
+               _idMatrix = [1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0],
+               _lumR = 0.212671,
+               _lumG = 0.715160,
+               _lumB = 0.072169,
+
+               _applyMatrix = function(m, m2) {
+                       if (!(m instanceof Array) || !(m2 instanceof Array)) {
+                               return m2;
+                       }
+                       var temp = [],
+                               i = 0,
+                               z = 0,
+                               y, x;
+                       for (y = 0; y < 4; y++) {
+                               for (x = 0; x < 5; x++) {
+                                       z = (x === 4) ? m[i + 4] : 0;
+                                       temp[i + x] = m[i]   * m2[x] + m[i+1] * m2[x + 5] +     m[i+2] * m2[x + 10] + m[i+3] * m2[x + 15] +     z;
+                               }
+                               i += 5;
+                       }
+                       return temp;
+               },
+
+               _setSaturation = function(m, n) {
+                       if (isNaN(n)) {
+                               return m;
+                       }
+                       var inv = 1 - n,
+                               r = inv * _lumR,
+                               g = inv * _lumG,
+                               b = inv * _lumB;
+                       return _applyMatrix([r + n, g, b, 0, 0, r, g + n, b, 0, 0, r, g, b + n, 0, 0, 0, 0, 0, 1, 0], m);
+               },
+
+               _colorize = function(m, color, amount) {
+                       if (isNaN(amount)) {
+                               amount = 1;
+                       }
+                       var c = _parseColor(color),
+                               r = c[0] / 255,
+                               g = c[1] / 255,
+                               b = c[2] / 255,
+                               inv = 1 - amount;
+                       return _applyMatrix([inv + amount * r * _lumR, amount * r * _lumG, amount * r * _lumB, 0, 0, amount * g * _lumR, inv + amount * g * _lumG, amount * g * _lumB, 0, 0, amount * b * _lumR, amount * b * _lumG, inv + amount * b * _lumB, 0, 0, 0, 0, 0, 1, 0], m);
+               },
+
+               _setHue = function(m, n) {
+                       if (isNaN(n)) {
+                               return m;
+                       }
+                       n *= Math.PI / 180;
+                       var c = Math.cos(n),
+                               s = Math.sin(n);
+                       return _applyMatrix([(_lumR + (c * (1 - _lumR))) + (s * (-_lumR)), (_lumG + (c * (-_lumG))) + (s * (-_lumG)), (_lumB + (c * (-_lumB))) + (s * (1 - _lumB)), 0, 0, (_lumR + (c * (-_lumR))) + (s * 0.143), (_lumG + (c * (1 - _lumG))) + (s * 0.14), (_lumB + (c * (-_lumB))) + (s * -0.283), 0, 0, (_lumR + (c * (-_lumR))) + (s * (-(1 - _lumR))), (_lumG + (c * (-_lumG))) + (s * _lumG), (_lumB + (c * (1 - _lumB))) + (s * _lumB), 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1], m);
+               },
+
+               _setContrast = function(m, n) {
+                       if (isNaN(n)) {
+                               return m;
+                       }
+                       n += 0.01;
+                       return _applyMatrix([n,0,0,0,128 * (1 - n), 0,n,0,0,128 * (1 - n), 0,0,n,0,128 * (1 - n), 0,0,0,1,0], m);
+               },
+
+               _parseColorMatrixFilter = function(t, v, pg) {
+                       if (!_ColorMatrixFilter) {
+                               _ColorMatrixFilter = (window.ColorMatrixFilter || window.createjs.ColorMatrixFilter);
+                               if (!_ColorMatrixFilter) {
+                                       throw("EaselPlugin error: The EaselJS ColorMatrixFilter JavaScript file wasn't loaded.");
+                               }
+                       }
+                       var filters = t.filters || [],
+                               i = filters.length,
+                               matrix, startMatrix, s;
+                       while (--i > -1) {
+                               if (filters[i] instanceof _ColorMatrixFilter) {
+                                       s = filters[i];
+                                       break;
+                               }
+                       }
+                       if (!s) {
+                               s = new _ColorMatrixFilter(_idMatrix.slice());
+                               filters.push(s);
+                               t.filters = filters;
+                       }
+                       startMatrix = s.matrix;
+                       matrix = _idMatrix.slice();
+                       if (v.colorize != null) {
+                               matrix = _colorize(matrix, v.colorize, Number(v.colorizeAmount));
+                       }
+                       if (v.contrast != null) {
+                               matrix = _setContrast(matrix, Number(v.contrast));
+                       }
+                       if (v.hue != null) {
+                               matrix = _setHue(matrix, Number(v.hue));
+                       }
+                       if (v.saturation != null) {
+                               matrix = _setSaturation(matrix, Number(v.saturation));
+                       }
+
+                       i = matrix.length;
+                       while (--i > -1) {
+                               if (matrix[i] !== startMatrix[i]) {
+                                       pg._addTween(startMatrix, i, startMatrix[i], matrix[i], "easel_colorMatrixFilter");
+                               }
+                       }
+
+                       pg._overwriteProps.push("easel_colorMatrixFilter");
+                       if (!t.cacheID) {
+                               throw("EaselPlugin warning: for filters to display in EaselJS, you must call the object's cache() method first. " + t);
+                       }
+
+                       pg._matrix = startMatrix;
+               };
+
+
+       window._gsDefine.plugin({
+               propName: "easel",
+               priority: -1,
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       this._target = target;
+                       var p, pt, tint, colorMatrix;
+                       for (p in value) {
+
+                               if (p === "colorFilter" || p === "tint" || p === "tintAmount" || p === "exposure" || p === "brightness") {
+                                       if (!tint) {
+                                               _parseColorFilter(target, value.colorFilter || value, this);
+                                               tint = true;
+                                       }
+
+                               } else if (p === "saturation" || p === "contrast" || p === "hue" || p === "colorize" || p === "colorizeAmount") {
+                                       if (!colorMatrix) {
+                                               _parseColorMatrixFilter(target, value.colorMatrixFilter || value, this);
+                                               colorMatrix = true;
+                                       }
+
+                               } else if (target[p] != null) {
+                                       this._firstPT = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pr:0, type:0};
+                                       pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
+                                       pt.c = (typeof(value[p]) === "number") ? value[p] - pt.s : (typeof(value[p]) === "string") ? parseFloat(value[p].split("=").join("")) : 0;
+
+                                       if (pt._next) {
+                                               pt._next._prev = pt;
+                                       }
+                               }
+
+                       }
+                       return true;
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(v) {
+                       var pt = this._firstPT,
+                               min = 0.000001,
+                               val;
+                       while (pt) {
+                               val = pt.c * v + pt.s;
+                               if (pt.r) {
+                                       val = (val + ((val > 0) ? 0.5 : -0.5)) >> 0; //about 4x faster than Math.round()
+                               } else if (val < min && val > -min) {
+                                       val = 0;
+                               }
+                               if (pt.f) {
+                                       pt.t[pt.p](val);
+                               } else {
+                                       pt.t[pt.p] = val;
+                               }
+                               pt = pt._next;
+                       }
+                       if (this._target.cacheID) {
+                               this._target.updateCache();
+                       }
+               }
+
+       });
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/KineticPlugin.js b/js/libs/gsap/plugins/KineticPlugin.js
new file mode 100644 (file)
index 0000000..2b14f80
--- /dev/null
@@ -0,0 +1,298 @@
+/*!
+ * VERSION: 0.4.0
+ * DATE: 2013-05-16
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+       
+       "use strict";
+
+       var _specialProps = {setScale:1, setShadowOffset:1, setFillPatternOffset:1, setOffset:1, setFill:2, setStroke:2, setShadowColor:2}, //type 1 is one that has "x" and "y" components that can be split apart but in order to set them, they must be combined into a single object and passed to one setter (like setScale({x:0.5, y:0.6})). Type 2 is for colors.
+               _getterNames = {},
+               _getterFuncs = {},
+               _setterFuncs = {},
+               _numExp = /(\d|\.)+/g,
+               _directionalRotationExp = /(?:_cw|_ccw|_short)/g,
+               _plugins = window._gsDefine.globals.com.greensock.plugins,
+               _colorLookup = {aqua:[0,255,255],
+                       lime:[0,255,0],
+                       silver:[192,192,192],
+                       black:[0,0,0],
+                       maroon:[128,0,0],
+                       teal:[0,128,128],
+                       blue:[0,0,255],
+                       navy:[0,0,128],
+                       white:[255,255,255],
+                       fuchsia:[255,0,255],
+                       olive:[128,128,0],
+                       yellow:[255,255,0],
+                       orange:[255,165,0],
+                       gray:[128,128,128],
+                       purple:[128,0,128],
+                       green:[0,128,0],
+                       red:[255,0,0],
+                       pink:[255,192,203],
+                       cyan:[0,255,255],
+                       transparent:[255,255,255,0]},
+               _hue = function(h, m1, m2) {
+                       h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
+                       return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
+               },
+               _parseColor = function(color) {
+                       if (color === "" || color == null || color === "none") {
+                               return _colorLookup.transparent;
+                       }
+                       if (_colorLookup[color]) {
+                               return _colorLookup[color];
+                       }
+                       if (typeof(color) === "number") {
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       if (color.charAt(0) === "#") {
+                               if (color.length === 4) { //for shorthand like #9F0
+                                       color = "#" + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2) + color.charAt(3) + color.charAt(3);
+                               }
+                               color = parseInt(color.substr(1), 16);
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       if (color.substr(0, 3) === "hsl") {
+                               color = color.match(_numExp);
+                               var h = (Number(color[0]) % 360) / 360,
+                                       s = Number(color[1]) / 100,
+                                       l = Number(color[2]) / 100,
+                                       m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s,
+                                       m1 = l * 2 - m2;
+                               if (color.length > 3) {
+                                       color[3] = Number(color[3]);
+                               }
+                               color[0] = _hue(h + 1 / 3, m1, m2);
+                               color[1] = _hue(h, m1, m2);
+                               color[2] = _hue(h - 1 / 3, m1, m2);
+                               return color;
+                       }
+                       var a = color.match(_numExp) || _colorLookup.transparent,
+                               i = a.length;
+                       while (--i > -1) {
+                               a[i] = Number(a[i]);
+                       }
+                       return a;
+               },
+               ColorProp = function(target, getter, setter, next) {
+                       this.getter = getter;
+                       this.setter = setter;
+                       var val = _parseColor( target[getter]() );
+                       this.proxy = {r:val[0], g:val[1], b:val[2], a:(val.length > 3 ? val[3] : 1)};
+                       if (next) {
+                               this._next = next;
+                               next._prev = this;
+                       }
+               },
+               _layersToDraw = [],
+               _ticker, _listening,
+               _onTick = function() {
+                       var i = _layersToDraw.length;
+                       if (i !== 0) {
+                               while (--i > -1) {
+                                       _layersToDraw[i].draw();
+                                       _layersToDraw[i]._gsDraw = false;
+                               }
+                               _layersToDraw.length = 0;
+                       } else {
+                               _ticker.removeEventListener("tick", _onTick);
+                               _listening = false;
+                       }
+               },
+               _prepDimensionProp = function(p, dimension) {
+                       var alt = (dimension === "x") ? "y" : "x",
+                               uc = dimension.toUpperCase(),
+                               getter = "get" + p.substr(3),
+                               proxyName = "_gs_" + p;
+                       _getterNames[p + uc] = getter + uc;
+                       _getterFuncs[p + uc] = function() {
+                               return this[getter]()[dimension];
+                       };
+                       _setterFuncs[p + uc] =  function(value) {
+                               var cur = this[getter](),
+                                       proxy = this[proxyName];
+                               if (!proxy) {
+                                       proxy = this[proxyName] = {};
+                               }
+                               proxy[dimension] = value;
+                               proxy[alt] = cur[alt];
+                               this[p](proxy);
+                               return this;
+                       };
+               },
+               //looks at every property in the vars and converts them (when appropriate) to the KineticJS equivalent, like "x" would become "setX", "rotation" would be "setRotation", etc. If it finds a special property for which "x" and "y" must be split apart (like scale, offset, shadowOffset, etc.), it will do that as well, and if the getters and setters aren't already on the object (like setScaleX, setScaleY, getScaleX, and getScaleY), it'll add those to the target itself (actually, its prototype if available). This method returns an array of any names it had to change (like "x", "y", "scale", etc.) so that they can be used in the overwriteProps array.
+               _convertProps = function(target, vars) {
+                       var converted = [],
+                               p, gp, val, i, proto;
+                       for (p in vars) {
+                               val = vars[p];
+                               if (p !== "bezier" && p !== "autoDraw" && p.substr(0,3) !== "set" && target[p] === undefined) {
+                                       converted.push(p);
+                                       delete vars[p];
+                                       p = "set" + p.charAt(0).toUpperCase() + p.substr(1);
+                                       vars[p] = val;
+                               }
+                               gp = _getterNames[p];
+                               if (gp) {
+                                       if (_specialProps[p] === 1) {
+                                               vars[p + "X"] = vars[p + "Y"] = vars[p];
+                                               delete vars[p];
+                                               return _convertProps(target, vars);
+                                       } else if (!target[p] && _setterFuncs[p]) {
+                                               proto = target.prototype || target;
+                                               proto[p] = _setterFuncs[p];
+                                               proto[gp] = _getterFuncs[p];
+                                       }
+                               } else if (p === "bezier") {
+                                       val = (val instanceof Array) ? val : val.values || [];
+                                       i = val.length;
+                                       while (--i > -1) {
+                                               if (i === 0) {
+                                                       converted = converted.concat( _convertProps(target, val[i]) );
+                                               } else {
+                                                       _convertProps(target, val[i]);
+                                               }
+                                       }
+                               }
+                       }
+                       return converted;
+               },
+               _copy = function(obj) {
+                       var result = {},
+                               p;
+                       for (p in obj) {
+                               result[p] = obj[p];
+                       }
+                       return result;
+               },
+               p;
+
+       for (p in _specialProps) {
+               _getterNames[p] = "get" + p.substr(3);
+               if (_specialProps[p] === 1) {
+                       _prepDimensionProp(p, "x");
+                       _prepDimensionProp(p, "y");
+               }
+       }
+
+       window._gsDefine.plugin({
+               propName: "kinetic",
+               API: 2,
+
+               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+               init: function(target, value, tween) {
+                       var p, val, gp, sp, bezierPlugin, directionalRotationPlugin;
+                       this._overwriteProps = _convertProps(target, value); //allow users to pass in shorter names like "x" instead of "setX" and "rotationDeg" instead of "setRotationDeg"
+                       this._target = target;
+                       this._layer = (value.autoDraw !== false) ? target.getLayer() : null;
+                       if (!_ticker && this._layer) {
+                               _ticker = tween.constructor.ticker;
+                       }
+                       for (p in value) {
+                               val = value[p];
+                               //we must handle colors in a special way, splitting apart the red, green, blue, and alpha.
+                               if (_specialProps[p] === 2) {
+                                       gp = _getterNames[p];
+                                       sp = this._firstSP = new ColorProp(target, gp, p, this._firstSP);
+                                       val = _parseColor(val);
+                                       if (sp.proxy.r !== val[0]) {
+                                               this._addTween(sp.proxy, "r", sp.proxy.r, val[0], p);
+                                       }
+                                       if (sp.proxy.g !== val[1]) {
+                                               this._addTween(sp.proxy, "g", sp.proxy.g, val[1], p);
+                                       }
+                                       if (sp.proxy.b !== val[2]) {
+                                               this._addTween(sp.proxy, "b", sp.proxy.b, val[2], p);
+                                       }
+                                       if ((val.length > 3 || sp.proxy.a !== 1) && sp.proxy.a !== val[3]) {
+                                               this._addTween(sp.proxy, "a", sp.proxy.a, (val.length > 3 ? val[3] : 1), p);
+                                       }
+                               } else if (p === "bezier") {
+                                       bezierPlugin = _plugins.BezierPlugin;
+                                       if (!bezierPlugin) {
+                                               throw("BezierPlugin not loaded");
+                                       }
+                                       bezierPlugin = this._bezier = new bezierPlugin();
+                                       if (typeof(val) === "object" && val.autoRotate === true) {
+                                               val.autoRotate = ["setX","setY","setRotation",0,true];
+                                       }
+                                       bezierPlugin._onInitTween(target, val, tween);
+                                       this._overwriteProps = this._overwriteProps.concat(bezierPlugin._overwriteProps);
+                                       this._addTween(bezierPlugin, "setRatio", 0, 1, p);
+
+                               } else if ((p === "setRotation" || p === "setRotationDeg") && typeof(val) === "string" && _directionalRotationExp.test(val)) {
+                                       directionalRotationPlugin = _plugins.DirectionalRotationPlugin;
+                                       if (!directionalRotationPlugin) {
+                                               throw("DirectionalRotationPlugin not loaded");
+                                       }
+                                       directionalRotationPlugin = this._directionalRotation = new directionalRotationPlugin();
+                                       gp = {useRadians:(p === "setRotation")};
+                                       gp[p] = val;
+                                       directionalRotationPlugin._onInitTween(target, gp, tween);
+                                       this._addTween(directionalRotationPlugin, "setRatio", 0, 1, p);
+
+                               } else if (p !== "autoDraw") {
+                                       this._addTween(target, p, ((typeof(target[p]) === "function") ? target["get" + p.substr(3)]() : target[p]) || 0, val, p);
+                               }
+                               this._overwriteProps.push(p);
+                       }
+                       return true;
+               },
+
+               kill: function(lookup) {
+                       lookup = _copy(lookup);
+                       _convertProps(this._target, lookup);
+                       if (this._bezier) {
+                               this._bezier._kill(lookup);
+                       }
+                       if (this._directionalRotation) {
+                               this._directionalRotation._kill(lookup);
+                       }
+                       return this._super._kill.call(this, lookup);
+               },
+
+               round:function(lookup, value) {
+                       lookup = _copy(lookup);
+                       _convertProps(this._target, lookup);
+                       if (this._bezier) {
+                               this._bezier._roundProps(lookup, value);
+                       }
+                       return this._super._roundProps.call(this, lookup, value);
+               },
+
+               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+               set: function(ratio) {
+                       this._super.setRatio.call(this, ratio);
+                       var sp = this._firstSP,
+                               layer = this._layer,
+                               t, proxy;
+                       if (sp) {
+                               t = this._target;
+                               while (sp) {
+                                       proxy = sp.proxy;
+                                       t[sp.setter]( (proxy.a !== 1 ? "rgba(" : "rgb(") + (proxy.r | 0) + ", " + (proxy.g | 0) + ", " + (proxy.b | 0) + (proxy.a !== 1 ? ", " + proxy.a : "") + ")");
+                                       sp = sp._next;
+                               }
+                       }
+                       if (layer && !layer._gsDraw) {
+                               _layersToDraw.push(layer);
+                               layer._gsDraw = true; //a flag indicating that we need to draw() this layer as soon as all the tweens have finished updating (using a "tick" event listener)
+                               if (!_listening) {
+                                       _ticker.addEventListener("tick", _onTick);
+                                       _listening = true;
+                               }
+                       }
+               }
+
+       });
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/RaphaelPlugin.js b/js/libs/gsap/plugins/RaphaelPlugin.js
new file mode 100644 (file)
index 0000000..ba55528
--- /dev/null
@@ -0,0 +1,367 @@
+/*!
+ * VERSION: beta 0.2.0
+ * DATE: 2013-02-27
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       var     _NaNExp = /[^\d\-\.]/g,
+               _DEG2RAD = Math.PI / 180,
+               _numExp = /(\d|\.)+/g,
+               _colorLookup = {aqua:[0,255,255],
+                       lime:[0,255,0],
+                       silver:[192,192,192],
+                       black:[0,0,0],
+                       maroon:[128,0,0],
+                       teal:[0,128,128],
+                       blue:[0,0,255],
+                       navy:[0,0,128],
+                       white:[255,255,255],
+                       fuchsia:[255,0,255],
+                       olive:[128,128,0],
+                       yellow:[255,255,0],
+                       orange:[255,165,0],
+                       gray:[128,128,128],
+                       purple:[128,0,128],
+                       green:[0,128,0],
+                       red:[255,0,0],
+                       pink:[255,192,203],
+                       cyan:[0,255,255],
+                       transparent:[255,255,255,0]},
+               //parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course)
+               _parseColor = function(color) {
+                       if (typeof(color) === "number") {
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       } else if (color === "" || color == null || color === "none" || typeof(color) !== "string") {
+                               return _colorLookup.transparent;
+                       } else if (_colorLookup[color]) {
+                               return _colorLookup[color];
+                       } else if (color.charAt(0) === "#") {
+                               if (color.length === 4) { //for shorthand like #9F0
+                                       color = "#" + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2) + color.charAt(3) + color.charAt(3);
+                               }
+                               color = parseInt(color.substr(1), 16);
+                               return [color >> 16, (color >> 8) & 255, color & 255];
+                       }
+                       return color.match(_numExp) || _colorLookup.transparent;
+               },
+
+               _transformMap = {scaleX:1, scaleY:1, tx:1, ty:1, rotation:1, shortRotation:1, skewX:1, skewY:1, scale:1},
+
+               //parses the transform values for an element, returning an object with x, y, scaleX, scaleY, rotation, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
+               _getTransform = function(t, rec) {
+                       var s = t.matrix,
+                               min = 0.000001,
+                               a = s.a,
+                               b = s.b,
+                               c = s.c,
+                               d = s.d,
+                               m = rec ? t._gsTransform || {skewY:0} : {skewY:0},
+                               invX = (m.scaleX < 0); //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
+
+                       m.tx = s.e - (m.ox || 0); //ox is the offset x that we record in setRatio() whenever we apply a custom transform that might use a pivot point. Remember, s.e and s.f get affected by things like scale. For example, imagine an object whose top left corner is at 100,100 and then we scale it up to 300% using the center as the pivot point - that corner would now be very different even though to the user, they didn't intend to change/tween the x/y position per se. Therefore, we record whatever offsets we make so that we can compensate when reading the values back.
+                       m.ty = s.f - (m.oy || 0); //oy is the offset y (see note above)
+                       m.scaleX = Math.sqrt(a * a + b * b);
+                       m.scaleY = Math.sqrt(d * d + c * c);
+                       m.rotation = (a || b) ? Math.atan2(b, a) : m.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
+                       m.skewX = (c || d) ? Math.atan2(c, d) + m.rotation : m.skewX || 0;
+                       if (Math.abs(m.skewX) > Math.PI / 2) {
+                               if (invX) {
+                                       m.scaleX *= -1;
+                                       m.skewX += (m.rotation <= 0) ? Math.PI : -Math.PI;
+                                       m.rotation += (m.rotation <= 0) ? Math.PI : -Math.PI;
+                               } else {
+                                       m.scaleY *= -1;
+                                       m.skewX += (m.skewX <= 0) ? Math.PI : -Math.PI;
+                               }
+                       }
+                       //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs().
+                       if (m.rotation < min) if (m.rotation > -min) if (a || b) {
+                               m.rotation = 0;
+                       }
+                       if (m.skewX < min) if (m.skewX > -min) if (b || c) {
+                               m.skewX = 0;
+                       }
+                       if (rec) {
+                               t._gsTransform = m; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
+                       }
+                       return m;
+               },
+
+               //takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
+               _parseVal = function(v, d) {
+                       return (v == null) ? d : (typeof(v) === "string" && v.indexOf("=") === 1) ? parseInt(v.charAt(0)+"1", 10) * Number(v.substr(2)) + d : Number(v);
+               },
+
+               //translates strings like "40deg" or "40" or 40rad" or "+=40deg" to a numeric radian angle, optionally relative to a default value (if "+=" or "-=" prefix is found)
+               _parseAngle = function(v, d) {
+                       var m = (v.indexOf("rad") === -1) ? _DEG2RAD : 1,
+                               r = (v.indexOf("=") === 1);
+                       v = Number(v.replace(_NaNExp, "")) * m;
+                       return r ? v + d : v;
+               },
+
+
+               RaphaelPlugin = window._gsDefine.plugin({
+                       propName: "raphael",
+                       API: 2,
+
+                       //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                       init: function(target, value, tween) {
+                               if (!target.attr) { //raphael must have attr() method
+                                       return false;
+                               }
+                               this._target = target;
+                               this._tween = tween;
+                               this._props = target._gsProps = target._gsProps || {};
+                               var p, s, v, pt, clr1, clr2, rel;
+
+                               for (p in value) {
+
+                                       v = value[p];
+
+                                       if (p === "transform") {
+                                               this._parseTransform(target, v);
+                                               continue;
+                                       } else if (_transformMap[p] || p === "pivot") {
+                                               this._parseTransform(target, value);
+                                               continue;
+                                       }
+
+                                       s = target.attr(p);
+
+                                       //Some of these properties are in place in order to conform with the standard PropTweens in TweenPlugins so that overwriting and roundProps occur properly. For example, f and r may seem unnecessary here, but they enable other functionality.
+                                       //_next:*       next linked list node           [object]
+                                       //t:    *       target                                          [object]
+                                       //p:    *       property (camelCase)            [string]
+                                       //s:    *       starting value                          [number]
+                                       //c:    *       change value                            [number]
+                                       //f:    *       is function                                     [boolean]
+                                       //n:    *       name (for overwriting)          [string]
+                                       //b:            beginning value                         [string]
+                                       //i:            intermediate value                      [string]
+                                       //e:            ending value                            [string]
+                                       //r:    *       round                                           [boolean]
+                                       //type:         0=normal, 1=color, 2=rgba, -1=non-tweening prop [number]
+                                       this._firstPT = pt = {_next:this._firstPT,
+                                               t:this._props,
+                                               p:p,
+                                               b:s,
+                                               f:false,
+                                               n:"raphael_" + p,
+                                               r:false,
+                                               type:0};
+
+                                       //color values must be split apart into their R, G, B (and sometimes alpha) values and tweened independently.
+                                       if (p === "fill" || p === "stroke") {
+                                               clr1 = _parseColor(s);
+                                               clr2 = _parseColor(v);
+                                               pt.e = v;
+                                               pt.s = Number(clr1[0]);                         //red starting value
+                                               pt.c = Number(clr2[0]) - pt.s;          //red change
+                                               pt.gs = Number(clr1[1]);                        //green starting value
+                                               pt.gc = Number(clr2[1]) - pt.gs;        //green change
+                                               pt.bs = Number(clr1[2]);                        //blue starting value
+                                               pt.bc = Number(clr2[2]) - pt.bs;        //blue change
+                                               if (clr1.length > 3 || clr2.length > 3) { //detect an rgba() value
+                                                       pt.as = (clr1.length < 4) ? 1 : Number(clr1[3]);
+                                                       pt.ac = ((clr2.length < 4) ? 1 : Number(clr2[3])) - pt.as;
+                                                       pt.type = 2; //2 = rgba() tween
+                                               } else {
+                                                       pt.type = 1; //1 = color tween, -1 = no tween, just set the value at the end because there's no changes
+                                               }
+
+                                       } else {
+
+                                               s = (typeof(s) === "string") ? parseFloat(s.replace(_NaNExp, "")) : Number(s);
+
+                                               if (typeof(v) === "string") {
+                                                       rel = (v.charAt(1) === "=");
+                                                       v = parseFloat(v.replace(_NaNExp, ""));
+                                               } else {
+                                                       rel = false;
+                                               }
+
+                                               pt.e = (v || v === 0) ? (rel ? v + s : v) : value[p]; //ensures that any += or -= prefixes are taken care of.
+
+                                               if ((s || s === 0) && (v || v === 0) && (pt.c = (rel ? v : v - s))) { //faster than isNaN(). Also, we set pt.c (change) here because if it's 0, we'll just treat it like a non-tweening value. can't do (v !== start) because if it's a relative value and the CHANGE is identical to the START, the condition will fail unnecessarily.
+                                                       pt.s = s;
+                                               } else {
+                                                       pt.type = -1;
+                                                       pt.i = value[p]; //intermediate value is typically the same as the end value.
+                                                       pt.s = pt.c = 0;
+                                               }
+
+                                       }
+
+                                       this._overwriteProps.push("raphael_" + p);
+                                       if (pt._next) {
+                                               pt._next._prev = pt;
+                                       }
+                               }
+
+                               return true;
+                       },
+
+                       //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+                       set: function(v) {
+                               var pt = this._firstPT, val;
+
+                               while (pt) {
+                                       val = pt.c * v + pt.s;
+                                       if (pt.r) {
+                                               val = (val > 0) ? (val + 0.5) >> 0 : (val - 0.5) >> 0;
+                                       }
+                                       if (!pt.type) {
+                                               pt.t[pt.p] = val;
+                                       } else if (pt.type === 1) { //rgb()
+                                               pt.t[pt.p] = "rgb(" + (val >> 0) + ", " + ((pt.gs + (v * pt.gc)) >> 0) + ", " + ((pt.bs + (v * pt.bc)) >> 0) + ")";
+                                       } else if (pt.type === 2) { //rgba()
+                                               pt.t[pt.p] = "rgba(" + (val >> 0) + ", " + ((pt.gs + (v * pt.gc)) >> 0) + ", " + ((pt.bs + (v * pt.bc)) >> 0) + ", " + (pt.as + (v * pt.ac)) + ")";
+                                       } else if (pt.type === -1) { //non-tweening
+                                               pt.t[pt.p] = pt.i;
+                                       }
+                                       pt = pt._next;
+                               }
+
+                               this._target.attr(this._props);
+
+                               //apply transform values like x, y, scaleX, scaleY, rotation, skewX, or skewY. We do these after looping through all the PropTweens because those are where the changes are made to scaleX/scaleY/rotation/skewX/skewY/x/y.
+                               if (this._transform) {
+                                       pt = this._transform; //to improve speed and reduce size, reuse the pt variable as an alias to the _transform property
+                                       var ang = pt.rotation,
+                                               skew = ang - pt.skewX,
+                                               a = Math.cos(ang) * pt.scaleX,
+                                               b = Math.sin(ang) * pt.scaleX,
+                                               c = Math.sin(skew) * -pt.scaleY,
+                                               d = Math.cos(skew) * pt.scaleY,
+                                               min = 0.000001,
+                                               pxl = this._pxl,
+                                               pyl = this._pyl;
+
+                                       //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases for both b and c. The conditional logic here is faster than calling Math.abs().
+                                       if (b < min) if (b > -min) {
+                                               b = 0;
+                                       }
+                                       if (c < min) if (c > -min) {
+                                               c = 0;
+                                       }
+                                       pt.ox = this._pxg - (pxl * a + pyl * c); //we must record the offset x/y that we're making from the regular tx/ty (matrix.e and f) so that we can correctly interpret positional data in _getTransform(). See note there on tx and ox.
+                                       pt.oy = this._pyg - (pxl * b + pyl * d);
+                                       this._target.transform("m" + a + "," + b + "," + c + "," + d + "," + (pt.tx + pt.ox) + "," + (pt.ty + pt.oy));
+                               }
+
+                       }
+
+               }),
+               p = RaphaelPlugin.prototype;
+
+       //compares the beginning x, y, scaleX, scaleY, rotation, and skewX properties with the ending ones and adds PropTweens accordingly wherever necessary. We must tween them individually (rather than just tweening the matrix values) so that elgant overwriting can occur, like if one tween is controlling scaleX, scaleY, and rotation and then another one starts mid-tween that is trying to control the scaleX only - this tween should continue tweening scaleY and rotation.
+       p._parseTransform = function(t, v) {
+               if (this._transform) { return; } //only need to parse the transform once, and only if the browser supports it.
+
+               var m1 = this._transform = _getTransform(t, true),
+                       min = 0.000001,
+                       m2, skewY, p, pt, copy, dx, dy, mtx, pivot;
+
+               if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
+
+                       m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
+                                 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
+                                 tx:_parseVal(v.tx, m1.tx),
+                                 ty:_parseVal(v.ty, m1.ty)};
+
+                       if (v.shortRotation != null) {
+                               m2.rotation = (typeof(v.shortRotation) === "number") ? v.shortRotation * _DEG2RAD : _parseAngle(v.shortRotation, m1.rotation);
+                               var dif = (m2.rotation - m1.rotation) % (Math.PI * 2);
+                               if (dif !== dif % Math.PI) {
+                                       dif += Math.PI * ((dif < 0) ? 2 : -2);
+                               }
+                               m2.rotation = m1.rotation + dif;
+
+                       } else {
+                               m2.rotation = (v.rotation == null) ? m1.rotation : (typeof(v.rotation) === "number") ? v.rotation * _DEG2RAD : _parseAngle(v.rotation, m1.rotation);
+                       }
+                       m2.skewX = (v.skewX == null) ? m1.skewX : (typeof(v.skewX) === "number") ? v.skewX * _DEG2RAD : _parseAngle(v.skewX, m1.skewX);
+
+                       //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
+                       m2.skewY = (v.skewY == null) ? m1.skewY : (typeof(v.skewY) === "number") ? v.skewY * _DEG2RAD : _parseAngle(v.skewY, m1.skewY);
+                       if ((skewY = m2.skewY - m1.skewY)) {
+                               m2.skewX += skewY;
+                               m2.rotation += skewY;
+                       }
+                       //don't allow rotation/skew values to be a SUPER small decimal because when they're translated back to strings for setting the css property, the browser reports them in a funky way, like 1-e7. Of course we could use toFixed() to resolve that issue but that hurts performance quite a bit with all those function calls on every frame, plus it is virtually impossible to discern values that small visually (nobody will notice changing a rotation of 0.0000001 to 0, so the performance improvement is well worth it).
+                       if (m2.skewY < min) if (m2.skewY > -min) {
+                               m2.skewY = 0;
+                       }
+                       if (m2.skewX < min) if (m2.skewX > -min) {
+                               m2.skewX = 0;
+                       }
+                       if (m2.rotation < min) if (m2.rotation > -min) {
+                               m2.rotation = 0;
+                       }
+
+                       pivot = v.localPivot || v.globalPivot;
+
+                       if (typeof(pivot) === "string") {
+                               copy = pivot.split(",");
+                               dx = Number(copy[0]);
+                               dy = Number(copy[1]);
+                       } else if (typeof(pivot) === "object") {
+                               dx = Number(pivot.x);
+                               dy = Number(pivot.y);
+                       } else if (v.localPivot) {
+                               copy = t.getBBox(true);
+                               dx = copy.width / 2;
+                               dy = copy.height / 2;
+                       } else {
+                               copy = t.getBBox();
+                               dx = copy.x + copy.width / 2;
+                               dy = copy.y + copy.height / 2;
+                       }
+
+                       if (v.localPivot) {
+                               mtx = t.matrix;
+                               dx += t.attr("x");
+                               dy += t.attr("y");
+                               this._pxl = dx;
+                               this._pyl = dy;
+                               this._pxg = dx * mtx.a + dy * mtx.c + mtx.e - m1.tx;
+                               this._pyg = dx * mtx.b + dy * mtx.d + mtx.f - m1.ty;
+                       } else {
+                               mtx = t.matrix.invert();
+                               this._pxl = dx * mtx.a + dy * mtx.c + mtx.e;
+                               this._pyl = dx * mtx.b + dy * mtx.d + mtx.f;
+                               this._pxg = dx - m1.tx;
+                               this._pyg = dy - m1.ty;
+                       }
+
+               } else if (typeof(v) === "string") { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
+                       copy = this._target.transform();
+                       t.transform(v);
+                       m2 = _getTransform(t, false);
+                       t.transform(copy);
+               } else {
+                       return;
+               }
+
+               for (p in _transformMap) {
+                       if (m1[p] !== m2[p]) if (p !== "shortRotation") if (p !== "scale") {
+                               this._firstPT = pt = {_next:this._firstPT, t:m1, p:p, s:m1[p], c:m2[p] - m1[p], n:p, f:false, r:false, b:m1[p], e:m2[p], type:0};
+                               if (pt._next) {
+                                       pt._next._prev = pt;
+                               }
+                               this._overwriteProps.push("raphael_" + p);
+                       }
+               }
+       };
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/RoundPropsPlugin.js b/js/libs/gsap/plugins/RoundPropsPlugin.js
new file mode 100644 (file)
index 0000000..cb157df
--- /dev/null
@@ -0,0 +1,73 @@
+/*!
+ * VERSION: beta 1.4.0
+ * DATE: 2013-02-27
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+               var RoundPropsPlugin = window._gsDefine.plugin({
+                               propName: "roundProps",
+                               priority: -1,
+                               API: 2,
+
+                               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                               init: function(target, value, tween) {
+                                       this._tween = tween;
+                                       return true;
+                               }
+
+                       }),
+                       p = RoundPropsPlugin.prototype;
+
+               p._onInitAllProps = function() {
+                       var tween = this._tween,
+                               rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","),
+                               i = rp.length,
+                               lookup = {},
+                               rpt = tween._propLookup.roundProps,
+                               prop, pt, next;
+                       while (--i > -1) {
+                               lookup[rp[i]] = 1;
+                       }
+                       i = rp.length;
+                       while (--i > -1) {
+                               prop = rp[i];
+                               pt = tween._firstPT;
+                               while (pt) {
+                                       next = pt._next; //record here, because it may get removed
+                                       if (pt.pg) {
+                                               pt.t._roundProps(lookup, true);
+                                       } else if (pt.n === prop) {
+                                               this._add(pt.t, prop, pt.s, pt.c);
+                                               //remove from linked list
+                                               if (next) {
+                                                       next._prev = pt._prev;
+                                               }
+                                               if (pt._prev) {
+                                                       pt._prev._next = next;
+                                               } else if (tween._firstPT === pt) {
+                                                       tween._firstPT = next;
+                                               }
+                                               pt._next = pt._prev = null;
+                                               tween._propLookup[prop] = rpt;
+                                       }
+                                       pt = next;
+                               }
+                       }
+                       return false;
+               };
+
+               p._add = function(target, p, s, c) {
+                       this._addTween(target, p, s, s + c, p, true);
+                       this._overwriteProps.push(p);
+               };
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/ScrollToPlugin.js b/js/libs/gsap/plugins/ScrollToPlugin.js
new file mode 100644 (file)
index 0000000..f480238
--- /dev/null
@@ -0,0 +1,112 @@
+/*!
+ * VERSION: beta 1.7.0
+ * DATE: 2013-02-27
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+
+       "use strict";
+
+       var _doc = document.documentElement,
+               _window = window,
+               _max = function(element, axis) {
+                       var dim = (axis === "x") ? "Width" : "Height",
+                               scroll = "scroll" + dim,
+                               client = "client" + dim,
+                               body = document.body;
+                       return (element === _window || element === _doc || element === body) ? Math.max(_doc[scroll], body[scroll]) - Math.max(_doc[client], body[client]) : element[scroll] - element["offset" + dim];
+               },
+
+               ScrollToPlugin = window._gsDefine.plugin({
+                       propName: "scrollTo",
+                       API: 2,
+
+                       //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                       init: function(target, value, tween) {
+                               this._wdw = (target === _window);
+                               this._target = target;
+                               this._tween = tween;
+                               if (typeof(value) !== "object") {
+                                       value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
+                               }
+                               this._autoKill = (value.autoKill !== false);
+                               this.x = this.xPrev = this.getX();
+                               this.y = this.yPrev = this.getY();
+                               if (value.x != null) {
+                                       this._addTween(this, "x", this.x, (value.x === "max") ? _max(target, "x") : value.x, "scrollTo_x", true);
+                               } else {
+                                       this.skipX = true;
+                               }
+                               if (value.y != null) {
+                                       this._addTween(this, "y", this.y, (value.y === "max") ? _max(target, "y") : value.y, "scrollTo_y", true);
+                               } else {
+                                       this.skipY = true;
+                               }
+                               return true;
+                       },
+
+                       //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+                       set: function(v) {
+                               this._super.setRatio.call(this, v);
+
+                               var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
+                                       y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
+                                       yDif = y - this.yPrev,
+                                       xDif = x - this.xPrev;
+
+                               if (this._autoKill) {
+                                       //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match.
+                                       if (!this.skipX && (xDif > 7 || xDif < -7)) {
+                                               this.skipX = true; //if the user scrolls separately, we should stop tweening!
+                                       }
+                                       if (!this.skipY && (yDif > 7 || yDif < -7)) {
+                                               this.skipY = true; //if the user scrolls separately, we should stop tweening!
+                                       }
+                                       if (this.skipX && this.skipY) {
+                                               this._tween.kill();
+                                       }
+                               }
+                               if (this._wdw) {
+                                       _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
+                               } else {
+                                       if (!this.skipY) {
+                                               this._target.scrollTop = this.y;
+                                       }
+                                       if (!this.skipX) {
+                                               this._target.scrollLeft = this.x;
+                                       }
+                               }
+                               this.xPrev = this.x;
+                               this.yPrev = this.y;
+                       }
+
+               }),
+               p = ScrollToPlugin.prototype;
+
+       ScrollToPlugin.max = _max;
+
+       p.getX = function() {
+               return (!this._wdw) ? this._target.scrollLeft : (_window.pageXOffset != null) ? _window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : document.body.scrollLeft;
+       };
+
+       p.getY = function() {
+               return (!this._wdw) ? this._target.scrollTop : (_window.pageYOffset != null) ? _window.pageYOffset : (_doc.scrollTop != null) ? _doc.scrollTop : document.body.scrollTop;
+       };
+
+       p._kill = function(lookup) {
+               if (lookup.scrollTo_x) {
+                       this.skipX = true;
+               }
+               if (lookup.scrollTo_y) {
+                       this.skipY = true;
+               }
+               return this._super._kill.call(this, lookup);
+       };
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/TEMPLATE_Plugin.js b/js/libs/gsap/plugins/TEMPLATE_Plugin.js
new file mode 100644 (file)
index 0000000..33551e8
--- /dev/null
@@ -0,0 +1,74 @@
+/*!
+ * VERSION: 1.1.0
+ * DATE: 2013-02-28
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ * 
+ * This file is to be used as a simple template for writing your own plugin. See the 
+ * notes at http://api.greensock.com/js/com/greensock/plugins/TweenPlugin.html for more details.
+ *
+ * You can start by doing a search for "yourCustomProperty" and replace it with whatever the name
+ * of your property is. This way of defining a plugin was introduced in version 1.9.0 - previous versions
+ * of TweenLite won't work with this.
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ **/
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+       //ignore the line above this and at the very end - those are for ensuring things load in the proper order
+       "use strict";
+
+       window._gsDefine.plugin({
+               propName: "yourCustomProperty", //the name of the property that will get intercepted and handled by this plugin (obviously change it to whatever you want, typically it is camelCase starting with lowercase).
+               priority: 0, //the priority in the rendering pipeline (0 by default). A priority of -1 would mean this plugin will run after all those with 0 or greater. A priority of 1 would get run before 0, etc. This only matters when a plugin relies on other plugins finishing their work before it runs (or visa-versa)
+               API: 2, //the API should stay 2 - it just gives us a way to know the method/property structure so that if in the future we change to a different TweenPlugin architecture, we can identify this plugin's structure.
+               version: "1.0.0", //your plugin's version number
+               overwriteProps: ["yourCustomProperty"], //an array of property names whose tweens should be overwritten by this plugin. For example, if you create a "scale" plugin that handles both "scaleX" and "scaleY", the overwriteProps would be ["scaleX","scaleY"] so that if there's a scaleX or scaleY tween in-progress when a new "scale" tween starts (using this plugin), it would overwrite the scaleX or scaleY tween.
+
+               /*
+                * The init function is called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. It receives 3 parameters:
+                *   1) target [object] - the target of the tween. In cases where the tween's original target is an array (or jQuery object), this target will be the individual object inside that array (a new plugin instance is created for each target in the array). For example, TweenLite.to([obj1, obj2, obj3], 1, {x:100}) the target will be obj1 or obj2 or obj3 rather than the array containing them.
+                *   2) value [*] - whatever value is passed as the special property value. For example, TweenLite.to(element, 1, {yourCustomProperty:3}) the value would be 3. Or for TweenLite.to(element, 1, {yourCustomProperty:{subProp1:3, subProp2:"whatever"}});, value would be {subProp1:3, subProp2:"whatever"}.
+                *   3) tween [TweenLite] - the TweenLite (or TweenMax) instance that is managing this plugin instance. This can be useful if you need to check certain state-related properties on the tween (maybe in the set method) like its duration or time. Most of the time, however, you don't need to do anything with the tween. It is provided just in case you want to reference it.
+                *
+                * This function should return true unless you want to have TweenLite/Max skip the plugin altogether and instead treat the property/value like a normal tween (as if the plugin wasn't activated). This is rarely useful, so you should almost always return true.
+                */
+               init: function(target, value, tween) {
+                       this._target = target; //we record the target so that we can refer to it in the set method when doing updates.
+
+                       /* Next, we create a property tween for "scaleX" and "scaleY" properties of our target
+                        * (we're just using them as a examples of how to set up a property tween with a name, start, and end value).
+                        * the _addTween() method accepts the following parameters:
+                        *   1) target [object] - target object whose property this tween will control.
+                        *   2) property [string] - the name of the property, like "scaleX" or "scaleY"
+                        *   3) start [number] - The starting value of the property. For example, if you're tweening from 0 to 100, start would be 0.
+                        *   4) end [number] - the ending value of the property. For example, if you're tweening from 0 to 100, end would be 100.
+                        *   5) overwriteProperty [string] - the name that gets registered as the overwrite property so that if another concurrent tween of the same target gets created and it is tweening a property with this name, this one will be overwritten. Typically this is the same as "property".
+                        *   6) round [boolean] - if true, the updated value on each update will be rounded to the nearest integer. [false by default]
+                        * You do NOT need to use _addTween() at all. It is merely a convenience. You can record your own values internally or whatever you want.
+                        */
+                       this._addTween(target, "scaleX", target.scaleX, value, "scaleX", false);
+                       this._addTween(target, "scaleY", target.scaleY, value, "scaleY", false);
+
+                       //now, just for kicks, we'll record the starting "alpha" value and amount of change so that we can manage this manually rather than _addTween() (again, totally fictitious, just for an example)
+                       this._alphaStart = target.alpha;
+                       this._alphaChange = value.alpha - target.alpha;
+
+                       //always return true unless we want to scrap the plugin and have the value treated as a normal property tween (very uncommon)
+                       return true;
+               },
+
+               //[optional] - called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.). If you're using this._super._addTween() for all your tweens and you don't need to do anything special on each frame besides updating those values, you can omit this "set" function altogether.
+               set: function(ratio) {
+                       //since we used _addTween() inside init function, it created some property tweens that we'll update by calling the parent prototype's setRatio() (otherwise, the property tweens wouldn't get their values updated). this._super refers to the TweenPlugin prototype from which the plugin inherits (not that you need to worry about that).
+                       this._super.setRatio.call(this, ratio);
+
+                       //now manually set the alpha
+                       this._target.alpha = this._alphaStart + this._alphaChange * ratio;
+               }
+
+       });
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/gsap/plugins/TextPlugin.js b/js/libs/gsap/plugins/TextPlugin.js
new file mode 100644 (file)
index 0000000..b1aa7b8
--- /dev/null
@@ -0,0 +1,97 @@
+/*!
+ * VERSION: 0.4.0
+ * DATE: 2013-05-16
+ * UPDATES AND DOCS AT: http://www.greensock.com
+ *
+ * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
+ * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
+ * Club GreenSock members, the software agreement that was issued with your membership.
+ * 
+ * @author: Jack Doyle, jack@greensock.com
+ */
+(window._gsQueue || (window._gsQueue = [])).push( function() {
+       
+       "use strict";
+
+               var _getText = function(e) {
+                               var type = e.nodeType,
+                                       result = "";
+                               if (type === 1 || type === 9 || type === 11) {
+                                       if (typeof(e.textContent) === "string") {
+                                               return e.textContent;
+                                       } else {
+                                               for ( e = e.firstChild; e; e = e.nextSibling ) {
+                                                       result += _getText(e);
+                                               }
+                                       }
+                               } else if (type === 3 || type === 4) {
+                                       return e.nodeValue;
+                               }
+                               return result;
+                       },
+                       TextPlugin = window._gsDefine.plugin({
+                               propName: "text",
+                               API: 2,
+
+                               //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
+                               init: function(target, value, tween) {
+                                       if (!("innerHTML" in target)) {
+                                               return false;
+                                       }
+                                       this._target = target;
+                                       if (typeof(value) !== "object") {
+                                               value = {value:value};
+                                       }
+                                       if (value.value === undefined) {
+                                               this._text = this._original = [""];
+                                               return true;
+                                       }
+                                       this._delimiter = value.delimiter || "";
+                                       this._original = _getText(target).replace(/\s+/g, " ").split(this._delimiter);
+                                       this._text = value.value.replace(/\s+/g, " ").split(this._delimiter);
+                                       if (typeof(value.newClass) === "string") {
+                                               this._newClass = value.newClass;
+                                               this._hasClass = true;
+                                       }
+                                       if (typeof(value.oldClass) === "string") {
+                                               this._oldClass = value.oldClass;
+                                               this._hasClass = true;
+                                       }
+                                       var i = this._original.length - this._text.length,
+                                               shrt = (i < 0) ? this._original : this._text;
+                                       this._fillChar = value.fillChar || (value.padSpace ? "&nbsp;" : "");
+                                       if (i < 0) {
+                                               i = -i;
+                                       }
+                                       while (--i > -1) {
+                                               shrt.push(this._fillChar);
+                                       }
+                                       return true;
+                               },
+
+                               //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
+                               set: function(ratio) {
+                                       if (ratio > 1) {
+                                               ratio = 1;
+                                       } else if (ratio < 0) {
+                                               ratio = 0;
+                                       }
+                                       var l = this._text.length,
+                                               i = (ratio * l + 0.5) | 0,
+                                               applyNew, applyOld, str;
+                                       if (this._hasClass) {
+                                               applyNew = (this._newClass && i !== 0);
+                                               applyOld = (this._oldClass && i !== l);
+                                               str = (applyNew ? "<span class='" + this._newClass + "'>" : "") + this._text.slice(0, i).join(this._delimiter) + (applyNew ? "</span>" : "") + (applyOld ? "<span class='" + this._oldClass + "'>" : "") + this._delimiter + this._original.slice(i).join(this._delimiter) + (applyOld ? "</span>" : "");
+                                       } else {
+                                               str = this._text.slice(0, i).join(this._delimiter) + this._delimiter + this._original.slice(i).join(this._delimiter);
+                                       }
+                                       this._target.innerHTML = (this._fillChar === "&nbsp;" && str.indexOf("  ") !== -1) ? str.split("  ").join("&nbsp;&nbsp;") : str;
+                               }
+
+                       }),
+                       p = TextPlugin.prototype;
+               
+               p._newClass = p._oldClass = p._delimiter = "";
+
+}); if (window._gsDefine) { window._gsQueue.pop()(); }
\ No newline at end of file
diff --git a/js/libs/jquery/jquery.hashchange.js b/js/libs/jquery/jquery.hashchange.js
new file mode 100644 (file)
index 0000000..714b1e7
--- /dev/null
@@ -0,0 +1,290 @@
+// Script: jQuery hashchange event
+//
+// *Version: 1.3, Last updated: 7/21/2010*
+// 
+// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
+// GitHub       - http://github.com/cowboy/jquery-hashchange/
+// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
+// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
+// 
+// About: License
+// 
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+// 
+// About: Examples
+// 
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+// 
+// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
+// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
+// 
+// About: Support and Testing
+// 
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+// 
+// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
+//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
+// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
+// 
+// About: Known issues
+// 
+// While this jQuery hashchange event implementation is quite stable and
+// robust, there are a few unfortunate browser bugs surrounding expected
+// hashchange event-based behaviors, independent of any JavaScript
+// window.onhashchange abstraction. See the following examples for more
+// information:
+// 
+// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
+// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
+// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
+// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
+// 
+// Also note that should a browser natively support the window.onhashchange 
+// event, but not report that it does, the fallback polling loop will be used.
+// 
+// About: Release History
+// 
+// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
+//         "removable" for mobile-only development. Added IE6/7 document.title
+//         support. Attempted to make Iframe as hidden as possible by using
+//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
+//         support for the "shortcut" format $(window).hashchange( fn ) and
+//         $(window).hashchange() like jQuery provides for built-in events.
+//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
+//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
+//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
+//         file to address access denied issues when setting document.domain in
+//         IE6/7.
+// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
+//         from a page on another domain would cause an error in Safari 4. Also,
+//         IE6/7 Iframe is now inserted after the body (this actually works),
+//         which prevents the page from scrolling when the event is first bound.
+//         Event can also now be bound before DOM ready, but it won't be usable
+//         before then in IE6/7.
+// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
+//         where browser version is incorrectly reported as 8.0, despite
+//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
+// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
+//         window.onhashchange functionality into a separate plugin for users
+//         who want just the basic event & back button support, without all the
+//         extra awesomeness that BBQ provides. This plugin will be included as
+//         part of jQuery BBQ, but also be available separately.
+
+(function($,window,undefined){
+  '$:nomunge'; // Used by YUI compressor.
+  
+  // Reused string.
+  var str_hashchange = 'hashchange',
+    
+    // Method / object references.
+    doc = document,
+    fake_onhashchange,
+    special = $.event.special,
+    
+    // Does the browser support window.onhashchange? Note that IE8 running in
+    // IE7 compatibility mode reports true for 'onhashchange' in window, even
+    // though the event isn't supported, so also test document.documentMode.
+    doc_mode = doc.documentMode,
+    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
+  
+  // Get location.hash (or what you'd expect location.hash to be) sans any
+  // leading #. Thanks for making this necessary, Firefox!
+  function get_fragment( url ) {
+    url = url || location.href;
+    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
+  };
+  
+  // Method: jQuery.fn.hashchange
+  // 
+  // Bind a handler to the window.onhashchange event or trigger all bound
+  // window.onhashchange event handlers. This behavior is consistent with
+  // jQuery's built-in event handlers.
+  // 
+  // Usage:
+  // 
+  // > jQuery(window).hashchange( [ handler ] );
+  // 
+  // Arguments:
+  // 
+  //  handler - (Function) Optional handler to be bound to the hashchange
+  //    event. This is a "shortcut" for the more verbose form:
+  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
+  //    all bound window.onhashchange event handlers will be triggered. This
+  //    is a shortcut for the more verbose
+  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
+  //    the <hashchange event> section.
+  // 
+  // Returns:
+  // 
+  //  (jQuery) The initial jQuery collection of elements.
+  
+  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
+  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
+  $.fn[ str_hashchange ] = function( fn ) {
+    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
+  };
+  
+  // Property: jQuery.fn.hashchange.delay
+  // 
+  // The numeric interval (in milliseconds) at which the <hashchange event>
+  // polling loop executes. Defaults to 50.
+  
+  // Property: jQuery.fn.hashchange.domain
+  // 
+  // If you're setting document.domain in your JavaScript, and you want hash
+  // history to work in IE6/7, not only must this property be set, but you must
+  // also set document.domain BEFORE jQuery is loaded into the page. This
+  // property is only applicable if you are supporting IE6/7 (or IE8 operating
+  // in "IE7 compatibility" mode).
+  // 
+  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
+  // path of the included "document-domain.html" file, which can be renamed or
+  // modified if necessary (note that the document.domain specified must be the
+  // same in both your main JavaScript as well as in this file).
+  // 
+  // Usage:
+  // 
+  // jQuery.fn.hashchange.domain = document.domain;
+  
+  // Property: jQuery.fn.hashchange.src
+  // 
+  // If, for some reason, you need to specify an Iframe src file (for example,
+  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
+  // do so using this property. Note that when using this property, history
+  // won't be recorded in IE6/7 until the Iframe src file loads. This property
+  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
+  // compatibility" mode).
+  // 
+  // Usage:
+  // 
+  // jQuery.fn.hashchange.src = 'path/to/file.html';
+  
+  $.fn[ str_hashchange ].delay = 50;
+  /*
+  $.fn[ str_hashchange ].domain = null;
+  $.fn[ str_hashchange ].src = null;
+  */
+  
+  // Event: hashchange event
+  // 
+  // Fired when location.hash changes. In browsers that support it, the native
+  // HTML5 window.onhashchange event is used, otherwise a polling loop is
+  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
+  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
+  // compatibility" mode), a hidden Iframe is created to allow the back button
+  // and hash-based history to work.
+  // 
+  // Usage as described in <jQuery.fn.hashchange>:
+  // 
+  // > // Bind an event handler.
+  // > jQuery(window).hashchange( function(e) {
+  // >   var hash = location.hash;
+  // >   ...
+  // > });
+  // > 
+  // > // Manually trigger the event handler.
+  // > jQuery(window).hashchange();
+  // 
+  // A more verbose usage that allows for event namespacing:
+  // 
+  // > // Bind an event handler.
+  // > jQuery(window).bind( 'hashchange', function(e) {
+  // >   var hash = location.hash;
+  // >   ...
+  // > });
+  // > 
+  // > // Manually trigger the event handler.
+  // > jQuery(window).trigger( 'hashchange' );
+  // 
+  // Additional Notes:
+  // 
+  // * The polling loop and Iframe are not created until at least one handler
+  //   is actually bound to the 'hashchange' event.
+  // * If you need the bound handler(s) to execute immediately, in cases where
+  //   a location.hash exists on page load, via bookmark or page refresh for
+  //   example, use jQuery(window).hashchange() or the more verbose 
+  //   jQuery(window).trigger( 'hashchange' ).
+  // * The event can be bound before DOM ready, but since it won't be usable
+  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
+  //   to bind it inside a DOM ready handler.
+  
+  // Override existing $.event.special.hashchange methods (allowing this plugin
+  // to be defined after jQuery BBQ in BBQ's source code).
+  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
+    
+    // Called only when the first 'hashchange' event is bound to window.
+    setup: function() {
+      // If window.onhashchange is supported natively, there's nothing to do..
+      if ( supports_onhashchange ) { return false; }
+      
+      // Otherwise, we need to create our own. And we don't want to call this
+      // until the user binds to the event, just in case they never do, since it
+      // will create a polling loop and possibly even a hidden Iframe.
+      $( fake_onhashchange.start );
+    },
+    
+    // Called only when the last 'hashchange' event is unbound from window.
+    teardown: function() {
+      // If window.onhashchange is supported natively, there's nothing to do..
+      if ( supports_onhashchange ) { return false; }
+      
+      // Otherwise, we need to stop ours (if possible).
+      $( fake_onhashchange.stop );
+    }
+    
+  });
+  
+  // fake_onhashchange does all the work of triggering the window.onhashchange
+  // event for browsers that don't natively support it, including creating a
+  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
+  // Iframe to enable back and forward.
+  fake_onhashchange = (function(){
+    var self = {},
+      timeout_id,
+      
+      // Remember the initial hash so it doesn't get triggered immediately.
+      last_hash = get_fragment(),
+      
+      fn_retval = function(val){ return val; },
+      history_set = fn_retval,
+      history_get = fn_retval;
+    
+    // Start the polling loop.
+    self.start = function() {
+      timeout_id || poll();
+    };
+    
+    // Stop the polling loop.
+    self.stop = function() {
+      timeout_id && clearTimeout( timeout_id );
+      timeout_id = undefined;
+    };
+    
+    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
+    // if location.hash has changed, and triggers the 'hashchange' event on
+    // window when necessary.
+    function poll() {
+      var hash = get_fragment(),
+        history_hash = history_get( last_hash );
+      
+      if ( hash !== last_hash ) {
+        history_set( last_hash = hash, history_hash );
+        
+        $(window).trigger( str_hashchange );
+        
+      } else if ( history_hash !== last_hash ) {
+        location.href = location.href.replace( /#.*/, '' ) + history_hash;
+      }
+      
+      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
+    };    
+    return self;
+  })();
+  
+})(jQuery,this);
diff --git a/js/libs/jquery/jquery.js b/js/libs/jquery/jquery.js
new file mode 100644 (file)
index 0000000..280083f
--- /dev/null
@@ -0,0 +1,8842 @@
+/*!
+ * jQuery JavaScript Library v2.0.2
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-05-30T21:25Z
+ */
+(function( window, undefined ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+       // A central reference to the root jQuery(document)
+       rootjQuery,
+
+       // The deferred used on DOM ready
+       readyList,
+
+       // Support: IE9
+       // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
+       core_strundefined = typeof undefined,
+
+       // Use the correct document accordingly with window argument (sandbox)
+       location = window.location,
+       document = window.document,
+       docElem = document.documentElement,
+
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+
+       // Map over the $ in case of overwrite
+       _$ = window.$,
+
+       // [[Class]] -> type pairs
+       class2type = {},
+
+       // List of deleted data cache ids, so we can reuse them
+       core_deletedIds = [],
+
+       core_version = "2.0.2",
+
+       // Save a reference to some core methods
+       core_concat = core_deletedIds.concat,
+       core_push = core_deletedIds.push,
+       core_slice = core_deletedIds.slice,
+       core_indexOf = core_deletedIds.indexOf,
+       core_toString = class2type.toString,
+       core_hasOwn = class2type.hasOwnProperty,
+       core_trim = core_version.trim,
+
+       // Define a local copy of jQuery
+       jQuery = function( selector, context ) {
+               // The jQuery object is actually just the init constructor 'enhanced'
+               return new jQuery.fn.init( selector, context, rootjQuery );
+       },
+
+       // Used for matching numbers
+       core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+       // Used for splitting on whitespace
+       core_rnotwhite = /\S+/g,
+
+       // A simple way to check for HTML strings
+       // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+       // Strict HTML recognition (#11290: must start with <)
+       rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+       // Match a standalone tag
+       rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
+
+       // Matches dashed string for camelizing
+       rmsPrefix = /^-ms-/,
+       rdashAlpha = /-([\da-z])/gi,
+
+       // Used by jQuery.camelCase as callback to replace()
+       fcamelCase = function( all, letter ) {
+               return letter.toUpperCase();
+       },
+
+       // The ready event handler and self cleanup method
+       completed = function() {
+               document.removeEventListener( "DOMContentLoaded", completed, false );
+               window.removeEventListener( "load", completed, false );
+               jQuery.ready();
+       };
+
+jQuery.fn = jQuery.prototype = {
+       // The current version of jQuery being used
+       jquery: core_version,
+
+       constructor: jQuery,
+       init: function( selector, context, rootjQuery ) {
+               var match, elem;
+
+               // HANDLE: $(""), $(null), $(undefined), $(false)
+               if ( !selector ) {
+                       return this;
+               }
+
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+                               // Assume that strings that start and end with <> are HTML and skip the regex check
+                               match = [ null, selector, null ];
+
+                       } else {
+                               match = rquickExpr.exec( selector );
+                       }
+
+                       // Match html or make sure no context is specified for #id
+                       if ( match && (match[1] || !context) ) {
+
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[1] ) {
+                                       context = context instanceof jQuery ? context[0] : context;
+
+                                       // scripts is true for back-compat
+                                       jQuery.merge( this, jQuery.parseHTML(
+                                               match[1],
+                                               context && context.nodeType ? context.ownerDocument || context : document,
+                                               true
+                                       ) );
+
+                                       // HANDLE: $(html, props)
+                                       if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+                                               for ( match in context ) {
+                                                       // Properties of context are called as methods if possible
+                                                       if ( jQuery.isFunction( this[ match ] ) ) {
+                                                               this[ match ]( context[ match ] );
+
+                                                       // ...and otherwise set as attributes
+                                                       } else {
+                                                               this.attr( match, context[ match ] );
+                                                       }
+                                               }
+                                       }
+
+                                       return this;
+
+                               // HANDLE: $(#id)
+                               } else {
+                                       elem = document.getElementById( match[2] );
+
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document #6963
+                                       if ( elem && elem.parentNode ) {
+                                               // Inject the element directly into the jQuery object
+                                               this.length = 1;
+                                               this[0] = elem;
+                                       }
+
+                                       this.context = document;
+                                       this.selector = selector;
+                                       return this;
+                               }
+
+                       // HANDLE: $(expr, $(...))
+                       } else if ( !context || context.jquery ) {
+                               return ( context || rootjQuery ).find( selector );
+
+                       // HANDLE: $(expr, context)
+                       // (which is just equivalent to: $(context).find(expr)
+                       } else {
+                               return this.constructor( context ).find( selector );
+                       }
+
+               // HANDLE: $(DOMElement)
+               } else if ( selector.nodeType ) {
+                       this.context = this[0] = selector;
+                       this.length = 1;
+                       return this;
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction( selector ) ) {
+                       return rootjQuery.ready( selector );
+               }
+
+               if ( selector.selector !== undefined ) {
+                       this.selector = selector.selector;
+                       this.context = selector.context;
+               }
+
+               return jQuery.makeArray( selector, this );
+       },
+
+       // Start with an empty selector
+       selector: "",
+
+       // The default length of a jQuery object is 0
+       length: 0,
+
+       toArray: function() {
+               return core_slice.call( this );
+       },
+
+       // Get the Nth element in the matched element set OR
+       // Get the whole matched element set as a clean array
+       get: function( num ) {
+               return num == null ?
+
+                       // Return a 'clean' array
+                       this.toArray() :
+
+                       // Return just the object
+                       ( num < 0 ? this[ this.length + num ] : this[ num ] );
+       },
+
+       // Take an array of elements and push it onto the stack
+       // (returning the new matched element set)
+       pushStack: function( elems ) {
+
+               // Build a new jQuery matched element set
+               var ret = jQuery.merge( this.constructor(), elems );
+
+               // Add the old object onto the stack (as a reference)
+               ret.prevObject = this;
+               ret.context = this.context;
+
+               // Return the newly-formed element set
+               return ret;
+       },
+
+       // Execute a callback for every element in the matched set.
+       // (You can seed the arguments with an array of args, but this is
+       // only used internally.)
+       each: function( callback, args ) {
+               return jQuery.each( this, callback, args );
+       },
+
+       ready: function( fn ) {
+               // Add the callback
+               jQuery.ready.promise().done( fn );
+
+               return this;
+       },
+
+       slice: function() {
+               return this.pushStack( core_slice.apply( this, arguments ) );
+       },
+
+       first: function() {
+               return this.eq( 0 );
+       },
+
+       last: function() {
+               return this.eq( -1 );
+       },
+
+       eq: function( i ) {
+               var len = this.length,
+                       j = +i + ( i < 0 ? len : 0 );
+               return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+       },
+
+       map: function( callback ) {
+               return this.pushStack( jQuery.map(this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               }));
+       },
+
+       end: function() {
+               return this.prevObject || this.constructor(null);
+       },
+
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: core_push,
+       sort: [].sort,
+       splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+       var options, name, src, copy, copyIsArray, clone,
+               target = arguments[0] || {},
+               i = 1,
+               length = arguments.length,
+               deep = false;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+               target = arguments[1] || {};
+               // skip the boolean and the target
+               i = 2;
+       }
+
+       // Handle case when target is a string or something (possible in deep copy)
+       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+               target = {};
+       }
+
+       // extend jQuery itself if only one argument is passed
+       if ( length === i ) {
+               target = this;
+               --i;
+       }
+
+       for ( ; i < length; i++ ) {
+               // Only deal with non-null/undefined values
+               if ( (options = arguments[ i ]) != null ) {
+                       // Extend the base object
+                       for ( name in options ) {
+                               src = target[ name ];
+                               copy = options[ name ];
+
+                               // Prevent never-ending loop
+                               if ( target === copy ) {
+                                       continue;
+                               }
+
+                               // Recurse if we're merging plain objects or arrays
+                               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                                       if ( copyIsArray ) {
+                                               copyIsArray = false;
+                                               clone = src && jQuery.isArray(src) ? src : [];
+
+                                       } else {
+                                               clone = src && jQuery.isPlainObject(src) ? src : {};
+                                       }
+
+                                       // Never move original objects, clone them
+                                       target[ name ] = jQuery.extend( deep, clone, copy );
+
+                               // Don't bring in undefined values
+                               } else if ( copy !== undefined ) {
+                                       target[ name ] = copy;
+                               }
+                       }
+               }
+       }
+
+       // Return the modified object
+       return target;
+};
+
+jQuery.extend({
+       // Unique for each copy of jQuery on the page
+       expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
+       noConflict: function( deep ) {
+               if ( window.$ === jQuery ) {
+                       window.$ = _$;
+               }
+
+               if ( deep && window.jQuery === jQuery ) {
+                       window.jQuery = _jQuery;
+               }
+
+               return jQuery;
+       },
+
+       // Is the DOM ready to be used? Set to true once it occurs.
+       isReady: false,
+
+       // A counter to track how many items to wait for before
+       // the ready event fires. See #6781
+       readyWait: 1,
+
+       // Hold (or release) the ready event
+       holdReady: function( hold ) {
+               if ( hold ) {
+                       jQuery.readyWait++;
+               } else {
+                       jQuery.ready( true );
+               }
+       },
+
+       // Handle when the DOM is ready
+       ready: function( wait ) {
+
+               // Abort if there are pending holds or we're already ready
+               if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+                       return;
+               }
+
+               // Remember that the DOM is ready
+               jQuery.isReady = true;
+
+               // If a normal DOM Ready event fired, decrement, and wait if need be
+               if ( wait !== true && --jQuery.readyWait > 0 ) {
+                       return;
+               }
+
+               // If there are functions bound, to execute
+               readyList.resolveWith( document, [ jQuery ] );
+
+               // Trigger any bound ready events
+               if ( jQuery.fn.trigger ) {
+                       jQuery( document ).trigger("ready").off("ready");
+               }
+       },
+
+       // See test/unit/core.js for details concerning isFunction.
+       // Since version 1.3, DOM methods and functions like alert
+       // aren't supported. They return false on IE (#2968).
+       isFunction: function( obj ) {
+               return jQuery.type(obj) === "function";
+       },
+
+       isArray: Array.isArray,
+
+       isWindow: function( obj ) {
+               return obj != null && obj === obj.window;
+       },
+
+       isNumeric: function( obj ) {
+               return !isNaN( parseFloat(obj) ) && isFinite( obj );
+       },
+
+       type: function( obj ) {
+               if ( obj == null ) {
+                       return String( obj );
+               }
+               // Support: Safari <= 5.1 (functionish RegExp)
+               return typeof obj === "object" || typeof obj === "function" ?
+                       class2type[ core_toString.call(obj) ] || "object" :
+                       typeof obj;
+       },
+
+       isPlainObject: function( obj ) {
+               // Not plain objects:
+               // - Any object or value whose internal [[Class]] property is not "[object Object]"
+               // - DOM nodes
+               // - window
+               if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+                       return false;
+               }
+
+               // Support: Firefox <20
+               // The try/catch suppresses exceptions thrown when attempting to access
+               // the "constructor" property of certain host objects, ie. |window.location|
+               // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
+               try {
+                       if ( obj.constructor &&
+                                       !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
+                               return false;
+                       }
+               } catch ( e ) {
+                       return false;
+               }
+
+               // If the function hasn't returned already, we're confident that
+               // |obj| is a plain object, created by {} or constructed with new Object
+               return true;
+       },
+
+       isEmptyObject: function( obj ) {
+               var name;
+               for ( name in obj ) {
+                       return false;
+               }
+               return true;
+       },
+
+       error: function( msg ) {
+               throw new Error( msg );
+       },
+
+       // data: string of html
+       // context (optional): If specified, the fragment will be created in this context, defaults to document
+       // keepScripts (optional): If true, will include scripts passed in the html string
+       parseHTML: function( data, context, keepScripts ) {
+               if ( !data || typeof data !== "string" ) {
+                       return null;
+               }
+               if ( typeof context === "boolean" ) {
+                       keepScripts = context;
+                       context = false;
+               }
+               context = context || document;
+
+               var parsed = rsingleTag.exec( data ),
+                       scripts = !keepScripts && [];
+
+               // Single tag
+               if ( parsed ) {
+                       return [ context.createElement( parsed[1] ) ];
+               }
+
+               parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+               if ( scripts ) {
+                       jQuery( scripts ).remove();
+               }
+
+               return jQuery.merge( [], parsed.childNodes );
+       },
+
+       parseJSON: JSON.parse,
+
+       // Cross-browser xml parsing
+       parseXML: function( data ) {
+               var xml, tmp;
+               if ( !data || typeof data !== "string" ) {
+                       return null;
+               }
+
+               // Support: IE9
+               try {
+                       tmp = new DOMParser();
+                       xml = tmp.parseFromString( data , "text/xml" );
+               } catch ( e ) {
+                       xml = undefined;
+               }
+
+               if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+                       jQuery.error( "Invalid XML: " + data );
+               }
+               return xml;
+       },
+
+       noop: function() {},
+
+       // Evaluates a script in a global context
+       globalEval: function( code ) {
+               var script,
+                               indirect = eval;
+
+               code = jQuery.trim( code );
+
+               if ( code ) {
+                       // If the code includes a valid, prologue position
+                       // strict mode pragma, execute code by injecting a
+                       // script tag into the document.
+                       if ( code.indexOf("use strict") === 1 ) {
+                               script = document.createElement("script");
+                               script.text = code;
+                               document.head.appendChild( script ).parentNode.removeChild( script );
+                       } else {
+                       // Otherwise, avoid the DOM node creation, insertion
+                       // and removal by using an indirect global eval
+                               indirect( code );
+                       }
+               }
+       },
+
+       // Convert dashed to camelCase; used by the css and data modules
+       // Microsoft forgot to hump their vendor prefix (#9572)
+       camelCase: function( string ) {
+               return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+       },
+
+       nodeName: function( elem, name ) {
+               return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+       },
+
+       // args is for internal usage only
+       each: function( obj, callback, args ) {
+               var value,
+                       i = 0,
+                       length = obj.length,
+                       isArray = isArraylike( obj );
+
+               if ( args ) {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.apply( obj[ i ], args );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.apply( obj[ i ], args );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+
+               // A special, fast, case for the most common use of each
+               } else {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.call( obj[ i ], i, obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.call( obj[ i ], i, obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return obj;
+       },
+
+       trim: function( text ) {
+               return text == null ? "" : core_trim.call( text );
+       },
+
+       // results is for internal usage only
+       makeArray: function( arr, results ) {
+               var ret = results || [];
+
+               if ( arr != null ) {
+                       if ( isArraylike( Object(arr) ) ) {
+                               jQuery.merge( ret,
+                                       typeof arr === "string" ?
+                                       [ arr ] : arr
+                               );
+                       } else {
+                               core_push.call( ret, arr );
+                       }
+               }
+
+               return ret;
+       },
+
+       inArray: function( elem, arr, i ) {
+               return arr == null ? -1 : core_indexOf.call( arr, elem, i );
+       },
+
+       merge: function( first, second ) {
+               var l = second.length,
+                       i = first.length,
+                       j = 0;
+
+               if ( typeof l === "number" ) {
+                       for ( ; j < l; j++ ) {
+                               first[ i++ ] = second[ j ];
+                       }
+               } else {
+                       while ( second[j] !== undefined ) {
+                               first[ i++ ] = second[ j++ ];
+                       }
+               }
+
+               first.length = i;
+
+               return first;
+       },
+
+       grep: function( elems, callback, inv ) {
+               var retVal,
+                       ret = [],
+                       i = 0,
+                       length = elems.length;
+               inv = !!inv;
+
+               // Go through the array, only saving the items
+               // that pass the validator function
+               for ( ; i < length; i++ ) {
+                       retVal = !!callback( elems[ i ], i );
+                       if ( inv !== retVal ) {
+                               ret.push( elems[ i ] );
+                       }
+               }
+
+               return ret;
+       },
+
+       // arg is for internal usage only
+       map: function( elems, callback, arg ) {
+               var value,
+                       i = 0,
+                       length = elems.length,
+                       isArray = isArraylike( elems ),
+                       ret = [];
+
+               // Go through the array, translating each of the items to their
+               if ( isArray ) {
+                       for ( ; i < length; i++ ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret[ ret.length ] = value;
+                               }
+                       }
+
+               // Go through every key on the object,
+               } else {
+                       for ( i in elems ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret[ ret.length ] = value;
+                               }
+                       }
+               }
+
+               // Flatten any nested arrays
+               return core_concat.apply( [], ret );
+       },
+
+       // A global GUID counter for objects
+       guid: 1,
+
+       // Bind a function to a context, optionally partially applying any
+       // arguments.
+       proxy: function( fn, context ) {
+               var tmp, args, proxy;
+
+               if ( typeof context === "string" ) {
+                       tmp = fn[ context ];
+                       context = fn;
+                       fn = tmp;
+               }
+
+               // Quick check to determine if target is callable, in the spec
+               // this throws a TypeError, but we will just return undefined.
+               if ( !jQuery.isFunction( fn ) ) {
+                       return undefined;
+               }
+
+               // Simulated bind
+               args = core_slice.call( arguments, 2 );
+               proxy = function() {
+                       return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+               };
+
+               // Set the guid of unique handler to the same of original handler, so it can be removed
+               proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+               return proxy;
+       },
+
+       // Multifunctional method to get and set values of a collection
+       // The value/s can optionally be executed if it's a function
+       access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+               var i = 0,
+                       length = elems.length,
+                       bulk = key == null;
+
+               // Sets many values
+               if ( jQuery.type( key ) === "object" ) {
+                       chainable = true;
+                       for ( i in key ) {
+                               jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+                       }
+
+               // Sets one value
+               } else if ( value !== undefined ) {
+                       chainable = true;
+
+                       if ( !jQuery.isFunction( value ) ) {
+                               raw = true;
+                       }
+
+                       if ( bulk ) {
+                               // Bulk operations run against the entire set
+                               if ( raw ) {
+                                       fn.call( elems, value );
+                                       fn = null;
+
+                               // ...except when executing function values
+                               } else {
+                                       bulk = fn;
+                                       fn = function( elem, key, value ) {
+                                               return bulk.call( jQuery( elem ), value );
+                                       };
+                               }
+                       }
+
+                       if ( fn ) {
+                               for ( ; i < length; i++ ) {
+                                       fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+                               }
+                       }
+               }
+
+               return chainable ?
+                       elems :
+
+                       // Gets
+                       bulk ?
+                               fn.call( elems ) :
+                               length ? fn( elems[0], key ) : emptyGet;
+       },
+
+       now: Date.now,
+
+       // A method for quickly swapping in/out CSS properties to get correct calculations.
+       // Note: this method belongs to the css module but it's needed here for the support module.
+       // If support gets modularized, this method should be moved back to the css module.
+       swap: function( elem, options, callback, args ) {
+               var ret, name,
+                       old = {};
+
+               // Remember the old values, and insert the new ones
+               for ( name in options ) {
+                       old[ name ] = elem.style[ name ];
+                       elem.style[ name ] = options[ name ];
+               }
+
+               ret = callback.apply( elem, args || [] );
+
+               // Revert the old values
+               for ( name in options ) {
+                       elem.style[ name ] = old[ name ];
+               }
+
+               return ret;
+       }
+});
+
+jQuery.ready.promise = function( obj ) {
+       if ( !readyList ) {
+
+               readyList = jQuery.Deferred();
+
+               // Catch cases where $(document).ready() is called after the browser event has already occurred.
+               // we once tried to use readyState "interactive" here, but it caused issues like the one
+               // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+               if ( document.readyState === "complete" ) {
+                       // Handle it asynchronously to allow scripts the opportunity to delay ready
+                       setTimeout( jQuery.ready );
+
+               } else {
+
+                       // Use the handy event callback
+                       document.addEventListener( "DOMContentLoaded", completed, false );
+
+                       // A fallback to window.onload, that will always work
+                       window.addEventListener( "load", completed, false );
+               }
+       }
+       return readyList.promise( obj );
+};
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+       var length = obj.length,
+               type = jQuery.type( obj );
+
+       if ( jQuery.isWindow( obj ) ) {
+               return false;
+       }
+
+       if ( obj.nodeType === 1 && length ) {
+               return true;
+       }
+
+       return type === "array" || type !== "function" &&
+               ( length === 0 ||
+               typeof length === "number" && length > 0 && ( length - 1 ) in obj );
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+/*!
+ * Sizzle CSS Selector Engine v1.9.4-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-05-27
+ */
+(function( window, undefined ) {
+
+var i,
+       support,
+       cachedruns,
+       Expr,
+       getText,
+       isXML,
+       compile,
+       outermostContext,
+       sortInput,
+
+       // Local document vars
+       setDocument,
+       document,
+       docElem,
+       documentIsHTML,
+       rbuggyQSA,
+       rbuggyMatches,
+       matches,
+       contains,
+
+       // Instance-specific data
+       expando = "sizzle" + -(new Date()),
+       preferredDoc = window.document,
+       dirruns = 0,
+       done = 0,
+       classCache = createCache(),
+       tokenCache = createCache(),
+       compilerCache = createCache(),
+       hasDuplicate = false,
+       sortOrder = function() { return 0; },
+
+       // General-purpose constants
+       strundefined = typeof undefined,
+       MAX_NEGATIVE = 1 << 31,
+
+       // Instance methods
+       hasOwn = ({}).hasOwnProperty,
+       arr = [],
+       pop = arr.pop,
+       push_native = arr.push,
+       push = arr.push,
+       slice = arr.slice,
+       // Use a stripped-down indexOf if we can't use a native one
+       indexOf = arr.indexOf || function( elem ) {
+               var i = 0,
+                       len = this.length;
+               for ( ; i < len; i++ ) {
+                       if ( this[i] === elem ) {
+                               return i;
+                       }
+               }
+               return -1;
+       },
+
+       booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+       // Regular expressions
+
+       // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+       whitespace = "[\\x20\\t\\r\\n\\f]",
+       // http://www.w3.org/TR/css3-syntax/#characters
+       characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+       // Loosely modeled on CSS identifier characters
+       // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+       // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+       identifier = characterEncoding.replace( "w", "w#" ),
+
+       // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+       attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+               "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+       // Prefer arguments quoted,
+       //   then not containing pseudos/brackets,
+       //   then attribute selectors/non-parenthetical expressions,
+       //   then anything else
+       // These preferences are here to reduce the number of selectors
+       //   needing tokenize in the PSEUDO preFilter
+       pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+       // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+       rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+       rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+       rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+       rsibling = new RegExp( whitespace + "*[+~]" ),
+       rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
+
+       rpseudo = new RegExp( pseudos ),
+       ridentifier = new RegExp( "^" + identifier + "$" ),
+
+       matchExpr = {
+               "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+               "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+               "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+               "ATTR": new RegExp( "^" + attributes ),
+               "PSEUDO": new RegExp( "^" + pseudos ),
+               "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+                       "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+                       "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+               "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+               // For use in libraries implementing .is()
+               // We use this for POS matching in `select`
+               "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+                       whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+       },
+
+       rnative = /^[^{]+\{\s*\[native \w/,
+
+       // Easily-parseable/retrievable ID or TAG or CLASS selectors
+       rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+       rinputs = /^(?:input|select|textarea|button)$/i,
+       rheader = /^h\d$/i,
+
+       rescape = /'|\\/g,
+
+       // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+       runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+       funescape = function( _, escaped, escapedWhitespace ) {
+               var high = "0x" + escaped - 0x10000;
+               // NaN means non-codepoint
+               // Support: Firefox
+               // Workaround erroneous numeric interpretation of +"0x"
+               return high !== high || escapedWhitespace ?
+                       escaped :
+                       // BMP codepoint
+                       high < 0 ?
+                               String.fromCharCode( high + 0x10000 ) :
+                               // Supplemental Plane codepoint (surrogate pair)
+                               String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+       };
+
+// Optimize for push.apply( _, NodeList )
+try {
+       push.apply(
+               (arr = slice.call( preferredDoc.childNodes )),
+               preferredDoc.childNodes
+       );
+       // Support: Android<4.0
+       // Detect silently failing push.apply
+       arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+       push = { apply: arr.length ?
+
+               // Leverage slice if possible
+               function( target, els ) {
+                       push_native.apply( target, slice.call(els) );
+               } :
+
+               // Support: IE<9
+               // Otherwise append directly
+               function( target, els ) {
+                       var j = target.length,
+                               i = 0;
+                       // Can't trust NodeList.length
+                       while ( (target[j++] = els[i++]) ) {}
+                       target.length = j - 1;
+               }
+       };
+}
+
+function Sizzle( selector, context, results, seed ) {
+       var match, elem, m, nodeType,
+               // QSA vars
+               i, groups, old, nid, newContext, newSelector;
+
+       if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+               setDocument( context );
+       }
+
+       context = context || document;
+       results = results || [];
+
+       if ( !selector || typeof selector !== "string" ) {
+               return results;
+       }
+
+       if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+               return [];
+       }
+
+       if ( documentIsHTML && !seed ) {
+
+               // Shortcuts
+               if ( (match = rquickExpr.exec( selector )) ) {
+                       // Speed-up: Sizzle("#ID")
+                       if ( (m = match[1]) ) {
+                               if ( nodeType === 9 ) {
+                                       elem = context.getElementById( m );
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document #6963
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE, Opera, and Webkit return items
+                                               // by name instead of ID
+                                               if ( elem.id === m ) {
+                                                       results.push( elem );
+                                                       return results;
+                                               }
+                                       } else {
+                                               return results;
+                                       }
+                               } else {
+                                       // Context is not a document
+                                       if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+                                               contains( context, elem ) && elem.id === m ) {
+                                               results.push( elem );
+                                               return results;
+                                       }
+                               }
+
+                       // Speed-up: Sizzle("TAG")
+                       } else if ( match[2] ) {
+                               push.apply( results, context.getElementsByTagName( selector ) );
+                               return results;
+
+                       // Speed-up: Sizzle(".CLASS")
+                       } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+                               push.apply( results, context.getElementsByClassName( m ) );
+                               return results;
+                       }
+               }
+
+               // QSA path
+               if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+                       nid = old = expando;
+                       newContext = context;
+                       newSelector = nodeType === 9 && selector;
+
+                       // qSA works strangely on Element-rooted queries
+                       // We can work around this by specifying an extra ID on the root
+                       // and working up from there (Thanks to Andrew Dupont for the technique)
+                       // IE 8 doesn't work on object elements
+                       if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+                               groups = tokenize( selector );
+
+                               if ( (old = context.getAttribute("id")) ) {
+                                       nid = old.replace( rescape, "\\$&" );
+                               } else {
+                                       context.setAttribute( "id", nid );
+                               }
+                               nid = "[id='" + nid + "'] ";
+
+                               i = groups.length;
+                               while ( i-- ) {
+                                       groups[i] = nid + toSelector( groups[i] );
+                               }
+                               newContext = rsibling.test( selector ) && context.parentNode || context;
+                               newSelector = groups.join(",");
+                       }
+
+                       if ( newSelector ) {
+                               try {
+                                       push.apply( results,
+                                               newContext.querySelectorAll( newSelector )
+                                       );
+                                       return results;
+                               } catch(qsaError) {
+                               } finally {
+                                       if ( !old ) {
+                                               context.removeAttribute("id");
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // All others
+       return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * For feature detection
+ * @param {Function} fn The function to test for native support
+ */
+function isNative( fn ) {
+       return rnative.test( fn + "" );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ *     property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *     deleting the oldest entry
+ */
+function createCache() {
+       var keys = [];
+
+       function cache( key, value ) {
+               // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+               if ( keys.push( key += " " ) > Expr.cacheLength ) {
+                       // Only keep the most recent entries
+                       delete cache[ keys.shift() ];
+               }
+               return (cache[ key ] = value);
+       }
+       return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+       fn[ expando ] = true;
+       return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+       var div = document.createElement("div");
+
+       try {
+               return !!fn( div );
+       } catch (e) {
+               return false;
+       } finally {
+               // Remove from its parent by default
+               if ( div.parentNode ) {
+                       div.parentNode.removeChild( div );
+               }
+               // release memory in IE
+               div = null;
+       }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied if the test fails
+ * @param {Boolean} test The result of a test. If true, null will be set as the handler in leiu of the specified handler
+ */
+function addHandle( attrs, handler, test ) {
+       attrs = attrs.split("|");
+       var current,
+               i = attrs.length,
+               setHandle = test ? null : handler;
+
+       while ( i-- ) {
+               // Don't override a user's handler
+               if ( !(current = Expr.attrHandle[ attrs[i] ]) || current === handler ) {
+                       Expr.attrHandle[ attrs[i] ] = setHandle;
+               }
+       }
+}
+
+/**
+ * Fetches boolean attributes by node
+ * @param {Element} elem
+ * @param {String} name
+ */
+function boolHandler( elem, name ) {
+       // XML does not need to be checked as this will not be assigned for XML documents
+       var val = elem.getAttributeNode( name );
+       return val && val.specified ?
+               val.value :
+               elem[ name ] === true ? name.toLowerCase() : null;
+}
+
+/**
+ * Fetches attributes without interpolation
+ * http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+ * @param {Element} elem
+ * @param {String} name
+ */
+function interpolationHandler( elem, name ) {
+       // XML does not need to be checked as this will not be assigned for XML documents
+       return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+}
+
+/**
+ * Uses defaultValue to retrieve value in IE6/7
+ * @param {Element} elem
+ * @param {String} name
+ */
+function valueHandler( elem ) {
+       // Ignore the value *property* on inputs by using defaultValue
+       // Fallback to Sizzle.attr by returning undefined where appropriate
+       // XML does not need to be checked as this will not be assigned for XML documents
+       if ( elem.nodeName.toLowerCase() === "input" ) {
+               return elem.defaultValue;
+       }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns Returns -1 if a precedes b, 1 if a follows b
+ */
+function siblingCheck( a, b ) {
+       var cur = b && a,
+               diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+                       ( ~b.sourceIndex || MAX_NEGATIVE ) -
+                       ( ~a.sourceIndex || MAX_NEGATIVE );
+
+       // Use IE sourceIndex if available on both nodes
+       if ( diff ) {
+               return diff;
+       }
+
+       // Check if b follows a
+       if ( cur ) {
+               while ( (cur = cur.nextSibling) ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+               }
+       }
+
+       return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return name === "input" && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return (name === "input" || name === "button") && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+       return markFunction(function( argument ) {
+               argument = +argument;
+               return markFunction(function( seed, matches ) {
+                       var j,
+                               matchIndexes = fn( [], seed.length, argument ),
+                               i = matchIndexes.length;
+
+                       // Match elements found at the specified indexes
+                       while ( i-- ) {
+                               if ( seed[ (j = matchIndexes[i]) ] ) {
+                                       seed[j] = !(matches[j] = seed[j]);
+                               }
+                       }
+               });
+       });
+}
+
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+       // documentElement is verified for cases where it doesn't yet exist
+       // (such as loading iframes in IE - #4833)
+       var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+       return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+       var doc = node ? node.ownerDocument || node : preferredDoc,
+               parent = doc.parentWindow;
+
+       // If no document and documentElement is available, return
+       if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+               return document;
+       }
+
+       // Set our document
+       document = doc;
+       docElem = doc.documentElement;
+
+       // Support tests
+       documentIsHTML = !isXML( doc );
+
+       // Support: IE>8
+       // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+       // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+       if ( parent && parent.frameElement ) {
+               parent.attachEvent( "onbeforeunload", function() {
+                       setDocument();
+               });
+       }
+
+       /* Attributes
+       ---------------------------------------------------------------------- */
+
+       // Support: IE<8
+       // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+       support.attributes = assert(function( div ) {
+
+               // Support: IE<8
+               // Prevent attribute/property "interpolation"
+               div.innerHTML = "<a href='#'></a>";
+               addHandle( "type|href|height|width", interpolationHandler, div.firstChild.getAttribute("href") === "#" );
+
+               // Support: IE<9
+               // Use getAttributeNode to fetch booleans when getAttribute lies
+               addHandle( booleans, boolHandler, div.getAttribute("disabled") == null );
+
+               div.className = "i";
+               return !div.getAttribute("className");
+       });
+
+       // Support: IE<9
+       // Retrieving value should defer to defaultValue
+       support.input = assert(function( div ) {
+               div.innerHTML = "<input>";
+               div.firstChild.setAttribute( "value", "" );
+               return div.firstChild.getAttribute( "value" ) === "";
+       });
+
+       // IE6/7 still return empty string for value,
+       // but are actually retrieving the property
+       addHandle( "value", valueHandler, support.attributes && support.input );
+
+       /* getElement(s)By*
+       ---------------------------------------------------------------------- */
+
+       // Check if getElementsByTagName("*") returns only elements
+       support.getElementsByTagName = assert(function( div ) {
+               div.appendChild( doc.createComment("") );
+               return !div.getElementsByTagName("*").length;
+       });
+
+       // Check if getElementsByClassName can be trusted
+       support.getElementsByClassName = assert(function( div ) {
+               div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+               // Support: Safari<4
+               // Catch class over-caching
+               div.firstChild.className = "i";
+               // Support: Opera<10
+               // Catch gEBCN failure to find non-leading classes
+               return div.getElementsByClassName("i").length === 2;
+       });
+
+       // Support: IE<10
+       // Check if getElementById returns elements by name
+       // The broken getElementById methods don't pick up programatically-set names,
+       // so use a roundabout getElementsByName test
+       support.getById = assert(function( div ) {
+               docElem.appendChild( div ).id = expando;
+               return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+       });
+
+       // ID find and filter
+       if ( support.getById ) {
+               Expr.find["ID"] = function( id, context ) {
+                       if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+                               var m = context.getElementById( id );
+                               // Check parentNode to catch when Blackberry 4.6 returns
+                               // nodes that are no longer in the document #6963
+                               return m && m.parentNode ? [m] : [];
+                       }
+               };
+               Expr.filter["ID"] = function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               return elem.getAttribute("id") === attrId;
+                       };
+               };
+       } else {
+               // Support: IE6/7
+               // getElementById is not reliable as a find shortcut
+               delete Expr.find["ID"];
+
+               Expr.filter["ID"] =  function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+                               return node && node.value === attrId;
+                       };
+               };
+       }
+
+       // Tag
+       Expr.find["TAG"] = support.getElementsByTagName ?
+               function( tag, context ) {
+                       if ( typeof context.getElementsByTagName !== strundefined ) {
+                               return context.getElementsByTagName( tag );
+                       }
+               } :
+               function( tag, context ) {
+                       var elem,
+                               tmp = [],
+                               i = 0,
+                               results = context.getElementsByTagName( tag );
+
+                       // Filter out possible comments
+                       if ( tag === "*" ) {
+                               while ( (elem = results[i++]) ) {
+                                       if ( elem.nodeType === 1 ) {
+                                               tmp.push( elem );
+                                       }
+                               }
+
+                               return tmp;
+                       }
+                       return results;
+               };
+
+       // Class
+       Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+               if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+                       return context.getElementsByClassName( className );
+               }
+       };
+
+       /* QSA/matchesSelector
+       ---------------------------------------------------------------------- */
+
+       // QSA and matchesSelector support
+
+       // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+       rbuggyMatches = [];
+
+       // qSa(:focus) reports false when true (Chrome 21)
+       // We allow this because of a bug in IE8/9 that throws an error
+       // whenever `document.activeElement` is accessed on an iframe
+       // So, we allow :focus to pass through QSA all the time to avoid the IE error
+       // See http://bugs.jquery.com/ticket/13378
+       rbuggyQSA = [];
+
+       if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
+               // Build QSA regex
+               // Regex strategy adopted from Diego Perini
+               assert(function( div ) {
+                       // Select is set to empty string on purpose
+                       // This is to test IE's treatment of not explicitly
+                       // setting a boolean content attribute,
+                       // since its presence should be enough
+                       // http://bugs.jquery.com/ticket/12359
+                       div.innerHTML = "<select><option selected=''></option></select>";
+
+                       // Support: IE8
+                       // Boolean attributes and "value" are not treated correctly
+                       if ( !div.querySelectorAll("[selected]").length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+                       }
+
+                       // Webkit/Opera - :checked should return selected option elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       // IE8 throws error here and will not see later tests
+                       if ( !div.querySelectorAll(":checked").length ) {
+                               rbuggyQSA.push(":checked");
+                       }
+               });
+
+               assert(function( div ) {
+
+                       // Support: Opera 10-12/IE8
+                       // ^= $= *= and empty values
+                       // Should not select anything
+                       // Support: Windows 8 Native Apps
+                       // The type attribute is restricted during .innerHTML assignment
+                       var input = doc.createElement("input");
+                       input.setAttribute( "type", "hidden" );
+                       div.appendChild( input ).setAttribute( "t", "" );
+
+                       if ( div.querySelectorAll("[t^='']").length ) {
+                               rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+                       }
+
+                       // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+                       // IE8 throws error here and will not see later tests
+                       if ( !div.querySelectorAll(":enabled").length ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
+
+                       // Opera 10-11 does not throw on post-comma invalid pseudos
+                       div.querySelectorAll("*,:x");
+                       rbuggyQSA.push(",.*:");
+               });
+       }
+
+       if ( (support.matchesSelector = isNative( (matches = docElem.webkitMatchesSelector ||
+               docElem.mozMatchesSelector ||
+               docElem.oMatchesSelector ||
+               docElem.msMatchesSelector) )) ) {
+
+               assert(function( div ) {
+                       // Check to see if it's possible to do matchesSelector
+                       // on a disconnected node (IE 9)
+                       support.disconnectedMatch = matches.call( div, "div" );
+
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( div, "[s!='']:x" );
+                       rbuggyMatches.push( "!=", pseudos );
+               });
+       }
+
+       rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+       rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+       /* Contains
+       ---------------------------------------------------------------------- */
+
+       // Element contains another
+       // Purposefully does not implement inclusive descendent
+       // As in, an element does not contain itself
+       contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
+               function( a, b ) {
+                       var adown = a.nodeType === 9 ? a.documentElement : a,
+                               bup = b && b.parentNode;
+                       return a === bup || !!( bup && bup.nodeType === 1 && (
+                               adown.contains ?
+                                       adown.contains( bup ) :
+                                       a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+                       ));
+               } :
+               function( a, b ) {
+                       if ( b ) {
+                               while ( (b = b.parentNode) ) {
+                                       if ( b === a ) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               };
+
+       /* Sorting
+       ---------------------------------------------------------------------- */
+
+       // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+       // Detached nodes confoundingly follow *each other*
+       support.sortDetached = assert(function( div1 ) {
+               // Should return 1, but returns 4 (following)
+               return div1.compareDocumentPosition( doc.createElement("div") ) & 1;
+       });
+
+       // Document order sorting
+       sortOrder = docElem.compareDocumentPosition ?
+       function( a, b ) {
+
+               // Flag for duplicate removal
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
+
+               if ( compare ) {
+                       // Disconnected nodes
+                       if ( compare & 1 ||
+                               (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+                               // Choose the first element that is related to our preferred document
+                               if ( a === doc || contains(preferredDoc, a) ) {
+                                       return -1;
+                               }
+                               if ( b === doc || contains(preferredDoc, b) ) {
+                                       return 1;
+                               }
+
+                               // Maintain original order
+                               return sortInput ?
+                                       ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+                                       0;
+                       }
+
+                       return compare & 4 ? -1 : 1;
+               }
+
+               // Not directly comparable, sort on existence of method
+               return a.compareDocumentPosition ? -1 : 1;
+       } :
+       function( a, b ) {
+               var cur,
+                       i = 0,
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       ap = [ a ],
+                       bp = [ b ];
+
+               // Exit early if the nodes are identical
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+
+               // Parentless nodes are either documents or disconnected
+               } else if ( !aup || !bup ) {
+                       return a === doc ? -1 :
+                               b === doc ? 1 :
+                               aup ? -1 :
+                               bup ? 1 :
+                               sortInput ?
+                               ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+                               0;
+
+               // If the nodes are siblings, we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+               }
+
+               // Otherwise we need full lists of their ancestors for comparison
+               cur = a;
+               while ( (cur = cur.parentNode) ) {
+                       ap.unshift( cur );
+               }
+               cur = b;
+               while ( (cur = cur.parentNode) ) {
+                       bp.unshift( cur );
+               }
+
+               // Walk down the tree looking for a discrepancy
+               while ( ap[i] === bp[i] ) {
+                       i++;
+               }
+
+               return i ?
+                       // Do a sibling check if the nodes have a common ancestor
+                       siblingCheck( ap[i], bp[i] ) :
+
+                       // Otherwise nodes in our document sort first
+                       ap[i] === preferredDoc ? -1 :
+                       bp[i] === preferredDoc ? 1 :
+                       0;
+       };
+
+       return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+       return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       // Make sure that attribute selectors are quoted
+       expr = expr.replace( rattributeQuotes, "='$1']" );
+
+       if ( support.matchesSelector && documentIsHTML &&
+               ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+               ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+               try {
+                       var ret = matches.call( elem, expr );
+
+                       // IE 9's matchesSelector returns false on disconnected nodes
+                       if ( ret || support.disconnectedMatch ||
+                                       // As well, disconnected nodes are said to be in a document
+                                       // fragment in IE 9
+                                       elem.document && elem.document.nodeType !== 11 ) {
+                               return ret;
+                       }
+               } catch(e) {}
+       }
+
+       return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+       // Set document vars if needed
+       if ( ( context.ownerDocument || context ) !== document ) {
+               setDocument( context );
+       }
+       return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       var fn = Expr.attrHandle[ name.toLowerCase() ],
+               // Don't get fooled by Object.prototype properties (jQuery #13807)
+               val = ( fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+                       fn( elem, name, !documentIsHTML ) :
+                       undefined );
+
+       return val === undefined ?
+               support.attributes || !documentIsHTML ?
+                       elem.getAttribute( name ) :
+                       (val = elem.getAttributeNode(name)) && val.specified ?
+                               val.value :
+                               null :
+               val;
+};
+
+Sizzle.error = function( msg ) {
+       throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+       var elem,
+               duplicates = [],
+               j = 0,
+               i = 0;
+
+       // Unless we *know* we can detect duplicates, assume their presence
+       hasDuplicate = !support.detectDuplicates;
+       sortInput = !support.sortStable && results.slice( 0 );
+       results.sort( sortOrder );
+
+       if ( hasDuplicate ) {
+               while ( (elem = results[i++]) ) {
+                       if ( elem === results[ i ] ) {
+                               j = duplicates.push( i );
+                       }
+               }
+               while ( j-- ) {
+                       results.splice( duplicates[ j ], 1 );
+               }
+       }
+
+       return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+       var node,
+               ret = "",
+               i = 0,
+               nodeType = elem.nodeType;
+
+       if ( !nodeType ) {
+               // If no nodeType, this is expected to be an array
+               for ( ; (node = elem[i]); i++ ) {
+                       // Do not traverse comment nodes
+                       ret += getText( node );
+               }
+       } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+               // Use textContent for elements
+               // innerText usage removed for consistency of new lines (see #11153)
+               if ( typeof elem.textContent === "string" ) {
+                       return elem.textContent;
+               } else {
+                       // Traverse its children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               ret += getText( elem );
+                       }
+               }
+       } else if ( nodeType === 3 || nodeType === 4 ) {
+               return elem.nodeValue;
+       }
+       // Do not include comment or processing instruction nodes
+
+       return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+       // Can be adjusted by the user
+       cacheLength: 50,
+
+       createPseudo: markFunction,
+
+       match: matchExpr,
+
+       attrHandle: {},
+
+       find: {},
+
+       relative: {
+               ">": { dir: "parentNode", first: true },
+               " ": { dir: "parentNode" },
+               "+": { dir: "previousSibling", first: true },
+               "~": { dir: "previousSibling" }
+       },
+
+       preFilter: {
+               "ATTR": function( match ) {
+                       match[1] = match[1].replace( runescape, funescape );
+
+                       // Move the given value to match[3] whether quoted or unquoted
+                       match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+                       if ( match[2] === "~=" ) {
+                               match[3] = " " + match[3] + " ";
+                       }
+
+                       return match.slice( 0, 4 );
+               },
+
+               "CHILD": function( match ) {
+                       /* matches from matchExpr["CHILD"]
+                               1 type (only|nth|...)
+                               2 what (child|of-type)
+                               3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+                               4 xn-component of xn+y argument ([+-]?\d*n|)
+                               5 sign of xn-component
+                               6 x of xn-component
+                               7 sign of y-component
+                               8 y of y-component
+                       */
+                       match[1] = match[1].toLowerCase();
+
+                       if ( match[1].slice( 0, 3 ) === "nth" ) {
+                               // nth-* requires argument
+                               if ( !match[3] ) {
+                                       Sizzle.error( match[0] );
+                               }
+
+                               // numeric x and y parameters for Expr.filter.CHILD
+                               // remember that false/true cast respectively to 0/1
+                               match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+                               match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+                       // other types prohibit arguments
+                       } else if ( match[3] ) {
+                               Sizzle.error( match[0] );
+                       }
+
+                       return match;
+               },
+
+               "PSEUDO": function( match ) {
+                       var excess,
+                               unquoted = !match[5] && match[2];
+
+                       if ( matchExpr["CHILD"].test( match[0] ) ) {
+                               return null;
+                       }
+
+                       // Accept quoted arguments as-is
+                       if ( match[3] && match[4] !== undefined ) {
+                               match[2] = match[4];
+
+                       // Strip excess characters from unquoted arguments
+                       } else if ( unquoted && rpseudo.test( unquoted ) &&
+                               // Get excess from tokenize (recursively)
+                               (excess = tokenize( unquoted, true )) &&
+                               // advance to the next closing parenthesis
+                               (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+                               // excess is a negative index
+                               match[0] = match[0].slice( 0, excess );
+                               match[2] = unquoted.slice( 0, excess );
+                       }
+
+                       // Return only captures needed by the pseudo filter method (type and argument)
+                       return match.slice( 0, 3 );
+               }
+       },
+
+       filter: {
+
+               "TAG": function( nodeNameSelector ) {
+                       var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+                       return nodeNameSelector === "*" ?
+                               function() { return true; } :
+                               function( elem ) {
+                                       return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+                               };
+               },
+
+               "CLASS": function( className ) {
+                       var pattern = classCache[ className + " " ];
+
+                       return pattern ||
+                               (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+                               classCache( className, function( elem ) {
+                                       return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+                               });
+               },
+
+               "ATTR": function( name, operator, check ) {
+                       return function( elem ) {
+                               var result = Sizzle.attr( elem, name );
+
+                               if ( result == null ) {
+                                       return operator === "!=";
+                               }
+                               if ( !operator ) {
+                                       return true;
+                               }
+
+                               result += "";
+
+                               return operator === "=" ? result === check :
+                                       operator === "!=" ? result !== check :
+                                       operator === "^=" ? check && result.indexOf( check ) === 0 :
+                                       operator === "*=" ? check && result.indexOf( check ) > -1 :
+                                       operator === "$=" ? check && result.slice( -check.length ) === check :
+                                       operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+                                       operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+                                       false;
+                       };
+               },
+
+               "CHILD": function( type, what, argument, first, last ) {
+                       var simple = type.slice( 0, 3 ) !== "nth",
+                               forward = type.slice( -4 ) !== "last",
+                               ofType = what === "of-type";
+
+                       return first === 1 && last === 0 ?
+
+                               // Shortcut for :nth-*(n)
+                               function( elem ) {
+                                       return !!elem.parentNode;
+                               } :
+
+                               function( elem, context, xml ) {
+                                       var cache, outerCache, node, diff, nodeIndex, start,
+                                               dir = simple !== forward ? "nextSibling" : "previousSibling",
+                                               parent = elem.parentNode,
+                                               name = ofType && elem.nodeName.toLowerCase(),
+                                               useCache = !xml && !ofType;
+
+                                       if ( parent ) {
+
+                                               // :(first|last|only)-(child|of-type)
+                                               if ( simple ) {
+                                                       while ( dir ) {
+                                                               node = elem;
+                                                               while ( (node = node[ dir ]) ) {
+                                                                       if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+                                                                               return false;
+                                                                       }
+                                                               }
+                                                               // Reverse direction for :only-* (if we haven't yet done so)
+                                                               start = dir = type === "only" && !start && "nextSibling";
+                                                       }
+                                                       return true;
+                                               }
+
+                                               start = [ forward ? parent.firstChild : parent.lastChild ];
+
+                                               // non-xml :nth-child(...) stores cache data on `parent`
+                                               if ( forward && useCache ) {
+                                                       // Seek `elem` from a previously-cached index
+                                                       outerCache = parent[ expando ] || (parent[ expando ] = {});
+                                                       cache = outerCache[ type ] || [];
+                                                       nodeIndex = cache[0] === dirruns && cache[1];
+                                                       diff = cache[0] === dirruns && cache[2];
+                                                       node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+                                                       while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+                                                               // Fallback to seeking `elem` from the start
+                                                               (diff = nodeIndex = 0) || start.pop()) ) {
+
+                                                               // When found, cache indexes on `parent` and break
+                                                               if ( node.nodeType === 1 && ++diff && node === elem ) {
+                                                                       outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+                                                                       break;
+                                                               }
+                                                       }
+
+                                               // Use previously-cached element index if available
+                                               } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+                                                       diff = cache[1];
+
+                                               // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+                                               } else {
+                                                       // Use the same loop as above to seek `elem` from the start
+                                                       while ( (node = ++nodeIndex && node && node[ dir ] ||
+                                                               (diff = nodeIndex = 0) || start.pop()) ) {
+
+                                                               if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+                                                                       // Cache the index of each encountered element
+                                                                       if ( useCache ) {
+                                                                               (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+                                                                       }
+
+                                                                       if ( node === elem ) {
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+
+                                               // Incorporate the offset, then check against cycle size
+                                               diff -= last;
+                                               return diff === first || ( diff % first === 0 && diff / first >= 0 );
+                                       }
+                               };
+               },
+
+               "PSEUDO": function( pseudo, argument ) {
+                       // pseudo-class names are case-insensitive
+                       // http://www.w3.org/TR/selectors/#pseudo-classes
+                       // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+                       // Remember that setFilters inherits from pseudos
+                       var args,
+                               fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+                                       Sizzle.error( "unsupported pseudo: " + pseudo );
+
+                       // The user may use createPseudo to indicate that
+                       // arguments are needed to create the filter function
+                       // just as Sizzle does
+                       if ( fn[ expando ] ) {
+                               return fn( argument );
+                       }
+
+                       // But maintain support for old signatures
+                       if ( fn.length > 1 ) {
+                               args = [ pseudo, pseudo, "", argument ];
+                               return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+                                       markFunction(function( seed, matches ) {
+                                               var idx,
+                                                       matched = fn( seed, argument ),
+                                                       i = matched.length;
+                                               while ( i-- ) {
+                                                       idx = indexOf.call( seed, matched[i] );
+                                                       seed[ idx ] = !( matches[ idx ] = matched[i] );
+                                               }
+                                       }) :
+                                       function( elem ) {
+                                               return fn( elem, 0, args );
+                                       };
+                       }
+
+                       return fn;
+               }
+       },
+
+       pseudos: {
+               // Potentially complex pseudos
+               "not": markFunction(function( selector ) {
+                       // Trim the selector passed to compile
+                       // to avoid treating leading and trailing
+                       // spaces as combinators
+                       var input = [],
+                               results = [],
+                               matcher = compile( selector.replace( rtrim, "$1" ) );
+
+                       return matcher[ expando ] ?
+                               markFunction(function( seed, matches, context, xml ) {
+                                       var elem,
+                                               unmatched = matcher( seed, null, xml, [] ),
+                                               i = seed.length;
+
+                                       // Match elements unmatched by `matcher`
+                                       while ( i-- ) {
+                                               if ( (elem = unmatched[i]) ) {
+                                                       seed[i] = !(matches[i] = elem);
+                                               }
+                                       }
+                               }) :
+                               function( elem, context, xml ) {
+                                       input[0] = elem;
+                                       matcher( input, null, xml, results );
+                                       return !results.pop();
+                               };
+               }),
+
+               "has": markFunction(function( selector ) {
+                       return function( elem ) {
+                               return Sizzle( selector, elem ).length > 0;
+                       };
+               }),
+
+               "contains": markFunction(function( text ) {
+                       return function( elem ) {
+                               return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+                       };
+               }),
+
+               // "Whether an element is represented by a :lang() selector
+               // is based solely on the element's language value
+               // being equal to the identifier C,
+               // or beginning with the identifier C immediately followed by "-".
+               // The matching of C against the element's language value is performed case-insensitively.
+               // The identifier C does not have to be a valid language name."
+               // http://www.w3.org/TR/selectors/#lang-pseudo
+               "lang": markFunction( function( lang ) {
+                       // lang value must be a valid identifier
+                       if ( !ridentifier.test(lang || "") ) {
+                               Sizzle.error( "unsupported lang: " + lang );
+                       }
+                       lang = lang.replace( runescape, funescape ).toLowerCase();
+                       return function( elem ) {
+                               var elemLang;
+                               do {
+                                       if ( (elemLang = documentIsHTML ?
+                                               elem.lang :
+                                               elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+                                               elemLang = elemLang.toLowerCase();
+                                               return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+                                       }
+                               } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+                               return false;
+                       };
+               }),
+
+               // Miscellaneous
+               "target": function( elem ) {
+                       var hash = window.location && window.location.hash;
+                       return hash && hash.slice( 1 ) === elem.id;
+               },
+
+               "root": function( elem ) {
+                       return elem === docElem;
+               },
+
+               "focus": function( elem ) {
+                       return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+               },
+
+               // Boolean properties
+               "enabled": function( elem ) {
+                       return elem.disabled === false;
+               },
+
+               "disabled": function( elem ) {
+                       return elem.disabled === true;
+               },
+
+               "checked": function( elem ) {
+                       // In CSS3, :checked should return both checked and selected elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       var nodeName = elem.nodeName.toLowerCase();
+                       return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+               },
+
+               "selected": function( elem ) {
+                       // Accessing this property makes selected-by-default
+                       // options in Safari work properly
+                       if ( elem.parentNode ) {
+                               elem.parentNode.selectedIndex;
+                       }
+
+                       return elem.selected === true;
+               },
+
+               // Contents
+               "empty": function( elem ) {
+                       // http://www.w3.org/TR/selectors/#empty-pseudo
+                       // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+                       //   not comment, processing instructions, or others
+                       // Thanks to Diego Perini for the nodeName shortcut
+                       //   Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               },
+
+               "parent": function( elem ) {
+                       return !Expr.pseudos["empty"]( elem );
+               },
+
+               // Element/input types
+               "header": function( elem ) {
+                       return rheader.test( elem.nodeName );
+               },
+
+               "input": function( elem ) {
+                       return rinputs.test( elem.nodeName );
+               },
+
+               "button": function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return name === "input" && elem.type === "button" || name === "button";
+               },
+
+               "text": function( elem ) {
+                       var attr;
+                       // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+                       // use getAttribute instead to test this case
+                       return elem.nodeName.toLowerCase() === "input" &&
+                               elem.type === "text" &&
+                               ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+               },
+
+               // Position-in-collection
+               "first": createPositionalPseudo(function() {
+                       return [ 0 ];
+               }),
+
+               "last": createPositionalPseudo(function( matchIndexes, length ) {
+                       return [ length - 1 ];
+               }),
+
+               "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       return [ argument < 0 ? argument + length : argument ];
+               }),
+
+               "even": createPositionalPseudo(function( matchIndexes, length ) {
+                       var i = 0;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "odd": createPositionalPseudo(function( matchIndexes, length ) {
+                       var i = 1;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; --i >= 0; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; ++i < length; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               })
+       }
+};
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+       Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+       Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+function tokenize( selector, parseOnly ) {
+       var matched, match, tokens, type,
+               soFar, groups, preFilters,
+               cached = tokenCache[ selector + " " ];
+
+       if ( cached ) {
+               return parseOnly ? 0 : cached.slice( 0 );
+       }
+
+       soFar = selector;
+       groups = [];
+       preFilters = Expr.preFilter;
+
+       while ( soFar ) {
+
+               // Comma and first run
+               if ( !matched || (match = rcomma.exec( soFar )) ) {
+                       if ( match ) {
+                               // Don't consume trailing commas as valid
+                               soFar = soFar.slice( match[0].length ) || soFar;
+                       }
+                       groups.push( tokens = [] );
+               }
+
+               matched = false;
+
+               // Combinators
+               if ( (match = rcombinators.exec( soFar )) ) {
+                       matched = match.shift();
+                       tokens.push({
+                               value: matched,
+                               // Cast descendant combinators to space
+                               type: match[0].replace( rtrim, " " )
+                       });
+                       soFar = soFar.slice( matched.length );
+               }
+
+               // Filters
+               for ( type in Expr.filter ) {
+                       if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+                               (match = preFilters[ type ]( match ))) ) {
+                               matched = match.shift();
+                               tokens.push({
+                                       value: matched,
+                                       type: type,
+                                       matches: match
+                               });
+                               soFar = soFar.slice( matched.length );
+                       }
+               }
+
+               if ( !matched ) {
+                       break;
+               }
+       }
+
+       // Return the length of the invalid excess
+       // if we're just parsing
+       // Otherwise, throw an error or return tokens
+       return parseOnly ?
+               soFar.length :
+               soFar ?
+                       Sizzle.error( selector ) :
+                       // Cache the tokens
+                       tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+       var i = 0,
+               len = tokens.length,
+               selector = "";
+       for ( ; i < len; i++ ) {
+               selector += tokens[i].value;
+       }
+       return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+       var dir = combinator.dir,
+               checkNonElements = base && dir === "parentNode",
+               doneName = done++;
+
+       return combinator.first ?
+               // Check against closest ancestor/preceding element
+               function( elem, context, xml ) {
+                       while ( (elem = elem[ dir ]) ) {
+                               if ( elem.nodeType === 1 || checkNonElements ) {
+                                       return matcher( elem, context, xml );
+                               }
+                       }
+               } :
+
+               // Check against all ancestor/preceding elements
+               function( elem, context, xml ) {
+                       var data, cache, outerCache,
+                               dirkey = dirruns + " " + doneName;
+
+                       // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+                       if ( xml ) {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               if ( matcher( elem, context, xml ) ) {
+                                                       return true;
+                                               }
+                                       }
+                               }
+                       } else {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               outerCache = elem[ expando ] || (elem[ expando ] = {});
+                                               if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+                                                       if ( (data = cache[1]) === true || data === cachedruns ) {
+                                                               return data === true;
+                                                       }
+                                               } else {
+                                                       cache = outerCache[ dir ] = [ dirkey ];
+                                                       cache[1] = matcher( elem, context, xml ) || cachedruns;
+                                                       if ( cache[1] === true ) {
+                                                               return true;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               };
+}
+
+function elementMatcher( matchers ) {
+       return matchers.length > 1 ?
+               function( elem, context, xml ) {
+                       var i = matchers.length;
+                       while ( i-- ) {
+                               if ( !matchers[i]( elem, context, xml ) ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               } :
+               matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+       var elem,
+               newUnmatched = [],
+               i = 0,
+               len = unmatched.length,
+               mapped = map != null;
+
+       for ( ; i < len; i++ ) {
+               if ( (elem = unmatched[i]) ) {
+                       if ( !filter || filter( elem, context, xml ) ) {
+                               newUnmatched.push( elem );
+                               if ( mapped ) {
+                                       map.push( i );
+                               }
+                       }
+               }
+       }
+
+       return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+       if ( postFilter && !postFilter[ expando ] ) {
+               postFilter = setMatcher( postFilter );
+       }
+       if ( postFinder && !postFinder[ expando ] ) {
+               postFinder = setMatcher( postFinder, postSelector );
+       }
+       return markFunction(function( seed, results, context, xml ) {
+               var temp, i, elem,
+                       preMap = [],
+                       postMap = [],
+                       preexisting = results.length,
+
+                       // Get initial elements from seed or context
+                       elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+                       // Prefilter to get matcher input, preserving a map for seed-results synchronization
+                       matcherIn = preFilter && ( seed || !selector ) ?
+                               condense( elems, preMap, preFilter, context, xml ) :
+                               elems,
+
+                       matcherOut = matcher ?
+                               // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+                               postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+                                       // ...intermediate processing is necessary
+                                       [] :
+
+                                       // ...otherwise use results directly
+                                       results :
+                               matcherIn;
+
+               // Find primary matches
+               if ( matcher ) {
+                       matcher( matcherIn, matcherOut, context, xml );
+               }
+
+               // Apply postFilter
+               if ( postFilter ) {
+                       temp = condense( matcherOut, postMap );
+                       postFilter( temp, [], context, xml );
+
+                       // Un-match failing elements by moving them back to matcherIn
+                       i = temp.length;
+                       while ( i-- ) {
+                               if ( (elem = temp[i]) ) {
+                                       matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+                               }
+                       }
+               }
+
+               if ( seed ) {
+                       if ( postFinder || preFilter ) {
+                               if ( postFinder ) {
+                                       // Get the final matcherOut by condensing this intermediate into postFinder contexts
+                                       temp = [];
+                                       i = matcherOut.length;
+                                       while ( i-- ) {
+                                               if ( (elem = matcherOut[i]) ) {
+                                                       // Restore matcherIn since elem is not yet a final match
+                                                       temp.push( (matcherIn[i] = elem) );
+                                               }
+                                       }
+                                       postFinder( null, (matcherOut = []), temp, xml );
+                               }
+
+                               // Move matched elements from seed to results to keep them synchronized
+                               i = matcherOut.length;
+                               while ( i-- ) {
+                                       if ( (elem = matcherOut[i]) &&
+                                               (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+                                               seed[temp] = !(results[temp] = elem);
+                                       }
+                               }
+                       }
+
+               // Add elements to results, through postFinder if defined
+               } else {
+                       matcherOut = condense(
+                               matcherOut === results ?
+                                       matcherOut.splice( preexisting, matcherOut.length ) :
+                                       matcherOut
+                       );
+                       if ( postFinder ) {
+                               postFinder( null, results, matcherOut, xml );
+                       } else {
+                               push.apply( results, matcherOut );
+                       }
+               }
+       });
+}
+
+function matcherFromTokens( tokens ) {
+       var checkContext, matcher, j,
+               len = tokens.length,
+               leadingRelative = Expr.relative[ tokens[0].type ],
+               implicitRelative = leadingRelative || Expr.relative[" "],
+               i = leadingRelative ? 1 : 0,
+
+               // The foundational matcher ensures that elements are reachable from top-level context(s)
+               matchContext = addCombinator( function( elem ) {
+                       return elem === checkContext;
+               }, implicitRelative, true ),
+               matchAnyContext = addCombinator( function( elem ) {
+                       return indexOf.call( checkContext, elem ) > -1;
+               }, implicitRelative, true ),
+               matchers = [ function( elem, context, xml ) {
+                       return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+                               (checkContext = context).nodeType ?
+                                       matchContext( elem, context, xml ) :
+                                       matchAnyContext( elem, context, xml ) );
+               } ];
+
+       for ( ; i < len; i++ ) {
+               if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+                       matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+               } else {
+                       matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+                       // Return special upon seeing a positional matcher
+                       if ( matcher[ expando ] ) {
+                               // Find the next relative operator (if any) for proper handling
+                               j = ++i;
+                               for ( ; j < len; j++ ) {
+                                       if ( Expr.relative[ tokens[j].type ] ) {
+                                               break;
+                                       }
+                               }
+                               return setMatcher(
+                                       i > 1 && elementMatcher( matchers ),
+                                       i > 1 && toSelector(
+                                               // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+                                               tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+                                       ).replace( rtrim, "$1" ),
+                                       matcher,
+                                       i < j && matcherFromTokens( tokens.slice( i, j ) ),
+                                       j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+                                       j < len && toSelector( tokens )
+                               );
+                       }
+                       matchers.push( matcher );
+               }
+       }
+
+       return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+       // A counter to specify which element is currently being matched
+       var matcherCachedRuns = 0,
+               bySet = setMatchers.length > 0,
+               byElement = elementMatchers.length > 0,
+               superMatcher = function( seed, context, xml, results, expandContext ) {
+                       var elem, j, matcher,
+                               setMatched = [],
+                               matchedCount = 0,
+                               i = "0",
+                               unmatched = seed && [],
+                               outermost = expandContext != null,
+                               contextBackup = outermostContext,
+                               // We must always have either seed elements or context
+                               elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+                               // Use integer dirruns iff this is the outermost matcher
+                               dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
+
+                       if ( outermost ) {
+                               outermostContext = context !== document && context;
+                               cachedruns = matcherCachedRuns;
+                       }
+
+                       // Add elements passing elementMatchers directly to results
+                       // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+                       for ( ; (elem = elems[i]) != null; i++ ) {
+                               if ( byElement && elem ) {
+                                       j = 0;
+                                       while ( (matcher = elementMatchers[j++]) ) {
+                                               if ( matcher( elem, context, xml ) ) {
+                                                       results.push( elem );
+                                                       break;
+                                               }
+                                       }
+                                       if ( outermost ) {
+                                               dirruns = dirrunsUnique;
+                                               cachedruns = ++matcherCachedRuns;
+                                       }
+                               }
+
+                               // Track unmatched elements for set filters
+                               if ( bySet ) {
+                                       // They will have gone through all possible matchers
+                                       if ( (elem = !matcher && elem) ) {
+                                               matchedCount--;
+                                       }
+
+                                       // Lengthen the array for every element, matched or not
+                                       if ( seed ) {
+                                               unmatched.push( elem );
+                                       }
+                               }
+                       }
+
+                       // Apply set filters to unmatched elements
+                       matchedCount += i;
+                       if ( bySet && i !== matchedCount ) {
+                               j = 0;
+                               while ( (matcher = setMatchers[j++]) ) {
+                                       matcher( unmatched, setMatched, context, xml );
+                               }
+
+                               if ( seed ) {
+                                       // Reintegrate element matches to eliminate the need for sorting
+                                       if ( matchedCount > 0 ) {
+                                               while ( i-- ) {
+                                                       if ( !(unmatched[i] || setMatched[i]) ) {
+                                                               setMatched[i] = pop.call( results );
+                                                       }
+                                               }
+                                       }
+
+                                       // Discard index placeholder values to get only actual matches
+                                       setMatched = condense( setMatched );
+                               }
+
+                               // Add matches to results
+                               push.apply( results, setMatched );
+
+                               // Seedless set matches succeeding multiple successful matchers stipulate sorting
+                               if ( outermost && !seed && setMatched.length > 0 &&
+                                       ( matchedCount + setMatchers.length ) > 1 ) {
+
+                                       Sizzle.uniqueSort( results );
+                               }
+                       }
+
+                       // Override manipulation of globals by nested matchers
+                       if ( outermost ) {
+                               dirruns = dirrunsUnique;
+                               outermostContext = contextBackup;
+                       }
+
+                       return unmatched;
+               };
+
+       return bySet ?
+               markFunction( superMatcher ) :
+               superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+       var i,
+               setMatchers = [],
+               elementMatchers = [],
+               cached = compilerCache[ selector + " " ];
+
+       if ( !cached ) {
+               // Generate a function of recursive functions that can be used to check each element
+               if ( !group ) {
+                       group = tokenize( selector );
+               }
+               i = group.length;
+               while ( i-- ) {
+                       cached = matcherFromTokens( group[i] );
+                       if ( cached[ expando ] ) {
+                               setMatchers.push( cached );
+                       } else {
+                               elementMatchers.push( cached );
+                       }
+               }
+
+               // Cache the compiled function
+               cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+       }
+       return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+       var i = 0,
+               len = contexts.length;
+       for ( ; i < len; i++ ) {
+               Sizzle( selector, contexts[i], results );
+       }
+       return results;
+}
+
+function select( selector, context, results, seed ) {
+       var i, tokens, token, type, find,
+               match = tokenize( selector );
+
+       if ( !seed ) {
+               // Try to minimize operations if there is only one group
+               if ( match.length === 1 ) {
+
+                       // Take a shortcut and set the context if the root selector is an ID
+                       tokens = match[0] = match[0].slice( 0 );
+                       if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+                                       support.getById && context.nodeType === 9 && documentIsHTML &&
+                                       Expr.relative[ tokens[1].type ] ) {
+
+                               context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+                               if ( !context ) {
+                                       return results;
+                               }
+                               selector = selector.slice( tokens.shift().value.length );
+                       }
+
+                       // Fetch a seed set for right-to-left matching
+                       i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+                       while ( i-- ) {
+                               token = tokens[i];
+
+                               // Abort if we hit a combinator
+                               if ( Expr.relative[ (type = token.type) ] ) {
+                                       break;
+                               }
+                               if ( (find = Expr.find[ type ]) ) {
+                                       // Search, expanding context for leading sibling combinators
+                                       if ( (seed = find(
+                                               token.matches[0].replace( runescape, funescape ),
+                                               rsibling.test( tokens[0].type ) && context.parentNode || context
+                                       )) ) {
+
+                                               // If seed is empty or no tokens remain, we can return early
+                                               tokens.splice( i, 1 );
+                                               selector = seed.length && toSelector( tokens );
+                                               if ( !selector ) {
+                                                       push.apply( results, seed );
+                                                       return results;
+                                               }
+
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // Compile and execute a filtering function
+       // Provide `match` to avoid retokenization if we modified the selector above
+       compile( selector, match )(
+               seed,
+               context,
+               !documentIsHTML,
+               results,
+               rsibling.test( selector )
+       );
+       return results;
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Chrome<<14
+// Always assume duplicates if they aren't passed to the comparison function
+[0, 0].sort( sortOrder );
+support.detectDuplicates = hasDuplicate;
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+       var object = optionsCache[ options ] = {};
+       jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+               object[ flag ] = true;
+       });
+       return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *     options: an optional list of space-separated options that will change how
+ *                     the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *     once:                   will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *     memory:                 will keep track of previous values and will call any callback added
+ *                                     after the list has been fired right away with the latest "memorized"
+ *                                     values (like a Deferred)
+ *
+ *     unique:                 will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *     stopOnFalse:    interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+       // Convert options from String-formatted to Object-formatted if needed
+       // (we check in cache first)
+       options = typeof options === "string" ?
+               ( optionsCache[ options ] || createOptions( options ) ) :
+               jQuery.extend( {}, options );
+
+       var // Last fire value (for non-forgettable lists)
+               memory,
+               // Flag to know if list was already fired
+               fired,
+               // Flag to know if list is currently firing
+               firing,
+               // First callback to fire (used internally by add and fireWith)
+               firingStart,
+               // End of the loop when firing
+               firingLength,
+               // Index of currently firing callback (modified by remove if needed)
+               firingIndex,
+               // Actual callback list
+               list = [],
+               // Stack of fire calls for repeatable lists
+               stack = !options.once && [],
+               // Fire callbacks
+               fire = function( data ) {
+                       memory = options.memory && data;
+                       fired = true;
+                       firingIndex = firingStart || 0;
+                       firingStart = 0;
+                       firingLength = list.length;
+                       firing = true;
+                       for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+                               if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+                                       memory = false; // To prevent further calls using add
+                                       break;
+                               }
+                       }
+                       firing = false;
+                       if ( list ) {
+                               if ( stack ) {
+                                       if ( stack.length ) {
+                                               fire( stack.shift() );
+                                       }
+                               } else if ( memory ) {
+                                       list = [];
+                               } else {
+                                       self.disable();
+                               }
+                       }
+               },
+               // Actual Callbacks object
+               self = {
+                       // Add a callback or a collection of callbacks to the list
+                       add: function() {
+                               if ( list ) {
+                                       // First, we save the current length
+                                       var start = list.length;
+                                       (function add( args ) {
+                                               jQuery.each( args, function( _, arg ) {
+                                                       var type = jQuery.type( arg );
+                                                       if ( type === "function" ) {
+                                                               if ( !options.unique || !self.has( arg ) ) {
+                                                                       list.push( arg );
+                                                               }
+                                                       } else if ( arg && arg.length && type !== "string" ) {
+                                                               // Inspect recursively
+                                                               add( arg );
+                                                       }
+                                               });
+                                       })( arguments );
+                                       // Do we need to add the callbacks to the
+                                       // current firing batch?
+                                       if ( firing ) {
+                                               firingLength = list.length;
+                                       // With memory, if we're not firing then
+                                       // we should call right away
+                                       } else if ( memory ) {
+                                               firingStart = start;
+                                               fire( memory );
+                                       }
+                               }
+                               return this;
+                       },
+                       // Remove a callback from the list
+                       remove: function() {
+                               if ( list ) {
+                                       jQuery.each( arguments, function( _, arg ) {
+                                               var index;
+                                               while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+                                                       list.splice( index, 1 );
+                                                       // Handle firing indexes
+                                                       if ( firing ) {
+                                                               if ( index <= firingLength ) {
+                                                                       firingLength--;
+                                                               }
+                                                               if ( index <= firingIndex ) {
+                                                                       firingIndex--;
+                                                               }
+                                                       }
+                                               }
+                                       });
+                               }
+                               return this;
+                       },
+                       // Check if a given callback is in the list.
+                       // If no argument is given, return whether or not list has callbacks attached.
+                       has: function( fn ) {
+                               return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+                       },
+                       // Remove all callbacks from the list
+                       empty: function() {
+                               list = [];
+                               firingLength = 0;
+                               return this;
+                       },
+                       // Have the list do nothing anymore
+                       disable: function() {
+                               list = stack = memory = undefined;
+                               return this;
+                       },
+                       // Is it disabled?
+                       disabled: function() {
+                               return !list;
+                       },
+                       // Lock the list in its current state
+                       lock: function() {
+                               stack = undefined;
+                               if ( !memory ) {
+                                       self.disable();
+                               }
+                               return this;
+                       },
+                       // Is it locked?
+                       locked: function() {
+                               return !stack;
+                       },
+                       // Call all callbacks with the given context and arguments
+                       fireWith: function( context, args ) {
+                               args = args || [];
+                               args = [ context, args.slice ? args.slice() : args ];
+                               if ( list && ( !fired || stack ) ) {
+                                       if ( firing ) {
+                                               stack.push( args );
+                                       } else {
+                                               fire( args );
+                                       }
+                               }
+                               return this;
+                       },
+                       // Call all the callbacks with the given arguments
+                       fire: function() {
+                               self.fireWith( this, arguments );
+                               return this;
+                       },
+                       // To know if the callbacks have already been called at least once
+                       fired: function() {
+                               return !!fired;
+                       }
+               };
+
+       return self;
+};
+jQuery.extend({
+
+       Deferred: function( func ) {
+               var tuples = [
+                               // action, add listener, listener list, final state
+                               [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+                               [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+                               [ "notify", "progress", jQuery.Callbacks("memory") ]
+                       ],
+                       state = "pending",
+                       promise = {
+                               state: function() {
+                                       return state;
+                               },
+                               always: function() {
+                                       deferred.done( arguments ).fail( arguments );
+                                       return this;
+                               },
+                               then: function( /* fnDone, fnFail, fnProgress */ ) {
+                                       var fns = arguments;
+                                       return jQuery.Deferred(function( newDefer ) {
+                                               jQuery.each( tuples, function( i, tuple ) {
+                                                       var action = tuple[ 0 ],
+                                                               fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+                                                       // deferred[ done | fail | progress ] for forwarding actions to newDefer
+                                                       deferred[ tuple[1] ](function() {
+                                                               var returned = fn && fn.apply( this, arguments );
+                                                               if ( returned && jQuery.isFunction( returned.promise ) ) {
+                                                                       returned.promise()
+                                                                               .done( newDefer.resolve )
+                                                                               .fail( newDefer.reject )
+                                                                               .progress( newDefer.notify );
+                                                               } else {
+                                                                       newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+                                                               }
+                                                       });
+                                               });
+                                               fns = null;
+                                       }).promise();
+                               },
+                               // Get a promise for this deferred
+                               // If obj is provided, the promise aspect is added to the object
+                               promise: function( obj ) {
+                                       return obj != null ? jQuery.extend( obj, promise ) : promise;
+                               }
+                       },
+                       deferred = {};
+
+               // Keep pipe for back-compat
+               promise.pipe = promise.then;
+
+               // Add list-specific methods
+               jQuery.each( tuples, function( i, tuple ) {
+                       var list = tuple[ 2 ],
+                               stateString = tuple[ 3 ];
+
+                       // promise[ done | fail | progress ] = list.add
+                       promise[ tuple[1] ] = list.add;
+
+                       // Handle state
+                       if ( stateString ) {
+                               list.add(function() {
+                                       // state = [ resolved | rejected ]
+                                       state = stateString;
+
+                               // [ reject_list | resolve_list ].disable; progress_list.lock
+                               }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+                       }
+
+                       // deferred[ resolve | reject | notify ]
+                       deferred[ tuple[0] ] = function() {
+                               deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+                               return this;
+                       };
+                       deferred[ tuple[0] + "With" ] = list.fireWith;
+               });
+
+               // Make the deferred a promise
+               promise.promise( deferred );
+
+               // Call given func if any
+               if ( func ) {
+                       func.call( deferred, deferred );
+               }
+
+               // All done!
+               return deferred;
+       },
+
+       // Deferred helper
+       when: function( subordinate /* , ..., subordinateN */ ) {
+               var i = 0,
+                       resolveValues = core_slice.call( arguments ),
+                       length = resolveValues.length,
+
+                       // the count of uncompleted subordinates
+                       remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+                       // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+                       deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+                       // Update function for both resolve and progress values
+                       updateFunc = function( i, contexts, values ) {
+                               return function( value ) {
+                                       contexts[ i ] = this;
+                                       values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+                                       if( values === progressValues ) {
+                                               deferred.notifyWith( contexts, values );
+                                       } else if ( !( --remaining ) ) {
+                                               deferred.resolveWith( contexts, values );
+                                       }
+                               };
+                       },
+
+                       progressValues, progressContexts, resolveContexts;
+
+               // add listeners to Deferred subordinates; treat others as resolved
+               if ( length > 1 ) {
+                       progressValues = new Array( length );
+                       progressContexts = new Array( length );
+                       resolveContexts = new Array( length );
+                       for ( ; i < length; i++ ) {
+                               if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+                                       resolveValues[ i ].promise()
+                                               .done( updateFunc( i, resolveContexts, resolveValues ) )
+                                               .fail( deferred.reject )
+                                               .progress( updateFunc( i, progressContexts, progressValues ) );
+                               } else {
+                                       --remaining;
+                               }
+                       }
+               }
+
+               // if we're not waiting on anything, resolve the master
+               if ( !remaining ) {
+                       deferred.resolveWith( resolveContexts, resolveValues );
+               }
+
+               return deferred.promise();
+       }
+});
+jQuery.support = (function( support ) {
+       var input = document.createElement("input"),
+               fragment = document.createDocumentFragment(),
+               div = document.createElement("div"),
+               select = document.createElement("select"),
+               opt = select.appendChild( document.createElement("option") );
+
+       // Finish early in limited environments
+       if ( !input.type ) {
+               return support;
+       }
+
+       input.type = "checkbox";
+
+       // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+       // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
+       support.checkOn = input.value !== "";
+
+       // Must access the parent to make an option select properly
+       // Support: IE9, IE10
+       support.optSelected = opt.selected;
+
+       // Will be defined later
+       support.reliableMarginRight = true;
+       support.boxSizingReliable = true;
+       support.pixelPosition = false;
+
+       // Make sure checked status is properly cloned
+       // Support: IE9, IE10
+       input.checked = true;
+       support.noCloneChecked = input.cloneNode( true ).checked;
+
+       // Make sure that the options inside disabled selects aren't marked as disabled
+       // (WebKit marks them as disabled)
+       select.disabled = true;
+       support.optDisabled = !opt.disabled;
+
+       // Check if an input maintains its value after becoming a radio
+       // Support: IE9, IE10
+       input = document.createElement("input");
+       input.value = "t";
+       input.type = "radio";
+       support.radioValue = input.value === "t";
+
+       // #11217 - WebKit loses check when the name is after the checked attribute
+       input.setAttribute( "checked", "t" );
+       input.setAttribute( "name", "t" );
+
+       fragment.appendChild( input );
+
+       // Support: Safari 5.1, Android 4.x, Android 2.3
+       // old WebKit doesn't clone checked state correctly in fragments
+       support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+       // Support: Firefox, Chrome, Safari
+       // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+       support.focusinBubbles = "onfocusin" in window;
+
+       div.style.backgroundClip = "content-box";
+       div.cloneNode( true ).style.backgroundClip = "";
+       support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+       // Run tests that need a body at doc ready
+       jQuery(function() {
+               var container, marginDiv,
+                       // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
+                       divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
+                       body = document.getElementsByTagName("body")[ 0 ];
+
+               if ( !body ) {
+                       // Return for frameset docs that don't have a body
+                       return;
+               }
+
+               container = document.createElement("div");
+               container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+               // Check box-sizing and margin behavior.
+               body.appendChild( container ).appendChild( div );
+               div.innerHTML = "";
+               // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
+               div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";
+
+               // Workaround failing boxSizing test due to offsetWidth returning wrong value
+               // with some non-1 values of body zoom, ticket #13543
+               jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
+                       support.boxSizing = div.offsetWidth === 4;
+               });
+
+               // Use window.getComputedStyle because jsdom on node.js will break without it.
+               if ( window.getComputedStyle ) {
+                       support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+                       support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+                       // Support: Android 2.3
+                       // Check if div with explicit width and no margin-right incorrectly
+                       // gets computed margin-right based on width of container. (#3333)
+                       // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                       marginDiv = div.appendChild( document.createElement("div") );
+                       marginDiv.style.cssText = div.style.cssText = divReset;
+                       marginDiv.style.marginRight = marginDiv.style.width = "0";
+                       div.style.width = "1px";
+
+                       support.reliableMarginRight =
+                               !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+               }
+
+               body.removeChild( container );
+       });
+
+       return support;
+})( {} );
+
+/*
+       Implementation Summary
+
+       1. Enforce API surface and semantic compatibility with 1.9.x branch
+       2. Improve the module's maintainability by reducing the storage
+               paths to a single mechanism.
+       3. Use the same single mechanism to support "private" and "user" data.
+       4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+       5. Avoid exposing implementation details on user objects (eg. expando properties)
+       6. Provide a clear path for implementation upgrade to WeakMap in 2014
+*/
+var data_user, data_priv,
+       rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
+       rmultiDash = /([A-Z])/g;
+
+function Data() {
+       // Support: Android < 4,
+       // Old WebKit does not have Object.preventExtensions/freeze method,
+       // return new empty object instead with no [[set]] accessor
+       Object.defineProperty( this.cache = {}, 0, {
+               get: function() {
+                       return {};
+               }
+       });
+
+       this.expando = jQuery.expando + Math.random();
+}
+
+Data.uid = 1;
+
+Data.accepts = function( owner ) {
+       // Accepts only:
+       //  - Node
+       //    - Node.ELEMENT_NODE
+       //    - Node.DOCUMENT_NODE
+       //  - Object
+       //    - Any
+       return owner.nodeType ?
+               owner.nodeType === 1 || owner.nodeType === 9 : true;
+};
+
+Data.prototype = {
+       key: function( owner ) {
+               // We can accept data for non-element nodes in modern browsers,
+               // but we should not, see #8335.
+               // Always return the key for a frozen object.
+               if ( !Data.accepts( owner ) ) {
+                       return 0;
+               }
+
+               var descriptor = {},
+                       // Check if the owner object already has a cache key
+                       unlock = owner[ this.expando ];
+
+               // If not, create one
+               if ( !unlock ) {
+                       unlock = Data.uid++;
+
+                       // Secure it in a non-enumerable, non-writable property
+                       try {
+                               descriptor[ this.expando ] = { value: unlock };
+                               Object.defineProperties( owner, descriptor );
+
+                       // Support: Android < 4
+                       // Fallback to a less secure definition
+                       } catch ( e ) {
+                               descriptor[ this.expando ] = unlock;
+                               jQuery.extend( owner, descriptor );
+                       }
+               }
+
+               // Ensure the cache object
+               if ( !this.cache[ unlock ] ) {
+                       this.cache[ unlock ] = {};
+               }
+
+               return unlock;
+       },
+       set: function( owner, data, value ) {
+               var prop,
+                       // There may be an unlock assigned to this node,
+                       // if there is no entry for this "owner", create one inline
+                       // and set the unlock as though an owner entry had always existed
+                       unlock = this.key( owner ),
+                       cache = this.cache[ unlock ];
+
+               // Handle: [ owner, key, value ] args
+               if ( typeof data === "string" ) {
+                       cache[ data ] = value;
+
+               // Handle: [ owner, { properties } ] args
+               } else {
+                       // Fresh assignments by object are shallow copied
+                       if ( jQuery.isEmptyObject( cache ) ) {
+                               jQuery.extend( this.cache[ unlock ], data );
+                       // Otherwise, copy the properties one-by-one to the cache object
+                       } else {
+                               for ( prop in data ) {
+                                       cache[ prop ] = data[ prop ];
+                               }
+                       }
+               }
+               return cache;
+       },
+       get: function( owner, key ) {
+               // Either a valid cache is found, or will be created.
+               // New caches will be created and the unlock returned,
+               // allowing direct access to the newly created
+               // empty data object. A valid owner object must be provided.
+               var cache = this.cache[ this.key( owner ) ];
+
+               return key === undefined ?
+                       cache : cache[ key ];
+       },
+       access: function( owner, key, value ) {
+               // In cases where either:
+               //
+               //   1. No key was specified
+               //   2. A string key was specified, but no value provided
+               //
+               // Take the "read" path and allow the get method to determine
+               // which value to return, respectively either:
+               //
+               //   1. The entire cache object
+               //   2. The data stored at the key
+               //
+               if ( key === undefined ||
+                               ((key && typeof key === "string") && value === undefined) ) {
+                       return this.get( owner, key );
+               }
+
+               // [*]When the key is not a string, or both a key and value
+               // are specified, set or extend (existing objects) with either:
+               //
+               //   1. An object of properties
+               //   2. A key and value
+               //
+               this.set( owner, key, value );
+
+               // Since the "set" path can have two possible entry points
+               // return the expected data based on which path was taken[*]
+               return value !== undefined ? value : key;
+       },
+       remove: function( owner, key ) {
+               var i, name, camel,
+                       unlock = this.key( owner ),
+                       cache = this.cache[ unlock ];
+
+               if ( key === undefined ) {
+                       this.cache[ unlock ] = {};
+
+               } else {
+                       // Support array or space separated string of keys
+                       if ( jQuery.isArray( key ) ) {
+                               // If "name" is an array of keys...
+                               // When data is initially created, via ("key", "val") signature,
+                               // keys will be converted to camelCase.
+                               // Since there is no way to tell _how_ a key was added, remove
+                               // both plain key and camelCase key. #12786
+                               // This will only penalize the array argument path.
+                               name = key.concat( key.map( jQuery.camelCase ) );
+                       } else {
+                               camel = jQuery.camelCase( key );
+                               // Try the string as a key before any manipulation
+                               if ( key in cache ) {
+                                       name = [ key, camel ];
+                               } else {
+                                       // If a key with the spaces exists, use it.
+                                       // Otherwise, create an array by matching non-whitespace
+                                       name = camel;
+                                       name = name in cache ?
+                                               [ name ] : ( name.match( core_rnotwhite ) || [] );
+                               }
+                       }
+
+                       i = name.length;
+                       while ( i-- ) {
+                               delete cache[ name[ i ] ];
+                       }
+               }
+       },
+       hasData: function( owner ) {
+               return !jQuery.isEmptyObject(
+                       this.cache[ owner[ this.expando ] ] || {}
+               );
+       },
+       discard: function( owner ) {
+               if ( owner[ this.expando ] ) {
+                       delete this.cache[ owner[ this.expando ] ];
+               }
+       }
+};
+
+// These may be used throughout the jQuery core codebase
+data_user = new Data();
+data_priv = new Data();
+
+
+jQuery.extend({
+       acceptData: Data.accepts,
+
+       hasData: function( elem ) {
+               return data_user.hasData( elem ) || data_priv.hasData( elem );
+       },
+
+       data: function( elem, name, data ) {
+               return data_user.access( elem, name, data );
+       },
+
+       removeData: function( elem, name ) {
+               data_user.remove( elem, name );
+       },
+
+       // TODO: Now that all calls to _data and _removeData have been replaced
+       // with direct calls to data_priv methods, these can be deprecated.
+       _data: function( elem, name, data ) {
+               return data_priv.access( elem, name, data );
+       },
+
+       _removeData: function( elem, name ) {
+               data_priv.remove( elem, name );
+       }
+});
+
+jQuery.fn.extend({
+       data: function( key, value ) {
+               var attrs, name,
+                       elem = this[ 0 ],
+                       i = 0,
+                       data = null;
+
+               // Gets all values
+               if ( key === undefined ) {
+                       if ( this.length ) {
+                               data = data_user.get( elem );
+
+                               if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
+                                       attrs = elem.attributes;
+                                       for ( ; i < attrs.length; i++ ) {
+                                               name = attrs[ i ].name;
+
+                                               if ( name.indexOf( "data-" ) === 0 ) {
+                                                       name = jQuery.camelCase( name.slice(5) );
+                                                       dataAttr( elem, name, data[ name ] );
+                                               }
+                                       }
+                                       data_priv.set( elem, "hasDataAttrs", true );
+                               }
+                       }
+
+                       return data;
+               }
+
+               // Sets multiple values
+               if ( typeof key === "object" ) {
+                       return this.each(function() {
+                               data_user.set( this, key );
+                       });
+               }
+
+               return jQuery.access( this, function( value ) {
+                       var data,
+                               camelKey = jQuery.camelCase( key );
+
+                       // The calling jQuery object (element matches) is not empty
+                       // (and therefore has an element appears at this[ 0 ]) and the
+                       // `value` parameter was not undefined. An empty jQuery object
+                       // will result in `undefined` for elem = this[ 0 ] which will
+                       // throw an exception if an attempt to read a data cache is made.
+                       if ( elem && value === undefined ) {
+                               // Attempt to get data from the cache
+                               // with the key as-is
+                               data = data_user.get( elem, key );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // Attempt to get data from the cache
+                               // with the key camelized
+                               data = data_user.get( elem, camelKey );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // Attempt to "discover" the data in
+                               // HTML5 custom data-* attrs
+                               data = dataAttr( elem, camelKey, undefined );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // We tried really hard, but the data doesn't exist.
+                               return;
+                       }
+
+                       // Set the data...
+                       this.each(function() {
+                               // First, attempt to store a copy or reference of any
+                               // data that might've been store with a camelCased key.
+                               var data = data_user.get( this, camelKey );
+
+                               // For HTML5 data-* attribute interop, we have to
+                               // store property names with dashes in a camelCase form.
+                               // This might not apply to all properties...*
+                               data_user.set( this, camelKey, value );
+
+                               // *... In the case of properties that might _actually_
+                               // have dashes, we need to also store a copy of that
+                               // unchanged property.
+                               if ( key.indexOf("-") !== -1 && data !== undefined ) {
+                                       data_user.set( this, key, value );
+                               }
+                       });
+               }, null, value, arguments.length > 1, null, true );
+       },
+
+       removeData: function( key ) {
+               return this.each(function() {
+                       data_user.remove( this, key );
+               });
+       }
+});
+
+function dataAttr( elem, key, data ) {
+       var name;
+
+       // If nothing was found internally, try to fetch any
+       // data from the HTML5 data-* attribute
+       if ( data === undefined && elem.nodeType === 1 ) {
+               name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+               data = elem.getAttribute( name );
+
+               if ( typeof data === "string" ) {
+                       try {
+                               data = data === "true" ? true :
+                                       data === "false" ? false :
+                                       data === "null" ? null :
+                                       // Only convert to a number if it doesn't change the string
+                                       +data + "" === data ? +data :
+                                       rbrace.test( data ) ? JSON.parse( data ) :
+                                       data;
+                       } catch( e ) {}
+
+                       // Make sure we set the data so it isn't changed later
+                       data_user.set( elem, key, data );
+               } else {
+                       data = undefined;
+               }
+       }
+       return data;
+}
+jQuery.extend({
+       queue: function( elem, type, data ) {
+               var queue;
+
+               if ( elem ) {
+                       type = ( type || "fx" ) + "queue";
+                       queue = data_priv.get( elem, type );
+
+                       // Speed up dequeue by getting out quickly if this is just a lookup
+                       if ( data ) {
+                               if ( !queue || jQuery.isArray( data ) ) {
+                                       queue = data_priv.access( elem, type, jQuery.makeArray(data) );
+                               } else {
+                                       queue.push( data );
+                               }
+                       }
+                       return queue || [];
+               }
+       },
+
+       dequeue: function( elem, type ) {
+               type = type || "fx";
+
+               var queue = jQuery.queue( elem, type ),
+                       startLength = queue.length,
+                       fn = queue.shift(),
+                       hooks = jQuery._queueHooks( elem, type ),
+                       next = function() {
+                               jQuery.dequeue( elem, type );
+                       };
+
+               // If the fx queue is dequeued, always remove the progress sentinel
+               if ( fn === "inprogress" ) {
+                       fn = queue.shift();
+                       startLength--;
+               }
+
+               if ( fn ) {
+
+                       // Add a progress sentinel to prevent the fx queue from being
+                       // automatically dequeued
+                       if ( type === "fx" ) {
+                               queue.unshift( "inprogress" );
+                       }
+
+                       // clear up the last queue stop function
+                       delete hooks.stop;
+                       fn.call( elem, next, hooks );
+               }
+
+               if ( !startLength && hooks ) {
+                       hooks.empty.fire();
+               }
+       },
+
+       // not intended for public consumption - generates a queueHooks object, or returns the current one
+       _queueHooks: function( elem, type ) {
+               var key = type + "queueHooks";
+               return data_priv.get( elem, key ) || data_priv.access( elem, key, {
+                       empty: jQuery.Callbacks("once memory").add(function() {
+                               data_priv.remove( elem, [ type + "queue", key ] );
+                       })
+               });
+       }
+});
+
+jQuery.fn.extend({
+       queue: function( type, data ) {
+               var setter = 2;
+
+               if ( typeof type !== "string" ) {
+                       data = type;
+                       type = "fx";
+                       setter--;
+               }
+
+               if ( arguments.length < setter ) {
+                       return jQuery.queue( this[0], type );
+               }
+
+               return data === undefined ?
+                       this :
+                       this.each(function() {
+                               var queue = jQuery.queue( this, type, data );
+
+                               // ensure a hooks for this queue
+                               jQuery._queueHooks( this, type );
+
+                               if ( type === "fx" && queue[0] !== "inprogress" ) {
+                                       jQuery.dequeue( this, type );
+                               }
+                       });
+       },
+       dequeue: function( type ) {
+               return this.each(function() {
+                       jQuery.dequeue( this, type );
+               });
+       },
+       // Based off of the plugin by Clint Helfers, with permission.
+       // http://blindsignals.com/index.php/2009/07/jquery-delay/
+       delay: function( time, type ) {
+               time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+               type = type || "fx";
+
+               return this.queue( type, function( next, hooks ) {
+                       var timeout = setTimeout( next, time );
+                       hooks.stop = function() {
+                               clearTimeout( timeout );
+                       };
+               });
+       },
+       clearQueue: function( type ) {
+               return this.queue( type || "fx", [] );
+       },
+       // Get a promise resolved when queues of a certain type
+       // are emptied (fx is the type by default)
+       promise: function( type, obj ) {
+               var tmp,
+                       count = 1,
+                       defer = jQuery.Deferred(),
+                       elements = this,
+                       i = this.length,
+                       resolve = function() {
+                               if ( !( --count ) ) {
+                                       defer.resolveWith( elements, [ elements ] );
+                               }
+                       };
+
+               if ( typeof type !== "string" ) {
+                       obj = type;
+                       type = undefined;
+               }
+               type = type || "fx";
+
+               while( i-- ) {
+                       tmp = data_priv.get( elements[ i ], type + "queueHooks" );
+                       if ( tmp && tmp.empty ) {
+                               count++;
+                               tmp.empty.add( resolve );
+                       }
+               }
+               resolve();
+               return defer.promise( obj );
+       }
+});
+var nodeHook, boolHook,
+       rclass = /[\t\r\n\f]/g,
+       rreturn = /\r/g,
+       rfocusable = /^(?:input|select|textarea|button)$/i;
+
+jQuery.fn.extend({
+       attr: function( name, value ) {
+               return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+       },
+
+       removeAttr: function( name ) {
+               return this.each(function() {
+                       jQuery.removeAttr( this, name );
+               });
+       },
+
+       prop: function( name, value ) {
+               return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+       },
+
+       removeProp: function( name ) {
+               return this.each(function() {
+                       delete this[ jQuery.propFix[ name ] || name ];
+               });
+       },
+
+       addClass: function( value ) {
+               var classes, elem, cur, clazz, j,
+                       i = 0,
+                       len = this.length,
+                       proceed = typeof value === "string" && value;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).addClass( value.call( this, j, this.className ) );
+                       });
+               }
+
+               if ( proceed ) {
+                       // The disjunction here is for better compressibility (see removeClass)
+                       classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( rclass, " " ) :
+                                       " "
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+                                                       cur += clazz + " ";
+                                               }
+                                       }
+                                       elem.className = jQuery.trim( cur );
+
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       removeClass: function( value ) {
+               var classes, elem, cur, clazz, j,
+                       i = 0,
+                       len = this.length,
+                       proceed = arguments.length === 0 || typeof value === "string" && value;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).removeClass( value.call( this, j, this.className ) );
+                       });
+               }
+               if ( proceed ) {
+                       classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               // This expression is here for better compressibility (see addClass)
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( rclass, " " ) :
+                                       ""
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               // Remove *all* instances
+                                               while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+                                                       cur = cur.replace( " " + clazz + " ", " " );
+                                               }
+                                       }
+                                       elem.className = value ? jQuery.trim( cur ) : "";
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       toggleClass: function( value, stateVal ) {
+               var type = typeof value,
+                       isBool = typeof stateVal === "boolean";
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+                       });
+               }
+
+               return this.each(function() {
+                       if ( type === "string" ) {
+                               // toggle individual class names
+                               var className,
+                                       i = 0,
+                                       self = jQuery( this ),
+                                       state = stateVal,
+                                       classNames = value.match( core_rnotwhite ) || [];
+
+                               while ( (className = classNames[ i++ ]) ) {
+                                       // check each className given, space separated list
+                                       state = isBool ? state : !self.hasClass( className );
+                                       self[ state ? "addClass" : "removeClass" ]( className );
+                               }
+
+                       // Toggle whole class name
+                       } else if ( type === core_strundefined || type === "boolean" ) {
+                               if ( this.className ) {
+                                       // store className if set
+                                       data_priv.set( this, "__className__", this.className );
+                               }
+
+                               // If the element has a class name or if we're passed "false",
+                               // then remove the whole classname (if there was one, the above saved it).
+                               // Otherwise bring back whatever was previously saved (if anything),
+                               // falling back to the empty string if nothing was stored.
+                               this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
+                       }
+               });
+       },
+
+       hasClass: function( selector ) {
+               var className = " " + selector + " ",
+                       i = 0,
+                       l = this.length;
+               for ( ; i < l; i++ ) {
+                       if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       },
+
+       val: function( value ) {
+               var hooks, ret, isFunction,
+                       elem = this[0];
+
+               if ( !arguments.length ) {
+                       if ( elem ) {
+                               hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+                               if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+                                       return ret;
+                               }
+
+                               ret = elem.value;
+
+                               return typeof ret === "string" ?
+                                       // handle most common string cases
+                                       ret.replace(rreturn, "") :
+                                       // handle cases where value is null/undef or number
+                                       ret == null ? "" : ret;
+                       }
+
+                       return;
+               }
+
+               isFunction = jQuery.isFunction( value );
+
+               return this.each(function( i ) {
+                       var val;
+
+                       if ( this.nodeType !== 1 ) {
+                               return;
+                       }
+
+                       if ( isFunction ) {
+                               val = value.call( this, i, jQuery( this ).val() );
+                       } else {
+                               val = value;
+                       }
+
+                       // Treat null/undefined as ""; convert numbers to string
+                       if ( val == null ) {
+                               val = "";
+                       } else if ( typeof val === "number" ) {
+                               val += "";
+                       } else if ( jQuery.isArray( val ) ) {
+                               val = jQuery.map(val, function ( value ) {
+                                       return value == null ? "" : value + "";
+                               });
+                       }
+
+                       hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+                               this.value = val;
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+                               // attributes.value is undefined in Blackberry 4.7 but
+                               // uses .value. See #6932
+                               var val = elem.attributes.value;
+                               return !val || val.specified ? elem.value : elem.text;
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var value, option,
+                                       options = elem.options,
+                                       index = elem.selectedIndex,
+                                       one = elem.type === "select-one" || index < 0,
+                                       values = one ? null : [],
+                                       max = one ? index + 1 : options.length,
+                                       i = index < 0 ?
+                                               max :
+                                               one ? index : 0;
+
+                               // Loop through all the selected options
+                               for ( ; i < max; i++ ) {
+                                       option = options[ i ];
+
+                                       // IE6-9 doesn't update selected after form reset (#2551)
+                                       if ( ( option.selected || i === index ) &&
+                                                       // Don't return options that are disabled or in a disabled optgroup
+                                                       ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+                                                       ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+                                               // Get the specific value for the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
+
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var optionSet, option,
+                                       options = elem.options,
+                                       values = jQuery.makeArray( value ),
+                                       i = options.length;
+
+                               while ( i-- ) {
+                                       option = options[ i ];
+                                       if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
+                                               optionSet = true;
+                                       }
+                               }
+
+                               // force browsers to behave consistently when non-matching value is set
+                               if ( !optionSet ) {
+                                       elem.selectedIndex = -1;
+                               }
+                               return values;
+                       }
+               }
+       },
+
+       attr: function( elem, name, value ) {
+               var hooks, ret,
+                       nType = elem.nodeType;
+
+               // don't get/set attributes on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               // Fallback to prop when attributes are not supported
+               if ( typeof elem.getAttribute === core_strundefined ) {
+                       return jQuery.prop( elem, name, value );
+               }
+
+               // All attributes are lowercase
+               // Grab necessary hook if one is defined
+               if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+                       name = name.toLowerCase();
+                       hooks = jQuery.attrHooks[ name ] ||
+                               ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+               }
+
+               if ( value !== undefined ) {
+
+                       if ( value === null ) {
+                               jQuery.removeAttr( elem, name );
+
+                       } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                               return ret;
+
+                       } else {
+                               elem.setAttribute( name, value + "" );
+                               return value;
+                       }
+
+               } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+                       return ret;
+
+               } else {
+                       ret = jQuery.find.attr( elem, name );
+
+                       // Non-existent attributes return null, we normalize to undefined
+                       return ret == null ?
+                               undefined :
+                               ret;
+               }
+       },
+
+       removeAttr: function( elem, value ) {
+               var name, propName,
+                       i = 0,
+                       attrNames = value && value.match( core_rnotwhite );
+
+               if ( attrNames && elem.nodeType === 1 ) {
+                       while ( (name = attrNames[i++]) ) {
+                               propName = jQuery.propFix[ name ] || name;
+
+                               // Boolean attributes get special treatment (#10870)
+                               if ( jQuery.expr.match.bool.test( name ) ) {
+                                       // Set corresponding property to false
+                                       elem[ propName ] = false;
+                               }
+
+                               elem.removeAttribute( name );
+                       }
+               }
+       },
+
+       attrHooks: {
+               type: {
+                       set: function( elem, value ) {
+                               if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+                                       // Setting the type on a radio button after the value resets the value in IE6-9
+                                       // Reset value to default in case type is set after value during creation
+                                       var val = elem.value;
+                                       elem.setAttribute( "type", value );
+                                       if ( val ) {
+                                               elem.value = val;
+                                       }
+                                       return value;
+                               }
+                       }
+               }
+       },
+
+       propFix: {
+               "for": "htmlFor",
+               "class": "className"
+       },
+
+       prop: function( elem, name, value ) {
+               var ret, hooks, notxml,
+                       nType = elem.nodeType;
+
+               // don't get/set properties on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+               if ( notxml ) {
+                       // Fix name and attach hooks
+                       name = jQuery.propFix[ name ] || name;
+                       hooks = jQuery.propHooks[ name ];
+               }
+
+               if ( value !== undefined ) {
+                       return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+                               ret :
+                               ( elem[ name ] = value );
+
+               } else {
+                       return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+                               ret :
+                               elem[ name ];
+               }
+       },
+
+       propHooks: {
+               tabIndex: {
+                       get: function( elem ) {
+                               return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
+                                       elem.tabIndex :
+                                       -1;
+                       }
+               }
+       }
+});
+
+// Hooks for boolean attributes
+boolHook = {
+       set: function( elem, value, name ) {
+               if ( value === false ) {
+                       // Remove boolean attributes when set to false
+                       jQuery.removeAttr( elem, name );
+               } else {
+                       elem.setAttribute( name, name );
+               }
+               return name;
+       }
+};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+       var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
+
+       jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
+               var fn = jQuery.expr.attrHandle[ name ],
+                       ret = isXML ?
+                               undefined :
+                               /* jshint eqeqeq: false */
+                               // Temporarily disable this handler to check existence
+                               (jQuery.expr.attrHandle[ name ] = undefined) !=
+                                       getter( elem, name, isXML ) ?
+
+                                       name.toLowerCase() :
+                                       null;
+
+               // Restore handler
+               jQuery.expr.attrHandle[ name ] = fn;
+
+               return ret;
+       };
+});
+
+// Support: IE9+
+// Selectedness for an option in an optgroup can be inaccurate
+if ( !jQuery.support.optSelected ) {
+       jQuery.propHooks.selected = {
+               get: function( elem ) {
+                       var parent = elem.parentNode;
+                       if ( parent && parent.parentNode ) {
+                               parent.parentNode.selectedIndex;
+                       }
+                       return null;
+               }
+       };
+}
+
+jQuery.each([
+       "tabIndex",
+       "readOnly",
+       "maxLength",
+       "cellSpacing",
+       "cellPadding",
+       "rowSpan",
+       "colSpan",
+       "useMap",
+       "frameBorder",
+       "contentEditable"
+], function() {
+       jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+       jQuery.valHooks[ this ] = {
+               set: function( elem, value ) {
+                       if ( jQuery.isArray( value ) ) {
+                               return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+                       }
+               }
+       };
+       if ( !jQuery.support.checkOn ) {
+               jQuery.valHooks[ this ].get = function( elem ) {
+                       // Support: Webkit
+                       // "" is returned instead of "on" if a value isn't specified
+                       return elem.getAttribute("value") === null ? "on" : elem.value;
+               };
+       }
+});
+var rkeyEvent = /^key/,
+       rmouseEvent = /^(?:mouse|contextmenu)|click/,
+       rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+       rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+       return true;
+}
+
+function returnFalse() {
+       return false;
+}
+
+function safeActiveElement() {
+       try {
+               return document.activeElement;
+       } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+       global: {},
+
+       add: function( elem, types, handler, data, selector ) {
+
+               var handleObjIn, eventHandle, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = data_priv.get( elem );
+
+               // Don't attach events to noData or text/comment nodes (but allow plain objects)
+               if ( !elemData ) {
+                       return;
+               }
+
+               // Caller can pass in an object of custom data in lieu of the handler
+               if ( handler.handler ) {
+                       handleObjIn = handler;
+                       handler = handleObjIn.handler;
+                       selector = handleObjIn.selector;
+               }
+
+               // Make sure that the handler has a unique ID, used to find/remove it later
+               if ( !handler.guid ) {
+                       handler.guid = jQuery.guid++;
+               }
+
+               // Init the element's event structure and main handler, if this is the first
+               if ( !(events = elemData.events) ) {
+                       events = elemData.events = {};
+               }
+               if ( !(eventHandle = elemData.handle) ) {
+                       eventHandle = elemData.handle = function( e ) {
+                               // Discard the second event of a jQuery.event.trigger() and
+                               // when an event is called after a page has unloaded
+                               return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+                                       jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+                                       undefined;
+                       };
+                       // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+                       eventHandle.elem = elem;
+               }
+
+               // Handle multiple events separated by a space
+               types = ( types || "" ).match( core_rnotwhite ) || [""];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // There *must* be a type, no attaching namespace-only handlers
+                       if ( !type ) {
+                               continue;
+                       }
+
+                       // If event changes its type, use the special event handlers for the changed type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // If selector defined, determine special event api type, otherwise given type
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+
+                       // Update special based on newly reset type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // handleObj is passed to all event handlers
+                       handleObj = jQuery.extend({
+                               type: type,
+                               origType: origType,
+                               data: data,
+                               handler: handler,
+                               guid: handler.guid,
+                               selector: selector,
+                               needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+                               namespace: namespaces.join(".")
+                       }, handleObjIn );
+
+                       // Init the event handler queue if we're the first
+                       if ( !(handlers = events[ type ]) ) {
+                               handlers = events[ type ] = [];
+                               handlers.delegateCount = 0;
+
+                               // Only use addEventListener if the special events handler returns false
+                               if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+                                       if ( elem.addEventListener ) {
+                                               elem.addEventListener( type, eventHandle, false );
+                                       }
+                               }
+                       }
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
+
+                               if ( !handleObj.handler.guid ) {
+                                       handleObj.handler.guid = handler.guid;
+                               }
+                       }
+
+                       // Add to the element's handler list, delegates in front
+                       if ( selector ) {
+                               handlers.splice( handlers.delegateCount++, 0, handleObj );
+                       } else {
+                               handlers.push( handleObj );
+                       }
+
+                       // Keep track of which events have ever been used, for event optimization
+                       jQuery.event.global[ type ] = true;
+               }
+
+               // Nullify elem to prevent memory leaks in IE
+               elem = null;
+       },
+
+       // Detach an event or set of events from an element
+       remove: function( elem, types, handler, selector, mappedTypes ) {
+
+               var j, origCount, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = data_priv.hasData( elem ) && data_priv.get( elem );
+
+               if ( !elemData || !(events = elemData.events) ) {
+                       return;
+               }
+
+               // Once for each type.namespace in types; type may be omitted
+               types = ( types || "" ).match( core_rnotwhite ) || [""];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // Unbind all events (on this namespace, if provided) for the element
+                       if ( !type ) {
+                               for ( type in events ) {
+                                       jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+                               }
+                               continue;
+                       }
+
+                       special = jQuery.event.special[ type ] || {};
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+                       handlers = events[ type ] || [];
+                       tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+                       // Remove matching events
+                       origCount = j = handlers.length;
+                       while ( j-- ) {
+                               handleObj = handlers[ j ];
+
+                               if ( ( mappedTypes || origType === handleObj.origType ) &&
+                                       ( !handler || handler.guid === handleObj.guid ) &&
+                                       ( !tmp || tmp.test( handleObj.namespace ) ) &&
+                                       ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+                                       handlers.splice( j, 1 );
+
+                                       if ( handleObj.selector ) {
+                                               handlers.delegateCount--;
+                                       }
+                                       if ( special.remove ) {
+                                               special.remove.call( elem, handleObj );
+                                       }
+                               }
+                       }
+
+                       // Remove generic event handler if we removed something and no more handlers exist
+                       // (avoids potential for endless recursion during removal of special event handlers)
+                       if ( origCount && !handlers.length ) {
+                               if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+                                       jQuery.removeEvent( elem, type, elemData.handle );
+                               }
+
+                               delete events[ type ];
+                       }
+               }
+
+               // Remove the expando if it's no longer used
+               if ( jQuery.isEmptyObject( events ) ) {
+                       delete elemData.handle;
+                       data_priv.remove( elem, "events" );
+               }
+       },
+
+       trigger: function( event, data, elem, onlyHandlers ) {
+
+               var i, cur, tmp, bubbleType, ontype, handle, special,
+                       eventPath = [ elem || document ],
+                       type = core_hasOwn.call( event, "type" ) ? event.type : event,
+                       namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+               cur = tmp = elem = elem || document;
+
+               // Don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               // focus/blur morphs to focusin/out; ensure we're not firing them right now
+               if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+                       return;
+               }
+
+               if ( type.indexOf(".") >= 0 ) {
+                       // Namespaced trigger; create a regexp to match event type in handle()
+                       namespaces = type.split(".");
+                       type = namespaces.shift();
+                       namespaces.sort();
+               }
+               ontype = type.indexOf(":") < 0 && "on" + type;
+
+               // Caller can pass in a jQuery.Event object, Object, or just an event type string
+               event = event[ jQuery.expando ] ?
+                       event :
+                       new jQuery.Event( type, typeof event === "object" && event );
+
+               // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+               event.isTrigger = onlyHandlers ? 2 : 3;
+               event.namespace = namespaces.join(".");
+               event.namespace_re = event.namespace ?
+                       new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+                       null;
+
+               // Clean up the event in case it is being reused
+               event.result = undefined;
+               if ( !event.target ) {
+                       event.target = elem;
+               }
+
+               // Clone any incoming data and prepend the event, creating the handler arg list
+               data = data == null ?
+                       [ event ] :
+                       jQuery.makeArray( data, [ event ] );
+
+               // Allow special events to draw outside the lines
+               special = jQuery.event.special[ type ] || {};
+               if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+                       return;
+               }
+
+               // Determine event propagation path in advance, per W3C events spec (#9951)
+               // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+               if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+                       bubbleType = special.delegateType || type;
+                       if ( !rfocusMorph.test( bubbleType + type ) ) {
+                               cur = cur.parentNode;
+                       }
+                       for ( ; cur; cur = cur.parentNode ) {
+                               eventPath.push( cur );
+                               tmp = cur;
+                       }
+
+                       // Only add window if we got to document (e.g., not plain obj or detached DOM)
+                       if ( tmp === (elem.ownerDocument || document) ) {
+                               eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+                       }
+               }
+
+               // Fire handlers on the event path
+               i = 0;
+               while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+                       event.type = i > 1 ?
+                               bubbleType :
+                               special.bindType || type;
+
+                       // jQuery handler
+                       handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
+                       if ( handle ) {
+                               handle.apply( cur, data );
+                       }
+
+                       // Native handler
+                       handle = ontype && cur[ ontype ];
+                       if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
+                               event.preventDefault();
+                       }
+               }
+               event.type = type;
+
+               // If nobody prevented the default action, do it now
+               if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+                       if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+                               jQuery.acceptData( elem ) ) {
+
+                               // Call a native DOM method on the target with the same name name as the event.
+                               // Don't do default actions on window, that's where global variables be (#6170)
+                               if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
+
+                                       // Don't re-trigger an onFOO event when we call its FOO() method
+                                       tmp = elem[ ontype ];
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = null;
+                                       }
+
+                                       // Prevent re-triggering of the same event, since we already bubbled it above
+                                       jQuery.event.triggered = type;
+                                       elem[ type ]();
+                                       jQuery.event.triggered = undefined;
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = tmp;
+                                       }
+                               }
+                       }
+               }
+
+               return event.result;
+       },
+
+       dispatch: function( event ) {
+
+               // Make a writable jQuery.Event from the native event object
+               event = jQuery.event.fix( event );
+
+               var i, j, ret, matched, handleObj,
+                       handlerQueue = [],
+                       args = core_slice.call( arguments ),
+                       handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
+                       special = jQuery.event.special[ event.type ] || {};
+
+               // Use the fix-ed jQuery.Event rather than the (read-only) native event
+               args[0] = event;
+               event.delegateTarget = this;
+
+               // Call the preDispatch hook for the mapped type, and let it bail if desired
+               if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+                       return;
+               }
+
+               // Determine handlers
+               handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+               // Run delegates first; they may want to stop propagation beneath us
+               i = 0;
+               while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+                       event.currentTarget = matched.elem;
+
+                       j = 0;
+                       while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+                               // Triggered event must either 1) have no namespace, or
+                               // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+                               if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+                                       event.handleObj = handleObj;
+                                       event.data = handleObj.data;
+
+                                       ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+                                                       .apply( matched.elem, args );
+
+                                       if ( ret !== undefined ) {
+                                               if ( (event.result = ret) === false ) {
+                                                       event.preventDefault();
+                                                       event.stopPropagation();
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Call the postDispatch hook for the mapped type
+               if ( special.postDispatch ) {
+                       special.postDispatch.call( this, event );
+               }
+
+               return event.result;
+       },
+
+       handlers: function( event, handlers ) {
+               var i, matches, sel, handleObj,
+                       handlerQueue = [],
+                       delegateCount = handlers.delegateCount,
+                       cur = event.target;
+
+               // Find delegate handlers
+               // Black-hole SVG <use> instance trees (#13180)
+               // Avoid non-left-click bubbling in Firefox (#3861)
+               if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+                       for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+                               // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+                               if ( cur.disabled !== true || event.type !== "click" ) {
+                                       matches = [];
+                                       for ( i = 0; i < delegateCount; i++ ) {
+                                               handleObj = handlers[ i ];
+
+                                               // Don't conflict with Object.prototype properties (#13203)
+                                               sel = handleObj.selector + " ";
+
+                                               if ( matches[ sel ] === undefined ) {
+                                                       matches[ sel ] = handleObj.needsContext ?
+                                                               jQuery( sel, this ).index( cur ) >= 0 :
+                                                               jQuery.find( sel, this, null, [ cur ] ).length;
+                                               }
+                                               if ( matches[ sel ] ) {
+                                                       matches.push( handleObj );
+                                               }
+                                       }
+                                       if ( matches.length ) {
+                                               handlerQueue.push({ elem: cur, handlers: matches });
+                                       }
+                               }
+                       }
+               }
+
+               // Add the remaining (directly-bound) handlers
+               if ( delegateCount < handlers.length ) {
+                       handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+               }
+
+               return handlerQueue;
+       },
+
+       // Includes some event props shared by KeyEvent and MouseEvent
+       props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+       fixHooks: {},
+
+       keyHooks: {
+               props: "char charCode key keyCode".split(" "),
+               filter: function( event, original ) {
+
+                       // Add which for key events
+                       if ( event.which == null ) {
+                               event.which = original.charCode != null ? original.charCode : original.keyCode;
+                       }
+
+                       return event;
+               }
+       },
+
+       mouseHooks: {
+               props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+               filter: function( event, original ) {
+                       var eventDoc, doc, body,
+                               button = original.button;
+
+                       // Calculate pageX/Y if missing and clientX/Y available
+                       if ( event.pageX == null && original.clientX != null ) {
+                               eventDoc = event.target.ownerDocument || document;
+                               doc = eventDoc.documentElement;
+                               body = eventDoc.body;
+
+                               event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+                               event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+                       }
+
+                       // Add which for click: 1 === left; 2 === middle; 3 === right
+                       // Note: button is not normalized, so don't use it
+                       if ( !event.which && button !== undefined ) {
+                               event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+                       }
+
+                       return event;
+               }
+       },
+
+       fix: function( event ) {
+               if ( event[ jQuery.expando ] ) {
+                       return event;
+               }
+
+               // Create a writable copy of the event object and normalize some properties
+               var i, prop, copy,
+                       type = event.type,
+                       originalEvent = event,
+                       fixHook = this.fixHooks[ type ];
+
+               if ( !fixHook ) {
+                       this.fixHooks[ type ] = fixHook =
+                               rmouseEvent.test( type ) ? this.mouseHooks :
+                               rkeyEvent.test( type ) ? this.keyHooks :
+                               {};
+               }
+               copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+               event = new jQuery.Event( originalEvent );
+
+               i = copy.length;
+               while ( i-- ) {
+                       prop = copy[ i ];
+                       event[ prop ] = originalEvent[ prop ];
+               }
+
+               // Support: Cordova 2.5 (WebKit) (#13255)
+               // All events should have a target; Cordova deviceready doesn't
+               if ( !event.target ) {
+                       event.target = document;
+               }
+
+               // Support: Safari 6.0+, Chrome < 28
+               // Target should not be a text node (#504, #13143)
+               if ( event.target.nodeType === 3 ) {
+                       event.target = event.target.parentNode;
+               }
+
+               return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+       },
+
+       special: {
+               load: {
+                       // Prevent triggered image.load events from bubbling to window.load
+                       noBubble: true
+               },
+               focus: {
+                       // Fire native event if possible so blur/focus sequence is correct
+                       trigger: function() {
+                               if ( this !== safeActiveElement() && this.focus ) {
+                                       this.focus();
+                                       return false;
+                               }
+                       },
+                       delegateType: "focusin"
+               },
+               blur: {
+                       trigger: function() {
+                               if ( this === safeActiveElement() && this.blur ) {
+                                       this.blur();
+                                       return false;
+                               }
+                       },
+                       delegateType: "focusout"
+               },
+               click: {
+                       // For checkbox, fire native event so checked state will be right
+                       trigger: function() {
+                               if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
+                                       this.click();
+                                       return false;
+                               }
+                       },
+
+                       // For cross-browser consistency, don't fire native .click() on links
+                       _default: function( event ) {
+                               return jQuery.nodeName( event.target, "a" );
+                       }
+               },
+
+               beforeunload: {
+                       postDispatch: function( event ) {
+
+                               // Support: Firefox 20+
+                               // Firefox doesn't alert if the returnValue field is not set.
+                               if ( event.result !== undefined ) {
+                                       event.originalEvent.returnValue = event.result;
+                               }
+                       }
+               }
+       },
+
+       simulate: function( type, elem, event, bubble ) {
+               // Piggyback on a donor event to simulate a different one.
+               // Fake originalEvent to avoid donor's stopPropagation, but if the
+               // simulated event prevents default then we do the same on the donor.
+               var e = jQuery.extend(
+                       new jQuery.Event(),
+                       event,
+                       {
+                               type: type,
+                               isSimulated: true,
+                               originalEvent: {}
+                       }
+               );
+               if ( bubble ) {
+                       jQuery.event.trigger( e, null, elem );
+               } else {
+                       jQuery.event.dispatch.call( elem, e );
+               }
+               if ( e.isDefaultPrevented() ) {
+                       event.preventDefault();
+               }
+       }
+};
+
+jQuery.removeEvent = function( elem, type, handle ) {
+       if ( elem.removeEventListener ) {
+               elem.removeEventListener( type, handle, false );
+       }
+};
+
+jQuery.Event = function( src, props ) {
+       // Allow instantiation without the 'new' keyword
+       if ( !(this instanceof jQuery.Event) ) {
+               return new jQuery.Event( src, props );
+       }
+
+       // Event object
+       if ( src && src.type ) {
+               this.originalEvent = src;
+               this.type = src.type;
+
+               // Events bubbling up the document may have been marked as prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = ( src.defaultPrevented ||
+                       src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+       // Event type
+       } else {
+               this.type = src;
+       }
+
+       // Put explicitly provided properties onto the event object
+       if ( props ) {
+               jQuery.extend( this, props );
+       }
+
+       // Create a timestamp if incoming event doesn't have one
+       this.timeStamp = src && src.timeStamp || jQuery.now();
+
+       // Mark it as fixed
+       this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+       isDefaultPrevented: returnFalse,
+       isPropagationStopped: returnFalse,
+       isImmediatePropagationStopped: returnFalse,
+
+       preventDefault: function() {
+               var e = this.originalEvent;
+
+               this.isDefaultPrevented = returnTrue;
+
+               if ( e && e.preventDefault ) {
+                       e.preventDefault();
+               }
+       },
+       stopPropagation: function() {
+               var e = this.originalEvent;
+
+               this.isPropagationStopped = returnTrue;
+
+               if ( e && e.stopPropagation ) {
+                       e.stopPropagation();
+               }
+       },
+       stopImmediatePropagation: function() {
+               this.isImmediatePropagationStopped = returnTrue;
+               this.stopPropagation();
+       }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// Support: Chrome 15+
+jQuery.each({
+       mouseenter: "mouseover",
+       mouseleave: "mouseout"
+}, function( orig, fix ) {
+       jQuery.event.special[ orig ] = {
+               delegateType: fix,
+               bindType: fix,
+
+               handle: function( event ) {
+                       var ret,
+                               target = this,
+                               related = event.relatedTarget,
+                               handleObj = event.handleObj;
+
+                       // For mousenter/leave call the handler if related is outside the target.
+                       // NB: No relatedTarget if the mouse left/entered the browser window
+                       if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+                               event.type = handleObj.origType;
+                               ret = handleObj.handler.apply( this, arguments );
+                               event.type = fix;
+                       }
+                       return ret;
+               }
+       };
+});
+
+// Create "bubbling" focus and blur events
+// Support: Firefox, Chrome, Safari
+if ( !jQuery.support.focusinBubbles ) {
+       jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+               // Attach a single capturing handler while someone wants focusin/focusout
+               var attaches = 0,
+                       handler = function( event ) {
+                               jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+                       };
+
+               jQuery.event.special[ fix ] = {
+                       setup: function() {
+                               if ( attaches++ === 0 ) {
+                                       document.addEventListener( orig, handler, true );
+                               }
+                       },
+                       teardown: function() {
+                               if ( --attaches === 0 ) {
+                                       document.removeEventListener( orig, handler, true );
+                               }
+                       }
+               };
+       });
+}
+
+jQuery.fn.extend({
+
+       on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+               var origFn, type;
+
+               // Types can be a map of types/handlers
+               if ( typeof types === "object" ) {
+                       // ( types-Object, selector, data )
+                       if ( typeof selector !== "string" ) {
+                               // ( types-Object, data )
+                               data = data || selector;
+                               selector = undefined;
+                       }
+                       for ( type in types ) {
+                               this.on( type, selector, data, types[ type ], one );
+                       }
+                       return this;
+               }
+
+               if ( data == null && fn == null ) {
+                       // ( types, fn )
+                       fn = selector;
+                       data = selector = undefined;
+               } else if ( fn == null ) {
+                       if ( typeof selector === "string" ) {
+                               // ( types, selector, fn )
+                               fn = data;
+                               data = undefined;
+                       } else {
+                               // ( types, data, fn )
+                               fn = data;
+                               data = selector;
+                               selector = undefined;
+                       }
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               } else if ( !fn ) {
+                       return this;
+               }
+
+               if ( one === 1 ) {
+                       origFn = fn;
+                       fn = function( event ) {
+                               // Can use an empty set, since event contains the info
+                               jQuery().off( event );
+                               return origFn.apply( this, arguments );
+                       };
+                       // Use same guid so caller can remove using origFn
+                       fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+               }
+               return this.each( function() {
+                       jQuery.event.add( this, types, fn, data, selector );
+               });
+       },
+       one: function( types, selector, data, fn ) {
+               return this.on( types, selector, data, fn, 1 );
+       },
+       off: function( types, selector, fn ) {
+               var handleObj, type;
+               if ( types && types.preventDefault && types.handleObj ) {
+                       // ( event )  dispatched jQuery.Event
+                       handleObj = types.handleObj;
+                       jQuery( types.delegateTarget ).off(
+                               handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+                               handleObj.selector,
+                               handleObj.handler
+                       );
+                       return this;
+               }
+               if ( typeof types === "object" ) {
+                       // ( types-object [, selector] )
+                       for ( type in types ) {
+                               this.off( type, selector, types[ type ] );
+                       }
+                       return this;
+               }
+               if ( selector === false || typeof selector === "function" ) {
+                       // ( types [, fn] )
+                       fn = selector;
+                       selector = undefined;
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               }
+               return this.each(function() {
+                       jQuery.event.remove( this, types, fn, selector );
+               });
+       },
+
+       trigger: function( type, data ) {
+               return this.each(function() {
+                       jQuery.event.trigger( type, data, this );
+               });
+       },
+       triggerHandler: function( type, data ) {
+               var elem = this[0];
+               if ( elem ) {
+                       return jQuery.event.trigger( type, data, elem, true );
+               }
+       }
+});
+var isSimple = /^.[^:#\[\.,]*$/,
+       rparentsprev = /^(?:parents|prev(?:Until|All))/,
+       rneedsContext = jQuery.expr.match.needsContext,
+       // methods guaranteed to produce a unique set when starting from a unique set
+       guaranteedUnique = {
+               children: true,
+               contents: true,
+               next: true,
+               prev: true
+       };
+
+jQuery.fn.extend({
+       find: function( selector ) {
+               var i,
+                       ret = [],
+                       self = this,
+                       len = self.length;
+
+               if ( typeof selector !== "string" ) {
+                       return this.pushStack( jQuery( selector ).filter(function() {
+                               for ( i = 0; i < len; i++ ) {
+                                       if ( jQuery.contains( self[ i ], this ) ) {
+                                               return true;
+                                       }
+                               }
+                       }) );
+               }
+
+               for ( i = 0; i < len; i++ ) {
+                       jQuery.find( selector, self[ i ], ret );
+               }
+
+               // Needed because $( selector, context ) becomes $( context ).find( selector )
+               ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+               ret.selector = this.selector ? this.selector + " " + selector : selector;
+               return ret;
+       },
+
+       has: function( target ) {
+               var targets = jQuery( target, this ),
+                       l = targets.length;
+
+               return this.filter(function() {
+                       var i = 0;
+                       for ( ; i < l; i++ ) {
+                               if ( jQuery.contains( this, targets[i] ) ) {
+                                       return true;
+                               }
+                       }
+               });
+       },
+
+       not: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], true) );
+       },
+
+       filter: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], false) );
+       },
+
+       is: function( selector ) {
+               return !!winnow(
+                       this,
+
+                       // If this is a positional/relative selector, check membership in the returned set
+                       // so $("p:first").is("p:last") won't return true for a doc with two "p".
+                       typeof selector === "string" && rneedsContext.test( selector ) ?
+                               jQuery( selector ) :
+                               selector || [],
+                       false
+               ).length;
+       },
+
+       closest: function( selectors, context ) {
+               var cur,
+                       i = 0,
+                       l = this.length,
+                       matched = [],
+                       pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ?
+                               jQuery( selectors, context || this.context ) :
+                               0;
+
+               for ( ; i < l; i++ ) {
+                       for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+                               // Always skip document fragments
+                               if ( cur.nodeType < 11 && (pos ?
+                                       pos.index(cur) > -1 :
+
+                                       // Don't pass non-elements to Sizzle
+                                       cur.nodeType === 1 &&
+                                               jQuery.find.matchesSelector(cur, selectors)) ) {
+
+                                       cur = matched.push( cur );
+                                       break;
+                               }
+                       }
+               }
+
+               return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+       },
+
+       // Determine the position of an element within
+       // the matched set of elements
+       index: function( elem ) {
+
+               // No argument, return index in parent
+               if ( !elem ) {
+                       return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+               }
+
+               // index in selector
+               if ( typeof elem === "string" ) {
+                       return core_indexOf.call( jQuery( elem ), this[ 0 ] );
+               }
+
+               // Locate the position of the desired element
+               return core_indexOf.call( this,
+
+                       // If it receives a jQuery object, the first element is used
+                       elem.jquery ? elem[ 0 ] : elem
+               );
+       },
+
+       add: function( selector, context ) {
+               var set = typeof selector === "string" ?
+                               jQuery( selector, context ) :
+                               jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+                       all = jQuery.merge( this.get(), set );
+
+               return this.pushStack( jQuery.unique(all) );
+       },
+
+       addBack: function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter(selector)
+               );
+       }
+});
+
+function sibling( cur, dir ) {
+       while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
+
+       return cur;
+}
+
+jQuery.each({
+       parent: function( elem ) {
+               var parent = elem.parentNode;
+               return parent && parent.nodeType !== 11 ? parent : null;
+       },
+       parents: function( elem ) {
+               return jQuery.dir( elem, "parentNode" );
+       },
+       parentsUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "parentNode", until );
+       },
+       next: function( elem ) {
+               return sibling( elem, "nextSibling" );
+       },
+       prev: function( elem ) {
+               return sibling( elem, "previousSibling" );
+       },
+       nextAll: function( elem ) {
+               return jQuery.dir( elem, "nextSibling" );
+       },
+       prevAll: function( elem ) {
+               return jQuery.dir( elem, "previousSibling" );
+       },
+       nextUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "nextSibling", until );
+       },
+       prevUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "previousSibling", until );
+       },
+       siblings: function( elem ) {
+               return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+       },
+       children: function( elem ) {
+               return jQuery.sibling( elem.firstChild );
+       },
+       contents: function( elem ) {
+               return elem.contentDocument || jQuery.merge( [], elem.childNodes );
+       }
+}, function( name, fn ) {
+       jQuery.fn[ name ] = function( until, selector ) {
+               var matched = jQuery.map( this, fn, until );
+
+               if ( name.slice( -5 ) !== "Until" ) {
+                       selector = until;
+               }
+
+               if ( selector && typeof selector === "string" ) {
+                       matched = jQuery.filter( selector, matched );
+               }
+
+               if ( this.length > 1 ) {
+                       // Remove duplicates
+                       if ( !guaranteedUnique[ name ] ) {
+                               jQuery.unique( matched );
+                       }
+
+                       // Reverse order for parents* and prev-derivatives
+                       if ( rparentsprev.test( name ) ) {
+                               matched.reverse();
+                       }
+               }
+
+               return this.pushStack( matched );
+       };
+});
+
+jQuery.extend({
+       filter: function( expr, elems, not ) {
+               var elem = elems[ 0 ];
+
+               if ( not ) {
+                       expr = ":not(" + expr + ")";
+               }
+
+               return elems.length === 1 && elem.nodeType === 1 ?
+                       jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+                       jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+                               return elem.nodeType === 1;
+                       }));
+       },
+
+       dir: function( elem, dir, until ) {
+               var matched = [],
+                       truncate = until !== undefined;
+
+               while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
+                       if ( elem.nodeType === 1 ) {
+                               if ( truncate && jQuery( elem ).is( until ) ) {
+                                       break;
+                               }
+                               matched.push( elem );
+                       }
+               }
+               return matched;
+       },
+
+       sibling: function( n, elem ) {
+               var matched = [];
+
+               for ( ; n; n = n.nextSibling ) {
+                       if ( n.nodeType === 1 && n !== elem ) {
+                               matched.push( n );
+                       }
+               }
+
+               return matched;
+       }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+       if ( jQuery.isFunction( qualifier ) ) {
+               return jQuery.grep( elements, function( elem, i ) {
+                       /* jshint -W018 */
+                       return !!qualifier.call( elem, i, elem ) !== not;
+               });
+
+       }
+
+       if ( qualifier.nodeType ) {
+               return jQuery.grep( elements, function( elem ) {
+                       return ( elem === qualifier ) !== not;
+               });
+
+       }
+
+       if ( typeof qualifier === "string" ) {
+               if ( isSimple.test( qualifier ) ) {
+                       return jQuery.filter( qualifier, elements, not );
+               }
+
+               qualifier = jQuery.filter( qualifier, elements );
+       }
+
+       return jQuery.grep( elements, function( elem ) {
+               return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
+       });
+}
+var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+       rtagName = /<([\w:]+)/,
+       rhtml = /<|&#?\w+;/,
+       rnoInnerhtml = /<(?:script|style|link)/i,
+       manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
+       // checked="checked" or checked
+       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+       rscriptType = /^$|\/(?:java|ecma)script/i,
+       rscriptTypeMasked = /^true\/(.*)/,
+       rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+       // We have to close these tags to support XHTML (#13200)
+       wrapMap = {
+
+               // Support: IE 9
+               option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+               thead: [ 1, "<table>", "</table>" ],
+               col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+               tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+               td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+               _default: [ 0, "", "" ]
+       };
+
+// Support: IE 9
+wrapMap.optgroup = wrapMap.option;
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+jQuery.fn.extend({
+       text: function( value ) {
+               return jQuery.access( this, function( value ) {
+                       return value === undefined ?
+                               jQuery.text( this ) :
+                               this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
+               }, null, value, arguments.length );
+       },
+
+       append: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.appendChild( elem );
+                       }
+               });
+       },
+
+       prepend: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.insertBefore( elem, target.firstChild );
+                       }
+               });
+       },
+
+       before: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this );
+                       }
+               });
+       },
+
+       after: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this.nextSibling );
+                       }
+               });
+       },
+
+       // keepData is for internal use only--do not document
+       remove: function( selector, keepData ) {
+               var elem,
+                       elems = selector ? jQuery.filter( selector, this ) : this,
+                       i = 0;
+
+               for ( ; (elem = elems[i]) != null; i++ ) {
+                       if ( !keepData && elem.nodeType === 1 ) {
+                               jQuery.cleanData( getAll( elem ) );
+                       }
+
+                       if ( elem.parentNode ) {
+                               if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+                                       setGlobalEval( getAll( elem, "script" ) );
+                               }
+                               elem.parentNode.removeChild( elem );
+                       }
+               }
+
+               return this;
+       },
+
+       empty: function() {
+               var elem,
+                       i = 0;
+
+               for ( ; (elem = this[i]) != null; i++ ) {
+                       if ( elem.nodeType === 1 ) {
+
+                               // Prevent memory leaks
+                               jQuery.cleanData( getAll( elem, false ) );
+
+                               // Remove any remaining nodes
+                               elem.textContent = "";
+                       }
+               }
+
+               return this;
+       },
+
+       clone: function( dataAndEvents, deepDataAndEvents ) {
+               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+               return this.map( function () {
+                       return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+               });
+       },
+
+       html: function( value ) {
+               return jQuery.access( this, function( value ) {
+                       var elem = this[ 0 ] || {},
+                               i = 0,
+                               l = this.length;
+
+                       if ( value === undefined && elem.nodeType === 1 ) {
+                               return elem.innerHTML;
+                       }
+
+                       // See if we can take a shortcut and just use innerHTML
+                       if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+                               !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+                               value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+                               try {
+                                       for ( ; i < l; i++ ) {
+                                               elem = this[ i ] || {};
+
+                                               // Remove element nodes and prevent memory leaks
+                                               if ( elem.nodeType === 1 ) {
+                                                       jQuery.cleanData( getAll( elem, false ) );
+                                                       elem.innerHTML = value;
+                                               }
+                                       }
+
+                                       elem = 0;
+
+                               // If using innerHTML throws an exception, use the fallback method
+                               } catch( e ) {}
+                       }
+
+                       if ( elem ) {
+                               this.empty().append( value );
+                       }
+               }, null, value, arguments.length );
+       },
+
+       replaceWith: function() {
+               var
+                       // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
+                       args = jQuery.map( this, function( elem ) {
+                               return [ elem.nextSibling, elem.parentNode ];
+                       }),
+                       i = 0;
+
+               // Make the changes, replacing each context element with the new content
+               this.domManip( arguments, function( elem ) {
+                       var next = args[ i++ ],
+                               parent = args[ i++ ];
+
+                       if ( parent ) {
+                               // Don't use the snapshot next if it has moved (#13810)
+                               if ( next && next.parentNode !== parent ) {
+                                       next = this.nextSibling;
+                               }
+                               jQuery( this ).remove();
+                               parent.insertBefore( elem, next );
+                       }
+               // Allow new content to include elements from the context set
+               }, true );
+
+               // Force removal if there was no new content (e.g., from empty arguments)
+               return i ? this : this.remove();
+       },
+
+       detach: function( selector ) {
+               return this.remove( selector, true );
+       },
+
+       domManip: function( args, callback, allowIntersection ) {
+
+               // Flatten any nested arrays
+               args = core_concat.apply( [], args );
+
+               var fragment, first, scripts, hasScripts, node, doc,
+                       i = 0,
+                       l = this.length,
+                       set = this,
+                       iNoClone = l - 1,
+                       value = args[ 0 ],
+                       isFunction = jQuery.isFunction( value );
+
+               // We can't cloneNode fragments that contain checked, in WebKit
+               if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+                       return this.each(function( index ) {
+                               var self = set.eq( index );
+                               if ( isFunction ) {
+                                       args[ 0 ] = value.call( this, index, self.html() );
+                               }
+                               self.domManip( args, callback, allowIntersection );
+                       });
+               }
+
+               if ( l ) {
+                       fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
+                       first = fragment.firstChild;
+
+                       if ( fragment.childNodes.length === 1 ) {
+                               fragment = first;
+                       }
+
+                       if ( first ) {
+                               scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+                               hasScripts = scripts.length;
+
+                               // Use the original fragment for the last item instead of the first because it can end up
+                               // being emptied incorrectly in certain situations (#8070).
+                               for ( ; i < l; i++ ) {
+                                       node = fragment;
+
+                                       if ( i !== iNoClone ) {
+                                               node = jQuery.clone( node, true, true );
+
+                                               // Keep references to cloned scripts for later restoration
+                                               if ( hasScripts ) {
+                                                       // Support: QtWebKit
+                                                       // jQuery.merge because core_push.apply(_, arraylike) throws
+                                                       jQuery.merge( scripts, getAll( node, "script" ) );
+                                               }
+                                       }
+
+                                       callback.call( this[ i ], node, i );
+                               }
+
+                               if ( hasScripts ) {
+                                       doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+                                       // Reenable scripts
+                                       jQuery.map( scripts, restoreScript );
+
+                                       // Evaluate executable scripts on first document insertion
+                                       for ( i = 0; i < hasScripts; i++ ) {
+                                               node = scripts[ i ];
+                                               if ( rscriptType.test( node.type || "" ) &&
+                                                       !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+                                                       if ( node.src ) {
+                                                               // Hope ajax is available...
+                                                               jQuery._evalUrl( node.src );
+                                                       } else {
+                                                               jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       }
+});
+
+jQuery.each({
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function( name, original ) {
+       jQuery.fn[ name ] = function( selector ) {
+               var elems,
+                       ret = [],
+                       insert = jQuery( selector ),
+                       last = insert.length - 1,
+                       i = 0;
+
+               for ( ; i <= last; i++ ) {
+                       elems = i === last ? this : this.clone( true );
+                       jQuery( insert[ i ] )[ original ]( elems );
+
+                       // Support: QtWebKit
+                       // .get() because core_push.apply(_, arraylike) throws
+                       core_push.apply( ret, elems.get() );
+               }
+
+               return this.pushStack( ret );
+       };
+});
+
+jQuery.extend({
+       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+               var i, l, srcElements, destElements,
+                       clone = elem.cloneNode( true ),
+                       inPage = jQuery.contains( elem.ownerDocument, elem );
+
+               // Support: IE >= 9
+               // Fix Cloning issues
+               if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
+
+                       // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+                       destElements = getAll( clone );
+                       srcElements = getAll( elem );
+
+                       for ( i = 0, l = srcElements.length; i < l; i++ ) {
+                               fixInput( srcElements[ i ], destElements[ i ] );
+                       }
+               }
+
+               // Copy the events from the original to the clone
+               if ( dataAndEvents ) {
+                       if ( deepDataAndEvents ) {
+                               srcElements = srcElements || getAll( elem );
+                               destElements = destElements || getAll( clone );
+
+                               for ( i = 0, l = srcElements.length; i < l; i++ ) {
+                                       cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+                               }
+                       } else {
+                               cloneCopyEvent( elem, clone );
+                       }
+               }
+
+               // Preserve script evaluation history
+               destElements = getAll( clone, "script" );
+               if ( destElements.length > 0 ) {
+                       setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+               }
+
+               // Return the cloned set
+               return clone;
+       },
+
+       buildFragment: function( elems, context, scripts, selection ) {
+               var elem, tmp, tag, wrap, contains, j,
+                       i = 0,
+                       l = elems.length,
+                       fragment = context.createDocumentFragment(),
+                       nodes = [];
+
+               for ( ; i < l; i++ ) {
+                       elem = elems[ i ];
+
+                       if ( elem || elem === 0 ) {
+
+                               // Add nodes directly
+                               if ( jQuery.type( elem ) === "object" ) {
+                                       // Support: QtWebKit
+                                       // jQuery.merge because core_push.apply(_, arraylike) throws
+                                       jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+                               // Convert non-html into a text node
+                               } else if ( !rhtml.test( elem ) ) {
+                                       nodes.push( context.createTextNode( elem ) );
+
+                               // Convert html into DOM nodes
+                               } else {
+                                       tmp = tmp || fragment.appendChild( context.createElement("div") );
+
+                                       // Deserialize a standard representation
+                                       tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
+                                       wrap = wrapMap[ tag ] || wrapMap._default;
+                                       tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
+
+                                       // Descend through wrappers to the right content
+                                       j = wrap[ 0 ];
+                                       while ( j-- ) {
+                                               tmp = tmp.firstChild;
+                                       }
+
+                                       // Support: QtWebKit
+                                       // jQuery.merge because core_push.apply(_, arraylike) throws
+                                       jQuery.merge( nodes, tmp.childNodes );
+
+                                       // Remember the top-level container
+                                       tmp = fragment.firstChild;
+
+                                       // Fixes #12346
+                                       // Support: Webkit, IE
+                                       tmp.textContent = "";
+                               }
+                       }
+               }
+
+               // Remove wrapper from fragment
+               fragment.textContent = "";
+
+               i = 0;
+               while ( (elem = nodes[ i++ ]) ) {
+
+                       // #4087 - If origin and destination elements are the same, and this is
+                       // that element, do not do anything
+                       if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+                               continue;
+                       }
+
+                       contains = jQuery.contains( elem.ownerDocument, elem );
+
+                       // Append to fragment
+                       tmp = getAll( fragment.appendChild( elem ), "script" );
+
+                       // Preserve script evaluation history
+                       if ( contains ) {
+                               setGlobalEval( tmp );
+                       }
+
+                       // Capture executables
+                       if ( scripts ) {
+                               j = 0;
+                               while ( (elem = tmp[ j++ ]) ) {
+                                       if ( rscriptType.test( elem.type || "" ) ) {
+                                               scripts.push( elem );
+                                       }
+                               }
+                       }
+               }
+
+               return fragment;
+       },
+
+       cleanData: function( elems ) {
+               var data, elem, events, type, key, j,
+                       special = jQuery.event.special,
+                       i = 0;
+
+               for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
+                       if ( Data.accepts( elem ) ) {
+                               key = elem[ data_priv.expando ];
+
+                               if ( key && (data = data_priv.cache[ key ]) ) {
+                                       events = Object.keys( data.events || {} );
+                                       if ( events.length ) {
+                                               for ( j = 0; (type = events[j]) !== undefined; j++ ) {
+                                                       if ( special[ type ] ) {
+                                                               jQuery.event.remove( elem, type );
+
+                                                       // This is a shortcut to avoid jQuery.event.remove's overhead
+                                                       } else {
+                                                               jQuery.removeEvent( elem, type, data.handle );
+                                                       }
+                                               }
+                                       }
+                                       if ( data_priv.cache[ key ] ) {
+                                               // Discard any remaining `private` data
+                                               delete data_priv.cache[ key ];
+                                       }
+                               }
+                       }
+                       // Discard any remaining `user` data
+                       delete data_user.cache[ elem[ data_user.expando ] ];
+               }
+       },
+
+       _evalUrl: function( url ) {
+               return jQuery.ajax({
+                       url: url,
+                       type: "GET",
+                       dataType: "script",
+                       async: false,
+                       global: false,
+                       "throws": true
+               });
+       }
+});
+
+// Support: 1.x compatibility
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+       return jQuery.nodeName( elem, "table" ) &&
+               jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
+
+               elem.getElementsByTagName("tbody")[0] ||
+                       elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+               elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+       elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
+       return elem;
+}
+function restoreScript( elem ) {
+       var match = rscriptTypeMasked.exec( elem.type );
+
+       if ( match ) {
+               elem.type = match[ 1 ];
+       } else {
+               elem.removeAttribute("type");
+       }
+
+       return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+       var l = elems.length,
+               i = 0;
+
+       for ( ; i < l; i++ ) {
+               data_priv.set(
+                       elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
+               );
+       }
+}
+
+function cloneCopyEvent( src, dest ) {
+       var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+
+       if ( dest.nodeType !== 1 ) {
+               return;
+       }
+
+       // 1. Copy private data: events, handlers, etc.
+       if ( data_priv.hasData( src ) ) {
+               pdataOld = data_priv.access( src );
+               pdataCur = data_priv.set( dest, pdataOld );
+               events = pdataOld.events;
+
+               if ( events ) {
+                       delete pdataCur.handle;
+                       pdataCur.events = {};
+
+                       for ( type in events ) {
+                               for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+                                       jQuery.event.add( dest, type, events[ type ][ i ] );
+                               }
+                       }
+               }
+       }
+
+       // 2. Copy user data
+       if ( data_user.hasData( src ) ) {
+               udataOld = data_user.access( src );
+               udataCur = jQuery.extend( {}, udataOld );
+
+               data_user.set( dest, udataCur );
+       }
+}
+
+
+function getAll( context, tag ) {
+       var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
+                       context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
+                       [];
+
+       return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+               jQuery.merge( [ context ], ret ) :
+               ret;
+}
+
+// Support: IE >= 9
+function fixInput( src, dest ) {
+       var nodeName = dest.nodeName.toLowerCase();
+
+       // Fails to persist the checked state of a cloned checkbox or radio button.
+       if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+               dest.checked = src.checked;
+
+       // Fails to return the selected option to the default selected state when cloning options
+       } else if ( nodeName === "input" || nodeName === "textarea" ) {
+               dest.defaultValue = src.defaultValue;
+       }
+}
+jQuery.fn.extend({
+       wrapAll: function( html ) {
+               var wrap;
+
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).wrapAll( html.call(this, i) );
+                       });
+               }
+
+               if ( this[ 0 ] ) {
+
+                       // The elements to wrap the target around
+                       wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+                       if ( this[ 0 ].parentNode ) {
+                               wrap.insertBefore( this[ 0 ] );
+                       }
+
+                       wrap.map(function() {
+                               var elem = this;
+
+                               while ( elem.firstElementChild ) {
+                                       elem = elem.firstElementChild;
+                               }
+
+                               return elem;
+                       }).append( this );
+               }
+
+               return this;
+       },
+
+       wrapInner: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).wrapInner( html.call(this, i) );
+                       });
+               }
+
+               return this.each(function() {
+                       var self = jQuery( this ),
+                               contents = self.contents();
+
+                       if ( contents.length ) {
+                               contents.wrapAll( html );
+
+                       } else {
+                               self.append( html );
+                       }
+               });
+       },
+
+       wrap: function( html ) {
+               var isFunction = jQuery.isFunction( html );
+
+               return this.each(function( i ) {
+                       jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+               });
+       },
+
+       unwrap: function() {
+               return this.parent().each(function() {
+                       if ( !jQuery.nodeName( this, "body" ) ) {
+                               jQuery( this ).replaceWith( this.childNodes );
+                       }
+               }).end();
+       }
+});
+var curCSS, iframe,
+       // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+       // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+       rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+       rmargin = /^margin/,
+       rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+       rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+       rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+       elemdisplay = { BODY: "block" },
+
+       cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+       cssNormalTransform = {
+               letterSpacing: 0,
+               fontWeight: 400
+       },
+
+       cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+       cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+       // shortcut for names that are not vendor prefixed
+       if ( name in style ) {
+               return name;
+       }
+
+       // check for vendor prefixed names
+       var capName = name.charAt(0).toUpperCase() + name.slice(1),
+               origName = name,
+               i = cssPrefixes.length;
+
+       while ( i-- ) {
+               name = cssPrefixes[ i ] + capName;
+               if ( name in style ) {
+                       return name;
+               }
+       }
+
+       return origName;
+}
+
+function isHidden( elem, el ) {
+       // isHidden might be called from jQuery#filter function;
+       // in that case, element will be second argument
+       elem = el || elem;
+       return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+}
+
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+function getStyles( elem ) {
+       return window.getComputedStyle( elem, null );
+}
+
+function showHide( elements, show ) {
+       var display, elem, hidden,
+               values = [],
+               index = 0,
+               length = elements.length;
+
+       for ( ; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+
+               values[ index ] = data_priv.get( elem, "olddisplay" );
+               display = elem.style.display;
+               if ( show ) {
+                       // Reset the inline display of this element to learn if it is
+                       // being hidden by cascaded rules or not
+                       if ( !values[ index ] && display === "none" ) {
+                               elem.style.display = "";
+                       }
+
+                       // Set elements which have been overridden with display: none
+                       // in a stylesheet to whatever the default browser style is
+                       // for such an element
+                       if ( elem.style.display === "" && isHidden( elem ) ) {
+                               values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+                       }
+               } else {
+
+                       if ( !values[ index ] ) {
+                               hidden = isHidden( elem );
+
+                               if ( display && display !== "none" || !hidden ) {
+                                       data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
+                               }
+                       }
+               }
+       }
+
+       // Set the display of most of the elements in a second loop
+       // to avoid the constant reflow
+       for ( index = 0; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+               if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+                       elem.style.display = show ? values[ index ] || "" : "none";
+               }
+       }
+
+       return elements;
+}
+
+jQuery.fn.extend({
+       css: function( name, value ) {
+               return jQuery.access( this, function( elem, name, value ) {
+                       var styles, len,
+                               map = {},
+                               i = 0;
+
+                       if ( jQuery.isArray( name ) ) {
+                               styles = getStyles( elem );
+                               len = name.length;
+
+                               for ( ; i < len; i++ ) {
+                                       map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+                               }
+
+                               return map;
+                       }
+
+                       return value !== undefined ?
+                               jQuery.style( elem, name, value ) :
+                               jQuery.css( elem, name );
+               }, name, value, arguments.length > 1 );
+       },
+       show: function() {
+               return showHide( this, true );
+       },
+       hide: function() {
+               return showHide( this );
+       },
+       toggle: function( state ) {
+               var bool = typeof state === "boolean";
+
+               return this.each(function() {
+                       if ( bool ? state : isHidden( this ) ) {
+                               jQuery( this ).show();
+                       } else {
+                               jQuery( this ).hide();
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       // Add in style property hooks for overriding the default
+       // behavior of getting and setting a style property
+       cssHooks: {
+               opacity: {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+                                       // We should always get a number back from opacity
+                                       var ret = curCSS( elem, "opacity" );
+                                       return ret === "" ? "1" : ret;
+                               }
+                       }
+               }
+       },
+
+       // Don't automatically add "px" to these possibly-unitless properties
+       cssNumber: {
+               "columnCount": true,
+               "fillOpacity": true,
+               "fontWeight": true,
+               "lineHeight": true,
+               "opacity": true,
+               "orphans": true,
+               "widows": true,
+               "zIndex": true,
+               "zoom": true
+       },
+
+       // Add in properties whose names you wish to fix before
+       // setting or getting the value
+       cssProps: {
+               // normalize float css property
+               "float": "cssFloat"
+       },
+
+       // Get and set the style property on a DOM Node
+       style: function( elem, name, value, extra ) {
+               // Don't set styles on text and comment nodes
+               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+                       return;
+               }
+
+               // Make sure that we're working with the right name
+               var ret, type, hooks,
+                       origName = jQuery.camelCase( name ),
+                       style = elem.style;
+
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // Check if we're setting a value
+               if ( value !== undefined ) {
+                       type = typeof value;
+
+                       // convert relative number strings (+= or -=) to relative numbers. #7345
+                       if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+                               value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+                               // Fixes bug #9237
+                               type = "number";
+                       }
+
+                       // Make sure that NaN and null values aren't set. See: #7116
+                       if ( value == null || type === "number" && isNaN( value ) ) {
+                               return;
+                       }
+
+                       // If a number was passed in, add 'px' to the (except for certain CSS properties)
+                       if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+                               value += "px";
+                       }
+
+                       // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
+                       // but it would mean to define eight (for every problematic property) identical functions
+                       if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+                               style[ name ] = "inherit";
+                       }
+
+                       // If a hook was provided, use that value, otherwise just set the specified value
+                       if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+                               style[ name ] = value;
+                       }
+
+               } else {
+                       // If a hook was provided get the non-computed value from there
+                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+                               return ret;
+                       }
+
+                       // Otherwise just get the value from the style object
+                       return style[ name ];
+               }
+       },
+
+       css: function( elem, name, extra, styles ) {
+               var val, num, hooks,
+                       origName = jQuery.camelCase( name );
+
+               // Make sure that we're working with the right name
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // If a hook was provided get the computed value from there
+               if ( hooks && "get" in hooks ) {
+                       val = hooks.get( elem, true, extra );
+               }
+
+               // Otherwise, if a way to get the computed value exists, use that
+               if ( val === undefined ) {
+                       val = curCSS( elem, name, styles );
+               }
+
+               //convert "normal" to computed value
+               if ( val === "normal" && name in cssNormalTransform ) {
+                       val = cssNormalTransform[ name ];
+               }
+
+               // Return, converting to number if forced or a qualifier was provided and val looks numeric
+               if ( extra === "" || extra ) {
+                       num = parseFloat( val );
+                       return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+               }
+               return val;
+       }
+});
+
+curCSS = function( elem, name, _computed ) {
+       var width, minWidth, maxWidth,
+               computed = _computed || getStyles( elem ),
+
+               // Support: IE9
+               // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+               ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+               style = elem.style;
+
+       if ( computed ) {
+
+               if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+                       ret = jQuery.style( elem, name );
+               }
+
+               // Support: Safari 5.1
+               // A tribute to the "awesome hack by Dean Edwards"
+               // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+               // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+               if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+                       // Remember the original values
+                       width = style.width;
+                       minWidth = style.minWidth;
+                       maxWidth = style.maxWidth;
+
+                       // Put in the new values to get a computed value out
+                       style.minWidth = style.maxWidth = style.width = ret;
+                       ret = computed.width;
+
+                       // Revert the changed values
+                       style.width = width;
+                       style.minWidth = minWidth;
+                       style.maxWidth = maxWidth;
+               }
+       }
+
+       return ret;
+};
+
+
+function setPositiveNumber( elem, value, subtract ) {
+       var matches = rnumsplit.exec( value );
+       return matches ?
+               // Guard against undefined "subtract", e.g., when used as in cssHooks
+               Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+               value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+       var i = extra === ( isBorderBox ? "border" : "content" ) ?
+               // If we already have the right measurement, avoid augmentation
+               4 :
+               // Otherwise initialize for horizontal or vertical properties
+               name === "width" ? 1 : 0,
+
+               val = 0;
+
+       for ( ; i < 4; i += 2 ) {
+               // both box models exclude margin, so add it if we want it
+               if ( extra === "margin" ) {
+                       val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+               }
+
+               if ( isBorderBox ) {
+                       // border-box includes padding, so remove it if we want content
+                       if ( extra === "content" ) {
+                               val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+                       }
+
+                       // at this point, extra isn't border nor margin, so remove border
+                       if ( extra !== "margin" ) {
+                               val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+               } else {
+                       // at this point, extra isn't content, so add padding
+                       val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+                       // at this point, extra isn't content nor padding, so add border
+                       if ( extra !== "padding" ) {
+                               val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+               }
+       }
+
+       return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+       // Start with offset property, which is equivalent to the border-box value
+       var valueIsBorderBox = true,
+               val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+               styles = getStyles( elem ),
+               isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+       // some non-html elements return undefined for offsetWidth, so check for null/undefined
+       // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+       // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+       if ( val <= 0 || val == null ) {
+               // Fall back to computed then uncomputed css if necessary
+               val = curCSS( elem, name, styles );
+               if ( val < 0 || val == null ) {
+                       val = elem.style[ name ];
+               }
+
+               // Computed unit is not pixels. Stop here and return.
+               if ( rnumnonpx.test(val) ) {
+                       return val;
+               }
+
+               // we need the check for style in case a browser which returns unreliable values
+               // for getComputedStyle silently falls back to the reliable elem.style
+               valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+               // Normalize "", auto, and prepare for extra
+               val = parseFloat( val ) || 0;
+       }
+
+       // use the active box-sizing model to add/subtract irrelevant styles
+       return ( val +
+               augmentWidthOrHeight(
+                       elem,
+                       name,
+                       extra || ( isBorderBox ? "border" : "content" ),
+                       valueIsBorderBox,
+                       styles
+               )
+       ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+       var doc = document,
+               display = elemdisplay[ nodeName ];
+
+       if ( !display ) {
+               display = actualDisplay( nodeName, doc );
+
+               // If the simple way fails, read from inside an iframe
+               if ( display === "none" || !display ) {
+                       // Use the already-created iframe if possible
+                       iframe = ( iframe ||
+                               jQuery("<iframe frameborder='0' width='0' height='0'/>")
+                               .css( "cssText", "display:block !important" )
+                       ).appendTo( doc.documentElement );
+
+                       // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+                       doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+                       doc.write("<!doctype html><html><body>");
+                       doc.close();
+
+                       display = actualDisplay( nodeName, doc );
+                       iframe.detach();
+               }
+
+               // Store the correct default display
+               elemdisplay[ nodeName ] = display;
+       }
+
+       return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+       var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+               display = jQuery.css( elem[0], "display" );
+       elem.remove();
+       return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+       jQuery.cssHooks[ name ] = {
+               get: function( elem, computed, extra ) {
+                       if ( computed ) {
+                               // certain elements can have dimension info if we invisibly show them
+                               // however, it must have a current display style that would benefit from this
+                               return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
+                                       jQuery.swap( elem, cssShow, function() {
+                                               return getWidthOrHeight( elem, name, extra );
+                                       }) :
+                                       getWidthOrHeight( elem, name, extra );
+                       }
+               },
+
+               set: function( elem, value, extra ) {
+                       var styles = extra && getStyles( elem );
+                       return setPositiveNumber( elem, value, extra ?
+                               augmentWidthOrHeight(
+                                       elem,
+                                       name,
+                                       extra,
+                                       jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+                                       styles
+                               ) : 0
+                       );
+               }
+       };
+});
+
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
+jQuery(function() {
+       // Support: Android 2.3
+       if ( !jQuery.support.reliableMarginRight ) {
+               jQuery.cssHooks.marginRight = {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+                                       // Support: Android 2.3
+                                       // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                                       // Work around by temporarily setting element display to inline-block
+                                       return jQuery.swap( elem, { "display": "inline-block" },
+                                               curCSS, [ elem, "marginRight" ] );
+                               }
+                       }
+               };
+       }
+
+       // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+       // getComputedStyle returns percent when specified for top/left/bottom/right
+       // rather than make the css module depend on the offset module, we just check for it here
+       if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+               jQuery.each( [ "top", "left" ], function( i, prop ) {
+                       jQuery.cssHooks[ prop ] = {
+                               get: function( elem, computed ) {
+                                       if ( computed ) {
+                                               computed = curCSS( elem, prop );
+                                               // if curCSS returns percentage, fallback to offset
+                                               return rnumnonpx.test( computed ) ?
+                                                       jQuery( elem ).position()[ prop ] + "px" :
+                                                       computed;
+                                       }
+                               }
+                       };
+               });
+       }
+
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+       jQuery.expr.filters.hidden = function( elem ) {
+               // Support: Opera <= 12.12
+               // Opera reports offsetWidths and offsetHeights less than zero on some elements
+               return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
+       };
+
+       jQuery.expr.filters.visible = function( elem ) {
+               return !jQuery.expr.filters.hidden( elem );
+       };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+       margin: "",
+       padding: "",
+       border: "Width"
+}, function( prefix, suffix ) {
+       jQuery.cssHooks[ prefix + suffix ] = {
+               expand: function( value ) {
+                       var i = 0,
+                               expanded = {},
+
+                               // assumes a single number if not a string
+                               parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+                       for ( ; i < 4; i++ ) {
+                               expanded[ prefix + cssExpand[ i ] + suffix ] =
+                                       parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+                       }
+
+                       return expanded;
+               }
+       };
+
+       if ( !rmargin.test( prefix ) ) {
+               jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+       }
+});
+var r20 = /%20/g,
+       rbracket = /\[\]$/,
+       rCRLF = /\r?\n/g,
+       rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+       rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+       serialize: function() {
+               return jQuery.param( this.serializeArray() );
+       },
+       serializeArray: function() {
+               return this.map(function(){
+                       // Can add propHook for "elements" to filter or add form elements
+                       var elements = jQuery.prop( this, "elements" );
+                       return elements ? jQuery.makeArray( elements ) : this;
+               })
+               .filter(function(){
+                       var type = this.type;
+                       // Use .is(":disabled") so that fieldset[disabled] works
+                       return this.name && !jQuery( this ).is( ":disabled" ) &&
+                               rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+                               ( this.checked || !manipulation_rcheckableType.test( type ) );
+               })
+               .map(function( i, elem ){
+                       var val = jQuery( this ).val();
+
+                       return val == null ?
+                               null :
+                               jQuery.isArray( val ) ?
+                                       jQuery.map( val, function( val ){
+                                               return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                                       }) :
+                                       { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+               }).get();
+       }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+       var prefix,
+               s = [],
+               add = function( key, value ) {
+                       // If value is a function, invoke it and return its value
+                       value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+                       s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+               };
+
+       // Set traditional to true for jQuery <= 1.3.2 behavior.
+       if ( traditional === undefined ) {
+               traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+       }
+
+       // If an array was passed in, assume that it is an array of form elements.
+       if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+               // Serialize the form elements
+               jQuery.each( a, function() {
+                       add( this.name, this.value );
+               });
+
+       } else {
+               // If traditional, encode the "old" way (the way 1.3.2 or older
+               // did it), otherwise encode params recursively.
+               for ( prefix in a ) {
+                       buildParams( prefix, a[ prefix ], traditional, add );
+               }
+       }
+
+       // Return the resulting serialization
+       return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+       var name;
+
+       if ( jQuery.isArray( obj ) ) {
+               // Serialize array item.
+               jQuery.each( obj, function( i, v ) {
+                       if ( traditional || rbracket.test( prefix ) ) {
+                               // Treat each array item as a scalar.
+                               add( prefix, v );
+
+                       } else {
+                               // Item is non-scalar (array or object), encode its numeric index.
+                               buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+                       }
+               });
+
+       } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+               // Serialize object item.
+               for ( name in obj ) {
+                       buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+               }
+
+       } else {
+               // Serialize scalar item.
+               add( prefix, obj );
+       }
+}
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+       "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+       // Handle event binding
+       jQuery.fn[ name ] = function( data, fn ) {
+               return arguments.length > 0 ?
+                       this.on( name, null, data, fn ) :
+                       this.trigger( name );
+       };
+});
+
+jQuery.fn.extend({
+       hover: function( fnOver, fnOut ) {
+               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+       },
+
+       bind: function( types, data, fn ) {
+               return this.on( types, null, data, fn );
+       },
+       unbind: function( types, fn ) {
+               return this.off( types, null, fn );
+       },
+
+       delegate: function( selector, types, data, fn ) {
+               return this.on( types, selector, data, fn );
+       },
+       undelegate: function( selector, types, fn ) {
+               // ( namespace ) or ( selector, types [, fn] )
+               return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+       }
+});
+var
+       // Document location
+       ajaxLocParts,
+       ajaxLocation,
+
+       ajax_nonce = jQuery.now(),
+
+       ajax_rquery = /\?/,
+       rhash = /#.*$/,
+       rts = /([?&])_=[^&]*/,
+       rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+       // #7653, #8125, #8152: local protocol detection
+       rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+       rnoContent = /^(?:GET|HEAD)$/,
+       rprotocol = /^\/\//,
+       rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
+
+       // Keep a copy of the old load method
+       _load = jQuery.fn.load,
+
+       /* Prefilters
+        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+        * 2) These are called:
+        *    - BEFORE asking for a transport
+        *    - AFTER param serialization (s.data is a string if s.processData is true)
+        * 3) key is the dataType
+        * 4) the catchall symbol "*" can be used
+        * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+        */
+       prefilters = {},
+
+       /* Transports bindings
+        * 1) key is the dataType
+        * 2) the catchall symbol "*" can be used
+        * 3) selection will start with transport dataType and THEN go to "*" if needed
+        */
+       transports = {},
+
+       // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+       allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+       ajaxLocation = location.href;
+} catch( e ) {
+       // Use the href attribute of an A element
+       // since IE will modify it given document.location
+       ajaxLocation = document.createElement( "a" );
+       ajaxLocation.href = "";
+       ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+       // dataTypeExpression is optional and defaults to "*"
+       return function( dataTypeExpression, func ) {
+
+               if ( typeof dataTypeExpression !== "string" ) {
+                       func = dataTypeExpression;
+                       dataTypeExpression = "*";
+               }
+
+               var dataType,
+                       i = 0,
+                       dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
+               if ( jQuery.isFunction( func ) ) {
+                       // For each dataType in the dataTypeExpression
+                       while ( (dataType = dataTypes[i++]) ) {
+                               // Prepend if requested
+                               if ( dataType[0] === "+" ) {
+                                       dataType = dataType.slice( 1 ) || "*";
+                                       (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+                               // Otherwise append
+                               } else {
+                                       (structure[ dataType ] = structure[ dataType ] || []).push( func );
+                               }
+                       }
+               }
+       };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+       var inspected = {},
+               seekingTransport = ( structure === transports );
+
+       function inspect( dataType ) {
+               var selected;
+               inspected[ dataType ] = true;
+               jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+                       var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+                       if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+                               options.dataTypes.unshift( dataTypeOrTransport );
+                               inspect( dataTypeOrTransport );
+                               return false;
+                       } else if ( seekingTransport ) {
+                               return !( selected = dataTypeOrTransport );
+                       }
+               });
+               return selected;
+       }
+
+       return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+       var key, deep,
+               flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+       for ( key in src ) {
+               if ( src[ key ] !== undefined ) {
+                       ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+               }
+       }
+       if ( deep ) {
+               jQuery.extend( true, target, deep );
+       }
+
+       return target;
+}
+
+jQuery.fn.load = function( url, params, callback ) {
+       if ( typeof url !== "string" && _load ) {
+               return _load.apply( this, arguments );
+       }
+
+       var selector, type, response,
+               self = this,
+               off = url.indexOf(" ");
+
+       if ( off >= 0 ) {
+               selector = url.slice( off );
+               url = url.slice( 0, off );
+       }
+
+       // If it's a function
+       if ( jQuery.isFunction( params ) ) {
+
+               // We assume that it's the callback
+               callback = params;
+               params = undefined;
+
+       // Otherwise, build a param string
+       } else if ( params && typeof params === "object" ) {
+               type = "POST";
+       }
+
+       // If we have elements to modify, make the request
+       if ( self.length > 0 ) {
+               jQuery.ajax({
+                       url: url,
+
+                       // if "type" variable is undefined, then "GET" method will be used
+                       type: type,
+                       dataType: "html",
+                       data: params
+               }).done(function( responseText ) {
+
+                       // Save response for use in complete callback
+                       response = arguments;
+
+                       self.html( selector ?
+
+                               // If a selector was specified, locate the right elements in a dummy div
+                               // Exclude scripts to avoid IE 'Permission Denied' errors
+                               jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+                               // Otherwise use the full result
+                               responseText );
+
+               }).complete( callback && function( jqXHR, status ) {
+                       self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+               });
+       }
+
+       return this;
+};
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+       jQuery.fn[ type ] = function( fn ){
+               return this.on( type, fn );
+       };
+});
+
+jQuery.extend({
+
+       // Counter for holding the number of active queries
+       active: 0,
+
+       // Last-Modified header cache for next request
+       lastModified: {},
+       etag: {},
+
+       ajaxSettings: {
+               url: ajaxLocation,
+               type: "GET",
+               isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+               global: true,
+               processData: true,
+               async: true,
+               contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+               /*
+               timeout: 0,
+               data: null,
+               dataType: null,
+               username: null,
+               password: null,
+               cache: null,
+               throws: false,
+               traditional: false,
+               headers: {},
+               */
+
+               accepts: {
+                       "*": allTypes,
+                       text: "text/plain",
+                       html: "text/html",
+                       xml: "application/xml, text/xml",
+                       json: "application/json, text/javascript"
+               },
+
+               contents: {
+                       xml: /xml/,
+                       html: /html/,
+                       json: /json/
+               },
+
+               responseFields: {
+                       xml: "responseXML",
+                       text: "responseText",
+                       json: "responseJSON"
+               },
+
+               // Data converters
+               // Keys separate source (or catchall "*") and destination types with a single space
+               converters: {
+
+                       // Convert anything to text
+                       "* text": String,
+
+                       // Text to html (true = no transformation)
+                       "text html": true,
+
+                       // Evaluate text as a json expression
+                       "text json": jQuery.parseJSON,
+
+                       // Parse text as xml
+                       "text xml": jQuery.parseXML
+               },
+
+               // For options that shouldn't be deep extended:
+               // you can add your own custom options here if
+               // and when you create one that shouldn't be
+               // deep extended (see ajaxExtend)
+               flatOptions: {
+                       url: true,
+                       context: true
+               }
+       },
+
+       // Creates a full fledged settings object into target
+       // with both ajaxSettings and settings fields.
+       // If target is omitted, writes into ajaxSettings.
+       ajaxSetup: function( target, settings ) {
+               return settings ?
+
+                       // Building a settings object
+                       ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+                       // Extending ajaxSettings
+                       ajaxExtend( jQuery.ajaxSettings, target );
+       },
+
+       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+       ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+       // Main method
+       ajax: function( url, options ) {
+
+               // If url is an object, simulate pre-1.5 signature
+               if ( typeof url === "object" ) {
+                       options = url;
+                       url = undefined;
+               }
+
+               // Force options to be an object
+               options = options || {};
+
+               var transport,
+                       // URL without anti-cache param
+                       cacheURL,
+                       // Response headers
+                       responseHeadersString,
+                       responseHeaders,
+                       // timeout handle
+                       timeoutTimer,
+                       // Cross-domain detection vars
+                       parts,
+                       // To know if global events are to be dispatched
+                       fireGlobals,
+                       // Loop variable
+                       i,
+                       // Create the final options object
+                       s = jQuery.ajaxSetup( {}, options ),
+                       // Callbacks context
+                       callbackContext = s.context || s,
+                       // Context for global events is callbackContext if it is a DOM node or jQuery collection
+                       globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+                               jQuery( callbackContext ) :
+                               jQuery.event,
+                       // Deferreds
+                       deferred = jQuery.Deferred(),
+                       completeDeferred = jQuery.Callbacks("once memory"),
+                       // Status-dependent callbacks
+                       statusCode = s.statusCode || {},
+                       // Headers (they are sent all at once)
+                       requestHeaders = {},
+                       requestHeadersNames = {},
+                       // The jqXHR state
+                       state = 0,
+                       // Default abort message
+                       strAbort = "canceled",
+                       // Fake xhr
+                       jqXHR = {
+                               readyState: 0,
+
+                               // Builds headers hashtable if needed
+                               getResponseHeader: function( key ) {
+                                       var match;
+                                       if ( state === 2 ) {
+                                               if ( !responseHeaders ) {
+                                                       responseHeaders = {};
+                                                       while ( (match = rheaders.exec( responseHeadersString )) ) {
+                                                               responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                                       }
+                                               }
+                                               match = responseHeaders[ key.toLowerCase() ];
+                                       }
+                                       return match == null ? null : match;
+                               },
+
+                               // Raw string
+                               getAllResponseHeaders: function() {
+                                       return state === 2 ? responseHeadersString : null;
+                               },
+
+                               // Caches the header
+                               setRequestHeader: function( name, value ) {
+                                       var lname = name.toLowerCase();
+                                       if ( !state ) {
+                                               name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+                                               requestHeaders[ name ] = value;
+                                       }
+                                       return this;
+                               },
+
+                               // Overrides response content-type header
+                               overrideMimeType: function( type ) {
+                                       if ( !state ) {
+                                               s.mimeType = type;
+                                       }
+                                       return this;
+                               },
+
+                               // Status-dependent callbacks
+                               statusCode: function( map ) {
+                                       var code;
+                                       if ( map ) {
+                                               if ( state < 2 ) {
+                                                       for ( code in map ) {
+                                                               // Lazy-add the new callback in a way that preserves old ones
+                                                               statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+                                                       }
+                                               } else {
+                                                       // Execute the appropriate callbacks
+                                                       jqXHR.always( map[ jqXHR.status ] );
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // Cancel the request
+                               abort: function( statusText ) {
+                                       var finalText = statusText || strAbort;
+                                       if ( transport ) {
+                                               transport.abort( finalText );
+                                       }
+                                       done( 0, finalText );
+                                       return this;
+                               }
+                       };
+
+               // Attach deferreds
+               deferred.promise( jqXHR ).complete = completeDeferred.add;
+               jqXHR.success = jqXHR.done;
+               jqXHR.error = jqXHR.fail;
+
+               // Remove hash character (#7531: and string promotion)
+               // Add protocol if not provided (prefilters might expect it)
+               // Handle falsy url in the settings object (#10093: consistency with old signature)
+               // We also use the url parameter if available
+               s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
+                       .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+               // Alias method option to type as per ticket #12004
+               s.type = options.method || options.type || s.method || s.type;
+
+               // Extract dataTypes list
+               s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+               // A cross-domain request is in order when we have a protocol:host:port mismatch
+               if ( s.crossDomain == null ) {
+                       parts = rurl.exec( s.url.toLowerCase() );
+                       s.crossDomain = !!( parts &&
+                               ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+                                       ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+                                               ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+                       );
+               }
+
+               // Convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" ) {
+                       s.data = jQuery.param( s.data, s.traditional );
+               }
+
+               // Apply prefilters
+               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+               // If request was aborted inside a prefilter, stop there
+               if ( state === 2 ) {
+                       return jqXHR;
+               }
+
+               // We can fire global events as of now if asked to
+               fireGlobals = s.global;
+
+               // Watch for a new set of requests
+               if ( fireGlobals && jQuery.active++ === 0 ) {
+                       jQuery.event.trigger("ajaxStart");
+               }
+
+               // Uppercase the type
+               s.type = s.type.toUpperCase();
+
+               // Determine if request has content
+               s.hasContent = !rnoContent.test( s.type );
+
+               // Save the URL in case we're toying with the If-Modified-Since
+               // and/or If-None-Match header later on
+               cacheURL = s.url;
+
+               // More options handling for requests with no content
+               if ( !s.hasContent ) {
+
+                       // If data is available, append data to url
+                       if ( s.data ) {
+                               cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+                               // #9682: remove data so that it's not used in an eventual retry
+                               delete s.data;
+                       }
+
+                       // Add anti-cache in url if needed
+                       if ( s.cache === false ) {
+                               s.url = rts.test( cacheURL ) ?
+
+                                       // If there is already a '_' parameter, set its value
+                                       cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+                                       // Otherwise add one to the end
+                                       cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+                       }
+               }
+
+               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+               if ( s.ifModified ) {
+                       if ( jQuery.lastModified[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+                       }
+                       if ( jQuery.etag[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+                       }
+               }
+
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                       jqXHR.setRequestHeader( "Content-Type", s.contentType );
+               }
+
+               // Set the Accepts header for the server, depending on the dataType
+               jqXHR.setRequestHeader(
+                       "Accept",
+                       s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                               s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                               s.accepts[ "*" ]
+               );
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       jqXHR.setRequestHeader( i, s.headers[ i ] );
+               }
+
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+                       // Abort if not done already and return
+                       return jqXHR.abort();
+               }
+
+               // aborting is no longer a cancellation
+               strAbort = "abort";
+
+               // Install callbacks on deferreds
+               for ( i in { success: 1, error: 1, complete: 1 } ) {
+                       jqXHR[ i ]( s[ i ] );
+               }
+
+               // Get transport
+               transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+               // If no transport, we auto-abort
+               if ( !transport ) {
+                       done( -1, "No Transport" );
+               } else {
+                       jqXHR.readyState = 1;
+
+                       // Send global event
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                       }
+                       // Timeout
+                       if ( s.async && s.timeout > 0 ) {
+                               timeoutTimer = setTimeout(function() {
+                                       jqXHR.abort("timeout");
+                               }, s.timeout );
+                       }
+
+                       try {
+                               state = 1;
+                               transport.send( requestHeaders, done );
+                       } catch ( e ) {
+                               // Propagate exception as error if not done
+                               if ( state < 2 ) {
+                                       done( -1, e );
+                               // Simply rethrow otherwise
+                               } else {
+                                       throw e;
+                               }
+                       }
+               }
+
+               // Callback for when everything is done
+               function done( status, nativeStatusText, responses, headers ) {
+                       var isSuccess, success, error, response, modified,
+                               statusText = nativeStatusText;
+
+                       // Called once
+                       if ( state === 2 ) {
+                               return;
+                       }
+
+                       // State is "done" now
+                       state = 2;
+
+                       // Clear timeout if it exists
+                       if ( timeoutTimer ) {
+                               clearTimeout( timeoutTimer );
+                       }
+
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jqXHR object will be used)
+                       transport = undefined;
+
+                       // Cache response headers
+                       responseHeadersString = headers || "";
+
+                       // Set readyState
+                       jqXHR.readyState = status > 0 ? 4 : 0;
+
+                       // Determine if successful
+                       isSuccess = status >= 200 && status < 300 || status === 304;
+
+                       // Get response data
+                       if ( responses ) {
+                               response = ajaxHandleResponses( s, jqXHR, responses );
+                       }
+
+                       // Convert no matter what (that way responseXXX fields are always set)
+                       response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+                       // If successful, handle type chaining
+                       if ( isSuccess ) {
+
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       modified = jqXHR.getResponseHeader("Last-Modified");
+                                       if ( modified ) {
+                                               jQuery.lastModified[ cacheURL ] = modified;
+                                       }
+                                       modified = jqXHR.getResponseHeader("etag");
+                                       if ( modified ) {
+                                               jQuery.etag[ cacheURL ] = modified;
+                                       }
+                               }
+
+                               // if no content
+                               if ( status === 204 || s.type === "HEAD" ) {
+                                       statusText = "nocontent";
+
+                               // if not modified
+                               } else if ( status === 304 ) {
+                                       statusText = "notmodified";
+
+                               // If we have data, let's convert it
+                               } else {
+                                       statusText = response.state;
+                                       success = response.data;
+                                       error = response.error;
+                                       isSuccess = !error;
+                               }
+                       } else {
+                               // We extract error from statusText
+                               // then normalize statusText and status for non-aborts
+                               error = statusText;
+                               if ( status || !statusText ) {
+                                       statusText = "error";
+                                       if ( status < 0 ) {
+                                               status = 0;
+                                       }
+                               }
+                       }
+
+                       // Set data for the fake xhr object
+                       jqXHR.status = status;
+                       jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+                       // Success/Error
+                       if ( isSuccess ) {
+                               deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                       } else {
+                               deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                       }
+
+                       // Status-dependent callbacks
+                       jqXHR.statusCode( statusCode );
+                       statusCode = undefined;
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+                                       [ jqXHR, s, isSuccess ? success : error ] );
+                       }
+
+                       // Complete
+                       completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+                               // Handle the global AJAX counter
+                               if ( !( --jQuery.active ) ) {
+                                       jQuery.event.trigger("ajaxStop");
+                               }
+                       }
+               }
+
+               return jqXHR;
+       },
+
+       getJSON: function( url, data, callback ) {
+               return jQuery.get( url, data, callback, "json" );
+       },
+
+       getScript: function( url, callback ) {
+               return jQuery.get( url, undefined, callback, "script" );
+       }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+       jQuery[ method ] = function( url, data, callback, type ) {
+               // shift arguments if data argument was omitted
+               if ( jQuery.isFunction( data ) ) {
+                       type = type || callback;
+                       callback = data;
+                       data = undefined;
+               }
+
+               return jQuery.ajax({
+                       url: url,
+                       type: method,
+                       dataType: type,
+                       data: data,
+                       success: callback
+               });
+       };
+});
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+       var ct, type, finalDataType, firstDataType,
+               contents = s.contents,
+               dataTypes = s.dataTypes;
+
+       // Remove auto dataType and get content-type in the process
+       while( dataTypes[ 0 ] === "*" ) {
+               dataTypes.shift();
+               if ( ct === undefined ) {
+                       ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+               }
+       }
+
+       // Check if we're dealing with a known content-type
+       if ( ct ) {
+               for ( type in contents ) {
+                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                               dataTypes.unshift( type );
+                               break;
+                       }
+               }
+       }
+
+       // Check to see if we have a response for the expected dataType
+       if ( dataTypes[ 0 ] in responses ) {
+               finalDataType = dataTypes[ 0 ];
+       } else {
+               // Try convertible dataTypes
+               for ( type in responses ) {
+                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+                               finalDataType = type;
+                               break;
+                       }
+                       if ( !firstDataType ) {
+                               firstDataType = type;
+                       }
+               }
+               // Or just use first one
+               finalDataType = finalDataType || firstDataType;
+       }
+
+       // If we found a dataType
+       // We add the dataType to the list if needed
+       // and return the corresponding response
+       if ( finalDataType ) {
+               if ( finalDataType !== dataTypes[ 0 ] ) {
+                       dataTypes.unshift( finalDataType );
+               }
+               return responses[ finalDataType ];
+       }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+       var conv2, current, conv, tmp, prev,
+               converters = {},
+               // Work with a copy of dataTypes in case we need to modify it for conversion
+               dataTypes = s.dataTypes.slice();
+
+       // Create converters map with lowercased keys
+       if ( dataTypes[ 1 ] ) {
+               for ( conv in s.converters ) {
+                       converters[ conv.toLowerCase() ] = s.converters[ conv ];
+               }
+       }
+
+       current = dataTypes.shift();
+
+       // Convert to each sequential dataType
+       while ( current ) {
+
+               if ( s.responseFields[ current ] ) {
+                       jqXHR[ s.responseFields[ current ] ] = response;
+               }
+
+               // Apply the dataFilter if provided
+               if ( !prev && isSuccess && s.dataFilter ) {
+                       response = s.dataFilter( response, s.dataType );
+               }
+
+               prev = current;
+               current = dataTypes.shift();
+
+               if ( current ) {
+
+               // There's only work to do if current dataType is non-auto
+                       if ( current === "*" ) {
+
+                               current = prev;
+
+                       // Convert response if prev dataType is non-auto and differs from current
+                       } else if ( prev !== "*" && prev !== current ) {
+
+                               // Seek a direct converter
+                               conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+                               // If none found, seek a pair
+                               if ( !conv ) {
+                                       for ( conv2 in converters ) {
+
+                                               // If conv2 outputs current
+                                               tmp = conv2.split( " " );
+                                               if ( tmp[ 1 ] === current ) {
+
+                                                       // If prev can be converted to accepted input
+                                                       conv = converters[ prev + " " + tmp[ 0 ] ] ||
+                                                               converters[ "* " + tmp[ 0 ] ];
+                                                       if ( conv ) {
+                                                               // Condense equivalence converters
+                                                               if ( conv === true ) {
+                                                                       conv = converters[ conv2 ];
+
+                                                               // Otherwise, insert the intermediate dataType
+                                                               } else if ( converters[ conv2 ] !== true ) {
+                                                                       current = tmp[ 0 ];
+                                                                       dataTypes.unshift( tmp[ 1 ] );
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Apply converter (if not an equivalence)
+                               if ( conv !== true ) {
+
+                                       // Unless errors are allowed to bubble, catch and return them
+                                       if ( conv && s[ "throws" ] ) {
+                                               response = conv( response );
+                                       } else {
+                                               try {
+                                                       response = conv( response );
+                                               } catch ( e ) {
+                                                       return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return { state: "success", data: response };
+}
+// Install script dataType
+jQuery.ajaxSetup({
+       accepts: {
+               script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+       },
+       contents: {
+               script: /(?:java|ecma)script/
+       },
+       converters: {
+               "text script": function( text ) {
+                       jQuery.globalEval( text );
+                       return text;
+               }
+       }
+});
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+       if ( s.cache === undefined ) {
+               s.cache = false;
+       }
+       if ( s.crossDomain ) {
+               s.type = "GET";
+       }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+       // This transport only deals with cross domain requests
+       if ( s.crossDomain ) {
+               var script, callback;
+               return {
+                       send: function( _, complete ) {
+                               script = jQuery("<script>").prop({
+                                       async: true,
+                                       charset: s.scriptCharset,
+                                       src: s.url
+                               }).on(
+                                       "load error",
+                                       callback = function( evt ) {
+                                               script.remove();
+                                               callback = null;
+                                               if ( evt ) {
+                                                       complete( evt.type === "error" ? 404 : 200, evt.type );
+                                               }
+                                       }
+                               );
+                               document.head.appendChild( script[ 0 ] );
+                       },
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+});
+var oldCallbacks = [],
+       rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+       jsonp: "callback",
+       jsonpCallback: function() {
+               var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+               this[ callback ] = true;
+               return callback;
+       }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+       var callbackName, overwritten, responseContainer,
+               jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+                       "url" :
+                       typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+               );
+
+       // Handle iff the expected data type is "jsonp" or we have a parameter to set
+       if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+               // Get callback name, remembering preexisting value associated with it
+               callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+                       s.jsonpCallback() :
+                       s.jsonpCallback;
+
+               // Insert callback into url or form data
+               if ( jsonProp ) {
+                       s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+               } else if ( s.jsonp !== false ) {
+                       s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+               }
+
+               // Use data converter to retrieve json after script execution
+               s.converters["script json"] = function() {
+                       if ( !responseContainer ) {
+                               jQuery.error( callbackName + " was not called" );
+                       }
+                       return responseContainer[ 0 ];
+               };
+
+               // force json dataType
+               s.dataTypes[ 0 ] = "json";
+
+               // Install callback
+               overwritten = window[ callbackName ];
+               window[ callbackName ] = function() {
+                       responseContainer = arguments;
+               };
+
+               // Clean-up function (fires after converters)
+               jqXHR.always(function() {
+                       // Restore preexisting value
+                       window[ callbackName ] = overwritten;
+
+                       // Save back as free
+                       if ( s[ callbackName ] ) {
+                               // make sure that re-using the options doesn't screw things around
+                               s.jsonpCallback = originalSettings.jsonpCallback;
+
+                               // save the callback name for future use
+                               oldCallbacks.push( callbackName );
+                       }
+
+                       // Call if it was a function and we have a response
+                       if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+                               overwritten( responseContainer[ 0 ] );
+                       }
+
+                       responseContainer = overwritten = undefined;
+               });
+
+               // Delegate to script
+               return "script";
+       }
+});
+jQuery.ajaxSettings.xhr = function() {
+       try {
+               return new XMLHttpRequest();
+       } catch( e ) {}
+};
+
+var xhrSupported = jQuery.ajaxSettings.xhr(),
+       xhrSuccessStatus = {
+               // file protocol always yields status code 0, assume 200
+               0: 200,
+               // Support: IE9
+               // #1450: sometimes IE returns 1223 when it should be 204
+               1223: 204
+       },
+       // Support: IE9
+       // We need to keep track of outbound xhr and abort them manually
+       // because IE is not smart enough to do it all by itself
+       xhrId = 0,
+       xhrCallbacks = {};
+
+if ( window.ActiveXObject ) {
+       jQuery( window ).on( "unload", function() {
+               for( var key in xhrCallbacks ) {
+                       xhrCallbacks[ key ]();
+               }
+               xhrCallbacks = undefined;
+       });
+}
+
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+jQuery.support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport(function( options ) {
+       var callback;
+       // Cross domain only allowed if supported through XMLHttpRequest
+       if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
+               return {
+                       send: function( headers, complete ) {
+                               var i, id,
+                                       xhr = options.xhr();
+                               xhr.open( options.type, options.url, options.async, options.username, options.password );
+                               // Apply custom fields if provided
+                               if ( options.xhrFields ) {
+                                       for ( i in options.xhrFields ) {
+                                               xhr[ i ] = options.xhrFields[ i ];
+                                       }
+                               }
+                               // Override mime type if needed
+                               if ( options.mimeType && xhr.overrideMimeType ) {
+                                       xhr.overrideMimeType( options.mimeType );
+                               }
+                               // X-Requested-With header
+                               // For cross-domain requests, seeing as conditions for a preflight are
+                               // akin to a jigsaw puzzle, we simply never set it to be sure.
+                               // (it can always be set on a per-request basis or even using ajaxSetup)
+                               // For same-domain requests, won't change header if already provided.
+                               if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+                                       headers["X-Requested-With"] = "XMLHttpRequest";
+                               }
+                               // Set headers
+                               for ( i in headers ) {
+                                       xhr.setRequestHeader( i, headers[ i ] );
+                               }
+                               // Callback
+                               callback = function( type ) {
+                                       return function() {
+                                               if ( callback ) {
+                                                       delete xhrCallbacks[ id ];
+                                                       callback = xhr.onload = xhr.onerror = null;
+                                                       if ( type === "abort" ) {
+                                                               xhr.abort();
+                                                       } else if ( type === "error" ) {
+                                                               complete(
+                                                                       // file protocol always yields status 0, assume 404
+                                                                       xhr.status || 404,
+                                                                       xhr.statusText
+                                                               );
+                                                       } else {
+                                                               complete(
+                                                                       xhrSuccessStatus[ xhr.status ] || xhr.status,
+                                                                       xhr.statusText,
+                                                                       // Support: IE9
+                                                                       // #11426: When requesting binary data, IE9 will throw an exception
+                                                                       // on any attempt to access responseText
+                                                                       typeof xhr.responseText === "string" ? {
+                                                                               text: xhr.responseText
+                                                                       } : undefined,
+                                                                       xhr.getAllResponseHeaders()
+                                                               );
+                                                       }
+                                               }
+                                       };
+                               };
+                               // Listen to events
+                               xhr.onload = callback();
+                               xhr.onerror = callback("error");
+                               // Create the abort callback
+                               callback = xhrCallbacks[( id = xhrId++ )] = callback("abort");
+                               // Do send the request
+                               // This may raise an exception which is actually
+                               // handled in jQuery.ajax (so no try/catch here)
+                               xhr.send( options.hasContent && options.data || null );
+                       },
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+});
+var fxNow, timerId,
+       rfxtypes = /^(?:toggle|show|hide)$/,
+       rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+       rrun = /queueHooks$/,
+       animationPrefilters = [ defaultPrefilter ],
+       tweeners = {
+               "*": [function( prop, value ) {
+                       var tween = this.createTween( prop, value ),
+                               target = tween.cur(),
+                               parts = rfxnum.exec( value ),
+                               unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+                               // Starting value computation is required for potential unit mismatches
+                               start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+                                       rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+                               scale = 1,
+                               maxIterations = 20;
+
+                       if ( start && start[ 3 ] !== unit ) {
+                               // Trust units reported by jQuery.css
+                               unit = unit || start[ 3 ];
+
+                               // Make sure we update the tween properties later on
+                               parts = parts || [];
+
+                               // Iteratively approximate from a nonzero starting point
+                               start = +target || 1;
+
+                               do {
+                                       // If previous iteration zeroed out, double until we get *something*
+                                       // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+                                       scale = scale || ".5";
+
+                                       // Adjust and apply
+                                       start = start / scale;
+                                       jQuery.style( tween.elem, prop, start + unit );
+
+                               // Update scale, tolerating zero or NaN from tween.cur()
+                               // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+                               } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+                       }
+
+                       // Update tween properties
+                       if ( parts ) {
+                               start = tween.start = +start || +target || 0;
+                               tween.unit = unit;
+                               // If a +=/-= token was provided, we're doing a relative animation
+                               tween.end = parts[ 1 ] ?
+                                       start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+                                       +parts[ 2 ];
+                       }
+
+                       return tween;
+               }]
+       };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+       setTimeout(function() {
+               fxNow = undefined;
+       });
+       return ( fxNow = jQuery.now() );
+}
+
+function createTween( value, prop, animation ) {
+       var tween,
+               collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+               index = 0,
+               length = collection.length;
+       for ( ; index < length; index++ ) {
+               if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+                       // we're done with this property
+                       return tween;
+               }
+       }
+}
+
+function Animation( elem, properties, options ) {
+       var result,
+               stopped,
+               index = 0,
+               length = animationPrefilters.length,
+               deferred = jQuery.Deferred().always( function() {
+                       // don't match elem in the :animated selector
+                       delete tick.elem;
+               }),
+               tick = function() {
+                       if ( stopped ) {
+                               return false;
+                       }
+                       var currentTime = fxNow || createFxNow(),
+                               remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+                               // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+                               temp = remaining / animation.duration || 0,
+                               percent = 1 - temp,
+                               index = 0,
+                               length = animation.tweens.length;
+
+                       for ( ; index < length ; index++ ) {
+                               animation.tweens[ index ].run( percent );
+                       }
+
+                       deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+                       if ( percent < 1 && length ) {
+                               return remaining;
+                       } else {
+                               deferred.resolveWith( elem, [ animation ] );
+                               return false;
+                       }
+               },
+               animation = deferred.promise({
+                       elem: elem,
+                       props: jQuery.extend( {}, properties ),
+                       opts: jQuery.extend( true, { specialEasing: {} }, options ),
+                       originalProperties: properties,
+                       originalOptions: options,
+                       startTime: fxNow || createFxNow(),
+                       duration: options.duration,
+                       tweens: [],
+                       createTween: function( prop, end ) {
+                               var tween = jQuery.Tween( elem, animation.opts, prop, end,
+                                               animation.opts.specialEasing[ prop ] || animation.opts.easing );
+                               animation.tweens.push( tween );
+                               return tween;
+                       },
+                       stop: function( gotoEnd ) {
+                               var index = 0,
+                                       // if we are going to the end, we want to run all the tweens
+                                       // otherwise we skip this part
+                                       length = gotoEnd ? animation.tweens.length : 0;
+                               if ( stopped ) {
+                                       return this;
+                               }
+                               stopped = true;
+                               for ( ; index < length ; index++ ) {
+                                       animation.tweens[ index ].run( 1 );
+                               }
+
+                               // resolve when we played the last frame
+                               // otherwise, reject
+                               if ( gotoEnd ) {
+                                       deferred.resolveWith( elem, [ animation, gotoEnd ] );
+                               } else {
+                                       deferred.rejectWith( elem, [ animation, gotoEnd ] );
+                               }
+                               return this;
+                       }
+               }),
+               props = animation.props;
+
+       propFilter( props, animation.opts.specialEasing );
+
+       for ( ; index < length ; index++ ) {
+               result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+               if ( result ) {
+                       return result;
+               }
+       }
+
+       jQuery.map( props, createTween, animation );
+
+       if ( jQuery.isFunction( animation.opts.start ) ) {
+               animation.opts.start.call( elem, animation );
+       }
+
+       jQuery.fx.timer(
+               jQuery.extend( tick, {
+                       elem: elem,
+                       anim: animation,
+                       queue: animation.opts.queue
+               })
+       );
+
+       // attach callbacks from options
+       return animation.progress( animation.opts.progress )
+               .done( animation.opts.done, animation.opts.complete )
+               .fail( animation.opts.fail )
+               .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+       var index, name, easing, value, hooks;
+
+       // camelCase, specialEasing and expand cssHook pass
+       for ( index in props ) {
+               name = jQuery.camelCase( index );
+               easing = specialEasing[ name ];
+               value = props[ index ];
+               if ( jQuery.isArray( value ) ) {
+                       easing = value[ 1 ];
+                       value = props[ index ] = value[ 0 ];
+               }
+
+               if ( index !== name ) {
+                       props[ name ] = value;
+                       delete props[ index ];
+               }
+
+               hooks = jQuery.cssHooks[ name ];
+               if ( hooks && "expand" in hooks ) {
+                       value = hooks.expand( value );
+                       delete props[ name ];
+
+                       // not quite $.extend, this wont overwrite keys already present.
+                       // also - reusing 'index' from above because we have the correct "name"
+                       for ( index in value ) {
+                               if ( !( index in props ) ) {
+                                       props[ index ] = value[ index ];
+                                       specialEasing[ index ] = easing;
+                               }
+                       }
+               } else {
+                       specialEasing[ name ] = easing;
+               }
+       }
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+       tweener: function( props, callback ) {
+               if ( jQuery.isFunction( props ) ) {
+                       callback = props;
+                       props = [ "*" ];
+               } else {
+                       props = props.split(" ");
+               }
+
+               var prop,
+                       index = 0,
+                       length = props.length;
+
+               for ( ; index < length ; index++ ) {
+                       prop = props[ index ];
+                       tweeners[ prop ] = tweeners[ prop ] || [];
+                       tweeners[ prop ].unshift( callback );
+               }
+       },
+
+       prefilter: function( callback, prepend ) {
+               if ( prepend ) {
+                       animationPrefilters.unshift( callback );
+               } else {
+                       animationPrefilters.push( callback );
+               }
+       }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+       /* jshint validthis: true */
+       var prop, value, toggle, tween, hooks, oldfire,
+               anim = this,
+               orig = {},
+               style = elem.style,
+               hidden = elem.nodeType && isHidden( elem ),
+               dataShow = data_priv.get( elem, "fxshow" );
+
+       // handle queue: false promises
+       if ( !opts.queue ) {
+               hooks = jQuery._queueHooks( elem, "fx" );
+               if ( hooks.unqueued == null ) {
+                       hooks.unqueued = 0;
+                       oldfire = hooks.empty.fire;
+                       hooks.empty.fire = function() {
+                               if ( !hooks.unqueued ) {
+                                       oldfire();
+                               }
+                       };
+               }
+               hooks.unqueued++;
+
+               anim.always(function() {
+                       // doing this makes sure that the complete handler will be called
+                       // before this completes
+                       anim.always(function() {
+                               hooks.unqueued--;
+                               if ( !jQuery.queue( elem, "fx" ).length ) {
+                                       hooks.empty.fire();
+                               }
+                       });
+               });
+       }
+
+       // height/width overflow pass
+       if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+               // Make sure that nothing sneaks out
+               // Record all 3 overflow attributes because IE9-10 do not
+               // change the overflow attribute when overflowX and
+               // overflowY are set to the same value
+               opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+               // Set display property to inline-block for height/width
+               // animations on inline elements that are having width/height animated
+               if ( jQuery.css( elem, "display" ) === "inline" &&
+                               jQuery.css( elem, "float" ) === "none" ) {
+
+                       style.display = "inline-block";
+               }
+       }
+
+       if ( opts.overflow ) {
+               style.overflow = "hidden";
+               anim.always(function() {
+                       style.overflow = opts.overflow[ 0 ];
+                       style.overflowX = opts.overflow[ 1 ];
+                       style.overflowY = opts.overflow[ 2 ];
+               });
+       }
+
+
+       // show/hide pass
+       for ( prop in props ) {
+               value = props[ prop ];
+               if ( rfxtypes.exec( value ) ) {
+                       delete props[ prop ];
+                       toggle = toggle || value === "toggle";
+                       if ( value === ( hidden ? "hide" : "show" ) ) {
+
+                               // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+                               if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+                                       hidden = true;
+                               } else {
+                                       continue;
+                               }
+                       }
+                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+               }
+       }
+
+       if ( !jQuery.isEmptyObject( orig ) ) {
+               if ( dataShow ) {
+                       if ( "hidden" in dataShow ) {
+                               hidden = dataShow.hidden;
+                       }
+               } else {
+                       dataShow = data_priv.access( elem, "fxshow", {} );
+               }
+
+               // store state if its toggle - enables .stop().toggle() to "reverse"
+               if ( toggle ) {
+                       dataShow.hidden = !hidden;
+               }
+               if ( hidden ) {
+                       jQuery( elem ).show();
+               } else {
+                       anim.done(function() {
+                               jQuery( elem ).hide();
+                       });
+               }
+               anim.done(function() {
+                       var prop;
+
+                       data_priv.remove( elem, "fxshow" );
+                       for ( prop in orig ) {
+                               jQuery.style( elem, prop, orig[ prop ] );
+                       }
+               });
+               for ( prop in orig ) {
+                       tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+                       if ( !( prop in dataShow ) ) {
+                               dataShow[ prop ] = tween.start;
+                               if ( hidden ) {
+                                       tween.end = tween.start;
+                                       tween.start = prop === "width" || prop === "height" ? 1 : 0;
+                               }
+                       }
+               }
+       }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+       return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+       constructor: Tween,
+       init: function( elem, options, prop, end, easing, unit ) {
+               this.elem = elem;
+               this.prop = prop;
+               this.easing = easing || "swing";
+               this.options = options;
+               this.start = this.now = this.cur();
+               this.end = end;
+               this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+       },
+       cur: function() {
+               var hooks = Tween.propHooks[ this.prop ];
+
+               return hooks && hooks.get ?
+                       hooks.get( this ) :
+                       Tween.propHooks._default.get( this );
+       },
+       run: function( percent ) {
+               var eased,
+                       hooks = Tween.propHooks[ this.prop ];
+
+               if ( this.options.duration ) {
+                       this.pos = eased = jQuery.easing[ this.easing ](
+                               percent, this.options.duration * percent, 0, 1, this.options.duration
+                       );
+               } else {
+                       this.pos = eased = percent;
+               }
+               this.now = ( this.end - this.start ) * eased + this.start;
+
+               if ( this.options.step ) {
+                       this.options.step.call( this.elem, this.now, this );
+               }
+
+               if ( hooks && hooks.set ) {
+                       hooks.set( this );
+               } else {
+                       Tween.propHooks._default.set( this );
+               }
+               return this;
+       }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+       _default: {
+               get: function( tween ) {
+                       var result;
+
+                       if ( tween.elem[ tween.prop ] != null &&
+                               (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+                               return tween.elem[ tween.prop ];
+                       }
+
+                       // passing an empty string as a 3rd parameter to .css will automatically
+                       // attempt a parseFloat and fallback to a string if the parse fails
+                       // so, simple values such as "10px" are parsed to Float.
+                       // complex values such as "rotate(1rad)" are returned as is.
+                       result = jQuery.css( tween.elem, tween.prop, "" );
+                       // Empty strings, null, undefined and "auto" are converted to 0.
+                       return !result || result === "auto" ? 0 : result;
+               },
+               set: function( tween ) {
+                       // use step hook for back compat - use cssHook if its there - use .style if its
+                       // available and use plain properties where available
+                       if ( jQuery.fx.step[ tween.prop ] ) {
+                               jQuery.fx.step[ tween.prop ]( tween );
+                       } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+                               jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+                       } else {
+                               tween.elem[ tween.prop ] = tween.now;
+                       }
+               }
+       }
+};
+
+// Support: IE9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+       set: function( tween ) {
+               if ( tween.elem.nodeType && tween.elem.parentNode ) {
+                       tween.elem[ tween.prop ] = tween.now;
+               }
+       }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+       var cssFn = jQuery.fn[ name ];
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return speed == null || typeof speed === "boolean" ?
+                       cssFn.apply( this, arguments ) :
+                       this.animate( genFx( name, true ), speed, easing, callback );
+       };
+});
+
+jQuery.fn.extend({
+       fadeTo: function( speed, to, easing, callback ) {
+
+               // show any hidden elements after setting opacity to 0
+               return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+                       // animate to the value specified
+                       .end().animate({ opacity: to }, speed, easing, callback );
+       },
+       animate: function( prop, speed, easing, callback ) {
+               var empty = jQuery.isEmptyObject( prop ),
+                       optall = jQuery.speed( speed, easing, callback ),
+                       doAnimation = function() {
+                               // Operate on a copy of prop so per-property easing won't be lost
+                               var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+                               // Empty animations, or finishing resolves immediately
+                               if ( empty || data_priv.get( this, "finish" ) ) {
+                                       anim.stop( true );
+                               }
+                       };
+                       doAnimation.finish = doAnimation;
+
+               return empty || optall.queue === false ?
+                       this.each( doAnimation ) :
+                       this.queue( optall.queue, doAnimation );
+       },
+       stop: function( type, clearQueue, gotoEnd ) {
+               var stopQueue = function( hooks ) {
+                       var stop = hooks.stop;
+                       delete hooks.stop;
+                       stop( gotoEnd );
+               };
+
+               if ( typeof type !== "string" ) {
+                       gotoEnd = clearQueue;
+                       clearQueue = type;
+                       type = undefined;
+               }
+               if ( clearQueue && type !== false ) {
+                       this.queue( type || "fx", [] );
+               }
+
+               return this.each(function() {
+                       var dequeue = true,
+                               index = type != null && type + "queueHooks",
+                               timers = jQuery.timers,
+                               data = data_priv.get( this );
+
+                       if ( index ) {
+                               if ( data[ index ] && data[ index ].stop ) {
+                                       stopQueue( data[ index ] );
+                               }
+                       } else {
+                               for ( index in data ) {
+                                       if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+                                               stopQueue( data[ index ] );
+                                       }
+                               }
+                       }
+
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+                                       timers[ index ].anim.stop( gotoEnd );
+                                       dequeue = false;
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // start the next in the queue if the last step wasn't forced
+                       // timers currently will call their complete callbacks, which will dequeue
+                       // but only if they were gotoEnd
+                       if ( dequeue || !gotoEnd ) {
+                               jQuery.dequeue( this, type );
+                       }
+               });
+       },
+       finish: function( type ) {
+               if ( type !== false ) {
+                       type = type || "fx";
+               }
+               return this.each(function() {
+                       var index,
+                               data = data_priv.get( this ),
+                               queue = data[ type + "queue" ],
+                               hooks = data[ type + "queueHooks" ],
+                               timers = jQuery.timers,
+                               length = queue ? queue.length : 0;
+
+                       // enable finishing flag on private data
+                       data.finish = true;
+
+                       // empty the queue first
+                       jQuery.queue( this, type, [] );
+
+                       if ( hooks && hooks.stop ) {
+                               hooks.stop.call( this, true );
+                       }
+
+                       // look for any active animations, and finish them
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+                                       timers[ index ].anim.stop( true );
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // look for any animations in the old queue and finish them
+                       for ( index = 0; index < length; index++ ) {
+                               if ( queue[ index ] && queue[ index ].finish ) {
+                                       queue[ index ].finish.call( this );
+                               }
+                       }
+
+                       // turn off finishing flag
+                       delete data.finish;
+               });
+       }
+});
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+       var which,
+               attrs = { height: type },
+               i = 0;
+
+       // if we include width, step value is 1 to do all cssExpand values,
+       // if we don't include width, step value is 2 to skip over Left and Right
+       includeWidth = includeWidth? 1 : 0;
+       for( ; i < 4 ; i += 2 - includeWidth ) {
+               which = cssExpand[ i ];
+               attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+       }
+
+       if ( includeWidth ) {
+               attrs.opacity = attrs.width = type;
+       }
+
+       return attrs;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+       slideDown: genFx("show"),
+       slideUp: genFx("hide"),
+       slideToggle: genFx("toggle"),
+       fadeIn: { opacity: "show" },
+       fadeOut: { opacity: "hide" },
+       fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return this.animate( props, speed, easing, callback );
+       };
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+       var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+               complete: fn || !fn && easing ||
+                       jQuery.isFunction( speed ) && speed,
+               duration: speed,
+               easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+       };
+
+       opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+               opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+       // normalize opt.queue - true/undefined/null -> "fx"
+       if ( opt.queue == null || opt.queue === true ) {
+               opt.queue = "fx";
+       }
+
+       // Queueing
+       opt.old = opt.complete;
+
+       opt.complete = function() {
+               if ( jQuery.isFunction( opt.old ) ) {
+                       opt.old.call( this );
+               }
+
+               if ( opt.queue ) {
+                       jQuery.dequeue( this, opt.queue );
+               }
+       };
+
+       return opt;
+};
+
+jQuery.easing = {
+       linear: function( p ) {
+               return p;
+       },
+       swing: function( p ) {
+               return 0.5 - Math.cos( p*Math.PI ) / 2;
+       }
+};
+
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+       var timer,
+               timers = jQuery.timers,
+               i = 0;
+
+       fxNow = jQuery.now();
+
+       for ( ; i < timers.length; i++ ) {
+               timer = timers[ i ];
+               // Checks the timer has not already been removed
+               if ( !timer() && timers[ i ] === timer ) {
+                       timers.splice( i--, 1 );
+               }
+       }
+
+       if ( !timers.length ) {
+               jQuery.fx.stop();
+       }
+       fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+       if ( timer() && jQuery.timers.push( timer ) ) {
+               jQuery.fx.start();
+       }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+       if ( !timerId ) {
+               timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+       }
+};
+
+jQuery.fx.stop = function() {
+       clearInterval( timerId );
+       timerId = null;
+};
+
+jQuery.fx.speeds = {
+       slow: 600,
+       fast: 200,
+       // Default speed
+       _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+       jQuery.expr.filters.animated = function( elem ) {
+               return jQuery.grep(jQuery.timers, function( fn ) {
+                       return elem === fn.elem;
+               }).length;
+       };
+}
+jQuery.fn.offset = function( options ) {
+       if ( arguments.length ) {
+               return options === undefined ?
+                       this :
+                       this.each(function( i ) {
+                               jQuery.offset.setOffset( this, options, i );
+                       });
+       }
+
+       var docElem, win,
+               elem = this[ 0 ],
+               box = { top: 0, left: 0 },
+               doc = elem && elem.ownerDocument;
+
+       if ( !doc ) {
+               return;
+       }
+
+       docElem = doc.documentElement;
+
+       // Make sure it's not a disconnected DOM node
+       if ( !jQuery.contains( docElem, elem ) ) {
+               return box;
+       }
+
+       // If we don't have gBCR, just use 0,0 rather than error
+       // BlackBerry 5, iOS 3 (original iPhone)
+       if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
+               box = elem.getBoundingClientRect();
+       }
+       win = getWindow( doc );
+       return {
+               top: box.top + win.pageYOffset - docElem.clientTop,
+               left: box.left + win.pageXOffset - docElem.clientLeft
+       };
+};
+
+jQuery.offset = {
+
+       setOffset: function( elem, options, i ) {
+               var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+                       position = jQuery.css( elem, "position" ),
+                       curElem = jQuery( elem ),
+                       props = {};
+
+               // Set position first, in-case top/left are set even on static elem
+               if ( position === "static" ) {
+                       elem.style.position = "relative";
+               }
+
+               curOffset = curElem.offset();
+               curCSSTop = jQuery.css( elem, "top" );
+               curCSSLeft = jQuery.css( elem, "left" );
+               calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
+
+               // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+               if ( calculatePosition ) {
+                       curPosition = curElem.position();
+                       curTop = curPosition.top;
+                       curLeft = curPosition.left;
+
+               } else {
+                       curTop = parseFloat( curCSSTop ) || 0;
+                       curLeft = parseFloat( curCSSLeft ) || 0;
+               }
+
+               if ( jQuery.isFunction( options ) ) {
+                       options = options.call( elem, i, curOffset );
+               }
+
+               if ( options.top != null ) {
+                       props.top = ( options.top - curOffset.top ) + curTop;
+               }
+               if ( options.left != null ) {
+                       props.left = ( options.left - curOffset.left ) + curLeft;
+               }
+
+               if ( "using" in options ) {
+                       options.using.call( elem, props );
+
+               } else {
+                       curElem.css( props );
+               }
+       }
+};
+
+
+jQuery.fn.extend({
+
+       position: function() {
+               if ( !this[ 0 ] ) {
+                       return;
+               }
+
+               var offsetParent, offset,
+                       elem = this[ 0 ],
+                       parentOffset = { top: 0, left: 0 };
+
+               // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+               if ( jQuery.css( elem, "position" ) === "fixed" ) {
+                       // We assume that getBoundingClientRect is available when computed position is fixed
+                       offset = elem.getBoundingClientRect();
+
+               } else {
+                       // Get *real* offsetParent
+                       offsetParent = this.offsetParent();
+
+                       // Get correct offsets
+                       offset = this.offset();
+                       if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+                               parentOffset = offsetParent.offset();
+                       }
+
+                       // Add offsetParent borders
+                       parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+                       parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+               }
+
+               // Subtract parent offsets and element margins
+               return {
+                       top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+                       left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+               };
+       },
+
+       offsetParent: function() {
+               return this.map(function() {
+                       var offsetParent = this.offsetParent || docElem;
+
+                       while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
+                               offsetParent = offsetParent.offsetParent;
+                       }
+
+                       return offsetParent || docElem;
+               });
+       }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+       var top = "pageYOffset" === prop;
+
+       jQuery.fn[ method ] = function( val ) {
+               return jQuery.access( this, function( elem, method, val ) {
+                       var win = getWindow( elem );
+
+                       if ( val === undefined ) {
+                               return win ? win[ prop ] : elem[ method ];
+                       }
+
+                       if ( win ) {
+                               win.scrollTo(
+                                       !top ? val : window.pageXOffset,
+                                       top ? val : window.pageYOffset
+                               );
+
+                       } else {
+                               elem[ method ] = val;
+                       }
+               }, method, val, arguments.length, null );
+       };
+});
+
+function getWindow( elem ) {
+       return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
+}
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+       jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+               // margin is only for outerHeight, outerWidth
+               jQuery.fn[ funcName ] = function( margin, value ) {
+                       var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+                               extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+                       return jQuery.access( this, function( elem, type, value ) {
+                               var doc;
+
+                               if ( jQuery.isWindow( elem ) ) {
+                                       // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+                                       // isn't a whole lot we can do. See pull request at this URL for discussion:
+                                       // https://github.com/jquery/jquery/pull/764
+                                       return elem.document.documentElement[ "client" + name ];
+                               }
+
+                               // Get document width or height
+                               if ( elem.nodeType === 9 ) {
+                                       doc = elem.documentElement;
+
+                                       // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+                                       // whichever is greatest
+                                       return Math.max(
+                                               elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+                                               elem.body[ "offset" + name ], doc[ "offset" + name ],
+                                               doc[ "client" + name ]
+                                       );
+                               }
+
+                               return value === undefined ?
+                                       // Get width or height on the element, requesting but not forcing parseFloat
+                                       jQuery.css( elem, type, extra ) :
+
+                                       // Set width or height on the element
+                                       jQuery.style( elem, type, value, extra );
+                       }, type, chainable ? margin : undefined, chainable, null );
+               };
+       });
+});
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+       return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// })();
+if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+       // Expose jQuery as module.exports in loaders that implement the Node
+       // module pattern (including browserify). Do not create the global, since
+       // the user will be storing it themselves locally, and globals are frowned
+       // upon in the Node module world.
+       module.exports = jQuery;
+} else {
+       // Register as a named AMD module, since jQuery can be concatenated with other
+       // files that may use define, but not via a proper concatenation script that
+       // understands anonymous AMD modules. A named AMD is safest and most robust
+       // way to register. Lowercase jquery is used because AMD module names are
+       // derived from file names, and jQuery is normally delivered in a lowercase
+       // file name. Do this after creating the global so that if an AMD module wants
+       // to call noConflict to hide this version of jQuery, it will work.
+       if ( typeof define === "function" && define.amd ) {
+               define( "jquery", [], function () { return jQuery; } );
+       }
+}
+
+// If there is a window object, that at least has a document property,
+// define jQuery and $ identifiers
+if ( typeof window === "object" && typeof window.document === "object" ) {
+       window.jQuery = window.$ = jQuery;
+}
+
+})( window );
diff --git a/js/libs/jquery/jquery.localscroll.js b/js/libs/jquery/jquery.localscroll.js
new file mode 100644 (file)
index 0000000..0a9ba8c
--- /dev/null
@@ -0,0 +1,133 @@
+/**
+ * jQuery.LocalScroll
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 3/11/2009
+ *
+ * @projectDescription Animated scrolling navigation, using anchors.
+ * http://flesler.blogspot.com/2007/10/jquerylocalscroll-10.html
+ * @author Ariel Flesler
+ * @version 1.2.7
+ *
+ * @id jQuery.fn.localScroll
+ * @param {Object} settings Hash of settings, it is passed in to jQuery.ScrollTo, none is required.
+ * @return {jQuery} Returns the same jQuery object, for chaining.
+ *
+ * @example $('ul.links').localScroll();
+ *
+ * @example $('ul.links').localScroll({ filter:'.animated', duration:400, axis:'x' });
+ *
+ * @example $.localScroll({ target:'#pane', axis:'xy', queue:true, event:'mouseover' });
+ *
+ * Notes:
+ *     - The plugin requires jQuery.ScrollTo.
+ *     - The hash of settings, is passed to jQuery.ScrollTo, so the settings are valid for that plugin as well.
+ *     - jQuery.localScroll can be used if the desired links, are all over the document, it accepts the same settings.
+ *  - If the setting 'lazy' is set to true, then the binding will still work for later added anchors.
+  *    - If onBefore returns false, the event is ignored.
+ **/
+;(function( $ ){
+       var URI = location.href.replace(/#.*/,''); // local url without hash
+
+       var $localScroll = $.localScroll = function( settings ){
+               $('body').localScroll( settings );
+       };
+
+       // Many of these defaults, belong to jQuery.ScrollTo, check it's demo for an example of each option.
+       // @see http://flesler.demos.com/jquery/scrollTo/
+       // The defaults are public and can be overriden.
+       $localScroll.defaults = {
+               duration:1000, // How long to animate.
+               axis:'y', // Which of top and left should be modified.
+               event:'click', // On which event to react.
+               stop:true, // Avoid queuing animations 
+               target: window, // What to scroll (selector or element). The whole window by default.
+               reset: true // Used by $.localScroll.hash. If true, elements' scroll is resetted before actual scrolling
+               /*
+               lock:false, // ignore events if already animating
+               lazy:false, // if true, links can be added later, and will still work.
+               filter:null, // filter some anchors out of the matched elements.
+               hash: false // if true, the hash of the selected link, will appear on the address bar.
+               */
+       };
+
+       // If the URL contains a hash, it will scroll to the pointed element
+       $localScroll.hash = function( settings ){
+               if( location.hash ){
+                       settings = $.extend( {}, $localScroll.defaults, settings );
+                       settings.hash = false; // can't be true
+                       
+                       if( settings.reset ){
+                               var d = settings.duration;
+                               delete settings.duration;
+                               $(settings.target).scrollTo( 0, settings );
+                               settings.duration = d;
+                       }
+                       scroll( 0, location, settings );
+               }
+       };
+
+       $.fn.localScroll = function( settings ){
+               settings = $.extend( {}, $localScroll.defaults, settings );
+
+               return settings.lazy ?
+                       // use event delegation, more links can be added later.         
+                       this.bind( settings.event, function( e ){
+                               // Could use closest(), but that would leave out jQuery -1.3.x
+                               var a = $([e.target, e.target.parentNode]).filter(filter)[0];
+                               // if a valid link was clicked
+                               if( a )
+                                       scroll( e, a, settings ); // do scroll.
+                       }) :
+                       // bind concretely, to each matching link
+                       this.find('a,area')
+                               .filter( filter ).bind( settings.event, function(e){
+                                       scroll( e, this, settings );
+                               }).end()
+                       .end();
+
+               function filter(){// is this a link that points to an anchor and passes a possible filter ? href is checked to avoid a bug in FF.
+                       return !!this.href && !!this.hash && this.href.replace(this.hash,'') == URI && (!settings.filter || $(this).is( settings.filter ));
+               };
+       };
+
+       function scroll( e, link, settings ){
+               var id = link.hash.slice(1),
+                       elem = document.getElementById(id) || document.getElementsByName(id)[0];
+
+               if ( !elem )
+                       return;
+
+               if( e )
+                       e.preventDefault();
+
+               var $target = $( settings.target );
+
+               if( settings.lock && $target.is(':animated') ||
+                       settings.onBefore && settings.onBefore.call(settings, e, elem, $target) === false ) 
+                       return;
+
+               if( settings.stop )
+                       $target.stop(true); // remove all its animations
+
+               if( settings.hash ){
+                       var attr = elem.id == id ? 'id' : 'name',
+                               $a = $('<a> </a>').attr(attr, id).css({
+                                       position:'absolute',
+                                       top: $(window).scrollTop(),
+                                       left: $(window).scrollLeft()
+                               });
+
+                       elem[attr] = '';
+                       $('body').prepend($a);
+                       location = link.hash;
+                       $a.remove();
+                       elem[attr] = id;
+               }
+                       
+               $target
+                       .scrollTo( elem, settings ) // do scroll
+                       .trigger('notify.serialScroll',[elem]); // notify serialScroll about this change
+       };
+
+})( jQuery );
\ No newline at end of file
diff --git a/js/libs/jquery/jquery.migrate.js b/js/libs/jquery/jquery.migrate.js
new file mode 100644 (file)
index 0000000..25b6c81
--- /dev/null
@@ -0,0 +1,521 @@
+/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+// jQuery.migrateMute = false;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+       window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+       jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+       warnedAbout = {};
+       jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+       var console = window.console;
+       if ( !warnedAbout[ msg ] ) {
+               warnedAbout[ msg ] = true;
+               jQuery.migrateWarnings.push( msg );
+               if ( console && console.warn && !jQuery.migrateMute ) {
+                       console.warn( "JQMIGRATE: " + msg );
+                       if ( jQuery.migrateTrace && console.trace ) {
+                               console.trace();
+                       }
+               }
+       }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+       if ( Object.defineProperty ) {
+               // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+               // allow property to be overwritten in case some other plugin wants it
+               try {
+                       Object.defineProperty( obj, prop, {
+                               configurable: true,
+                               enumerable: true,
+                               get: function() {
+                                       migrateWarn( msg );
+                                       return value;
+                               },
+                               set: function( newValue ) {
+                                       migrateWarn( msg );
+                                       value = newValue;
+                               }
+                       });
+                       return;
+               } catch( err ) {
+                       // IE8 is a dope about Object.defineProperty, can't warn there
+               }
+       }
+
+       // Non-ES5 (or broken) browser; just set the property
+       jQuery._definePropertyBroken = true;
+       obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+       // jQuery has never supported or tested Quirks Mode
+       migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+       oldAttr = jQuery.attr,
+       valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+               function() { return null; },
+       valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+               function() { return undefined; },
+       rnoType = /^(?:input|button)$/i,
+       rnoAttrNodeType = /^[238]$/,
+       rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+       ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+       var lowerName = name.toLowerCase(),
+               nType = elem && elem.nodeType;
+
+       if ( pass ) {
+               // Since pass is used internally, we only warn for new jQuery
+               // versions where there isn't a pass arg in the formal params
+               if ( oldAttr.length < 4 ) {
+                       migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+               }
+               if ( elem && !rnoAttrNodeType.test( nType ) &&
+                       (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+                       return jQuery( elem )[ name ]( value );
+               }
+       }
+
+       // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+       // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+       if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+               migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+       }
+
+       // Restore boolHook for boolean property/attribute synchronization
+       if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+               jQuery.attrHooks[ lowerName ] = {
+                       get: function( elem, name ) {
+                               // Align boolean attributes with corresponding properties
+                               // Fall back to attribute presence where some booleans are not supported
+                               var attrNode,
+                                       property = jQuery.prop( elem, name );
+                               return property === true || typeof property !== "boolean" &&
+                                       ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+                                       name.toLowerCase() :
+                                       undefined;
+                       },
+                       set: function( elem, value, name ) {
+                               var propName;
+                               if ( value === false ) {
+                                       // Remove boolean attributes when set to false
+                                       jQuery.removeAttr( elem, name );
+                               } else {
+                                       // value is true since we know at this point it's type boolean and not false
+                                       // Set boolean attributes to the same name and set the DOM property
+                                       propName = jQuery.propFix[ name ] || name;
+                                       if ( propName in elem ) {
+                                               // Only set the IDL specifically if it already exists on the element
+                                               elem[ propName ] = true;
+                                       }
+
+                                       elem.setAttribute( name, name.toLowerCase() );
+                               }
+                               return name;
+                       }
+               };
+
+               // Warn only for attributes that can remain distinct from their properties post-1.9
+               if ( ruseDefault.test( lowerName ) ) {
+                       migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+               }
+       }
+
+       return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+       get: function( elem, name ) {
+               var nodeName = ( elem.nodeName || "" ).toLowerCase();
+               if ( nodeName === "button" ) {
+                       return valueAttrGet.apply( this, arguments );
+               }
+               if ( nodeName !== "input" && nodeName !== "option" ) {
+                       migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+               }
+               return name in elem ?
+                       elem.value :
+                       null;
+       },
+       set: function( elem, value ) {
+               var nodeName = ( elem.nodeName || "" ).toLowerCase();
+               if ( nodeName === "button" ) {
+                       return valueAttrSet.apply( this, arguments );
+               }
+               if ( nodeName !== "input" && nodeName !== "option" ) {
+                       migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+               }
+               // Does not return so that setAttribute is also used
+               elem.value = value;
+       }
+};
+
+
+var matched, browser,
+       oldInit = jQuery.fn.init,
+       oldParseJSON = jQuery.parseJSON,
+       // Note: XSS check is done below after string is trimmed
+       rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+       var match;
+
+       if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+                       (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+               // This is an HTML string according to the "old" rules; is it still?
+               if ( selector.charAt( 0 ) !== "<" ) {
+                       migrateWarn("$(html) HTML strings must start with '<' character");
+               }
+               if ( match[ 3 ] ) {
+                       migrateWarn("$(html) HTML text after last tag is ignored");
+               }
+               // Consistently reject any HTML-like string starting with a hash (#9521)
+               // Note that this may break jQuery 1.6.x code that otherwise would work.
+               if ( match[ 0 ].charAt( 0 ) === "#" ) {
+                       migrateWarn("HTML string cannot start with a '#' character");
+                       jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+               }
+               // Now process using loose rules; let pre-1.8 play too
+               if ( context && context.context ) {
+                       // jQuery object as context; parseHTML expects a DOM object
+                       context = context.context;
+               }
+               if ( jQuery.parseHTML ) {
+                       return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+                                       context, rootjQuery );
+               }
+       }
+       return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+       if ( !json && json !== null ) {
+               migrateWarn("jQuery.parseJSON requires a valid JSON string");
+               return null;
+       }
+       return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+       ua = ua.toLowerCase();
+
+       var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+               /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+               /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+               /(msie) ([\w.]+)/.exec( ua ) ||
+               ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+               [];
+
+       return {
+               browser: match[ 1 ] || "",
+               version: match[ 2 ] || "0"
+       };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+       matched = jQuery.uaMatch( navigator.userAgent );
+       browser = {};
+
+       if ( matched.browser ) {
+               browser[ matched.browser ] = true;
+               browser.version = matched.version;
+       }
+
+       // Chrome is Webkit, but Webkit is also Safari.
+       if ( browser.chrome ) {
+               browser.webkit = true;
+       } else if ( browser.webkit ) {
+               browser.safari = true;
+       }
+
+       jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+       function jQuerySub( selector, context ) {
+               return new jQuerySub.fn.init( selector, context );
+       }
+       jQuery.extend( true, jQuerySub, this );
+       jQuerySub.superclass = this;
+       jQuerySub.fn = jQuerySub.prototype = this();
+       jQuerySub.fn.constructor = jQuerySub;
+       jQuerySub.sub = this.sub;
+       jQuerySub.fn.init = function init( selector, context ) {
+               if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+                       context = jQuerySub( context );
+               }
+
+               return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+       };
+       jQuerySub.fn.init.prototype = jQuerySub.fn;
+       var rootjQuerySub = jQuerySub(document);
+       migrateWarn( "jQuery.sub() is deprecated" );
+       return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+       converters: {
+               "text json": jQuery.parseJSON
+       }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+       var ret, evt,
+               elem = this[0];
+
+       // Handles 1.7 which has this behavior and 1.8 which doesn't
+       if ( elem && name === "events" && arguments.length === 1 ) {
+               ret = jQuery.data( elem, name );
+               evt = jQuery._data( elem, name );
+               if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+                       migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+                       return evt;
+               }
+       }
+       return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+       oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+       migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+       return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+       jQuery.clean = function( elems, context, fragment, scripts ) {
+               // Set context per 1.8 logic
+               context = context || document;
+               context = !context.nodeType && context[0] || context;
+               context = context.ownerDocument || context;
+
+               migrateWarn("jQuery.clean() is deprecated");
+
+               var i, elem, handleScript, jsTags,
+                       ret = [];
+
+               jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+               // Complex logic lifted directly from jQuery 1.8
+               if ( fragment ) {
+                       // Special handling of each script element
+                       handleScript = function( elem ) {
+                               // Check if we consider it executable
+                               if ( !elem.type || rscriptType.test( elem.type ) ) {
+                                       // Detach the script and store it in the scripts array (if provided) or the fragment
+                                       // Return truthy to indicate that it has been handled
+                                       return scripts ?
+                                               scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+                                               fragment.appendChild( elem );
+                               }
+                       };
+
+                       for ( i = 0; (elem = ret[i]) != null; i++ ) {
+                               // Check if we're done after handling an executable script
+                               if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+                                       // Append to fragment and handle embedded scripts
+                                       fragment.appendChild( elem );
+                                       if ( typeof elem.getElementsByTagName !== "undefined" ) {
+                                               // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+                                               jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+                                               // Splice the scripts into ret after their former ancestor and advance our index beyond them
+                                               ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+                                               i += jsTags.length;
+                                       }
+                               }
+                       }
+               }
+
+               return ret;
+       };
+}
+
+var eventAdd = jQuery.event.add,
+       eventRemove = jQuery.event.remove,
+       eventTrigger = jQuery.event.trigger,
+       oldToggle = jQuery.fn.toggle,
+       oldLive = jQuery.fn.live,
+       oldDie = jQuery.fn.die,
+       ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+       rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+       rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+       hoverHack = function( events ) {
+               if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+                       return events;
+               }
+               if ( rhoverHack.test( events ) ) {
+                       migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+               }
+               return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+       };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+       jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+       migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+       if ( elem !== document && rajaxEvent.test( types ) ) {
+               migrateWarn( "AJAX events should be attached to document: " + types );
+       }
+       eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+       eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+       var args = Array.prototype.slice.call( arguments, 0);
+       migrateWarn("jQuery.fn.error() is deprecated");
+       args.splice( 0, 0, "error" );
+       if ( arguments.length ) {
+               return this.bind.apply( this, args );
+       }
+       // error event should not bubble to window, although it does pre-1.7
+       this.triggerHandler.apply( this, args );
+       return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+       // Don't mess with animation or css toggles
+       if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+               return oldToggle.apply( this, arguments );
+       }
+       migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+       // Save reference to arguments for access in closure
+       var args = arguments,
+               guid = fn.guid || jQuery.guid++,
+               i = 0,
+               toggler = function( event ) {
+                       // Figure out which function to execute
+                       var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+                       jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+                       // Make sure that clicks stop
+                       event.preventDefault();
+
+                       // and execute the function
+                       return args[ lastToggle ].apply( this, arguments ) || false;
+               };
+
+       // link all the functions, so any of them can unbind this click handler
+       toggler.guid = guid;
+       while ( i < args.length ) {
+               args[ i++ ].guid = guid;
+       }
+
+       return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+       migrateWarn("jQuery.fn.live() is deprecated");
+       if ( oldLive ) {
+               return oldLive.apply( this, arguments );
+       }
+       jQuery( this.context ).on( types, this.selector, data, fn );
+       return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+       migrateWarn("jQuery.fn.die() is deprecated");
+       if ( oldDie ) {
+               return oldDie.apply( this, arguments );
+       }
+       jQuery( this.context ).off( types, this.selector || "**", fn );
+       return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers  ){
+       if ( !elem && !rajaxEvent.test( event ) ) {
+               migrateWarn( "Global events are undocumented and deprecated" );
+       }
+       return eventTrigger.call( this,  event, data, elem || document, onlyHandlers  );
+};
+jQuery.each( ajaxEvents.split("|"),
+       function( _, name ) {
+               jQuery.event.special[ name ] = {
+                       setup: function() {
+                               var elem = this;
+
+                               // The document needs no shimming; must be !== for oldIE
+                               if ( elem !== document ) {
+                                       jQuery.event.add( document, name + "." + jQuery.guid, function() {
+                                               jQuery.event.trigger( name, null, elem, true );
+                                       });
+                                       jQuery._data( this, name, jQuery.guid++ );
+                               }
+                               return false;
+                       },
+                       teardown: function() {
+                               if ( this !== document ) {
+                                       jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+                               }
+                               return false;
+                       }
+               };
+       }
+);
+
+
+})( jQuery, window );
diff --git a/js/libs/jquery/jquery.mousewheel.js b/js/libs/jquery/jquery.mousewheel.js
new file mode 100644 (file)
index 0000000..47e9a40
--- /dev/null
@@ -0,0 +1,84 @@
+/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
+* Licensed under the MIT License (LICENSE.txt).
+*
+* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+* Thanks to: Seamus Leahy for adding deltaX and deltaY
+*
+* Version: 3.0.6
+*
+* Requires: 1.2.2+
+*/
+
+(function($) {
+
+var types = ['DOMMouseScroll', 'mousewheel'];
+
+if ($.event.fixHooks) {
+    for ( var i=types.length; i; ) {
+        $.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
+    }
+}
+
+$.event.special.mousewheel = {
+    setup: function() {
+        if ( this.addEventListener ) {
+            for ( var i=types.length; i; ) {
+                this.addEventListener( types[--i], handler, false );
+            }
+        } else {
+            this.onmousewheel = handler;
+        }
+    },
+    
+    teardown: function() {
+        if ( this.removeEventListener ) {
+            for ( var i=types.length; i; ) {
+                this.removeEventListener( types[--i], handler, false );
+            }
+        } else {
+            this.onmousewheel = null;
+        }
+    }
+};
+
+$.fn.extend({
+    mousewheel: function(fn) {
+        return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+    },
+    
+    unmousewheel: function(fn) {
+        return this.unbind("mousewheel", fn);
+    }
+});
+
+
+function handler(event) {
+    var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
+    event = $.event.fix(orgEvent);
+    event.type = "mousewheel";
+    
+    // Old school scrollwheel delta
+    if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
+    if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
+    
+    // New school multidimensional scroll (touchpads) deltas
+    deltaY = delta;
+    
+    // Gecko
+    if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
+        deltaY = 0;
+        deltaX = -1*delta;
+    }
+    
+    // Webkit
+    if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
+    if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
+    
+    // Add event and delta to the front of the arguments
+    args.unshift(event, delta, deltaX, deltaY);
+    
+    return ($.event.dispatch || $.event.handle).apply(this, args);
+}
+
+})(jQuery);
\ No newline at end of file
diff --git a/js/libs/jquery/jquery.scrollto.js b/js/libs/jquery/jquery.scrollto.js
new file mode 100644 (file)
index 0000000..e47c1a8
--- /dev/null
@@ -0,0 +1,218 @@
+/*!
+ * jQuery.ScrollTo
+ * Copyright (c) 2007-2012 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 4/09/2012
+ *
+ * @projectDescription Easy element scrolling using jQuery.
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
+ * @author Ariel Flesler
+ * @version 1.4.3.1
+ *
+ * @id jQuery.scrollTo
+ * @id jQuery.fn.scrollTo
+ * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
+ *       The different options for target are:
+ *             - A number position (will be applied to all axes).
+ *             - A string position ('44', '100px', '+=90', etc ) will be applied to all axes
+ *             - A jQuery/DOM element ( logically, child of the element to scroll )
+ *             - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
+ *             - A hash { top:x, left:y }, x and y can be any kind of number/string like above.
+ *             - A percentage of the container's dimension/s, for example: 50% to go to the middle.
+ *             - The string 'max' for go-to-end. 
+ * @param {Number, Function} duration The OVERALL length of the animation, this argument can be the settings object instead.
+ * @param {Object,Function} settings Optional set of settings or the onAfter callback.
+ *      @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
+ *      @option {Number, Function} duration The OVERALL length of the animation.
+ *      @option {String} easing The easing method for the animation.
+ *      @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
+ *      @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
+ *      @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
+ *      @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
+ *      @option {Function} onAfter Function to be called after the scrolling ends. 
+ *      @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
+ * @return {jQuery} Returns the same jQuery object, for chaining.
+ *
+ * @desc Scroll to a fixed position
+ * @example $('div').scrollTo( 340 );
+ *
+ * @desc Scroll relatively to the actual position
+ * @example $('div').scrollTo( '+=340px', { axis:'y' } );
+ *
+ * @desc Scroll using a selector (relative to the scrolled element)
+ * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
+ *
+ * @desc Scroll to a DOM element (same for jQuery object)
+ * @example var second_child = document.getElementById('container').firstChild.nextSibling;
+ *                     $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
+ *                             alert('scrolled!!');                                                                                                                               
+ *                     }});
+ *
+ * @desc Scroll on both axes, to different values
+ * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
+ */
+
+;(function( $ ){
+       
+       var $scrollTo = $.scrollTo = function( target, duration, settings ){
+               $(window).scrollTo( target, duration, settings );
+       };
+
+       $scrollTo.defaults = {
+               axis:'xy',
+               duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1,
+               limit:true
+       };
+
+       // Returns the element that needs to be animated to scroll the window.
+       // Kept for backwards compatibility (specially for localScroll & serialScroll)
+       $scrollTo.window = function( scope ){
+               return $(window)._scrollable();
+       };
+
+       // Hack, hack, hack :)
+       // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
+       $.fn._scrollable = function(){
+               return this.map(function(){
+                       var elem = this,
+                               isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1;
+
+                               if( !isWin )
+                                       return elem;
+
+                       var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem;
+                       
+                       return /webkit/i.test(navigator.userAgent) || doc.compatMode == 'BackCompat' ?
+                               doc.body : 
+                               doc.documentElement;
+               });
+       };
+
+       $.fn.scrollTo = function( target, duration, settings ){
+               if( typeof duration == 'object' ){
+                       settings = duration;
+                       duration = 0;
+               }
+               if( typeof settings == 'function' )
+                       settings = { onAfter:settings };
+                       
+               if( target == 'max' )
+                       target = 9e9;
+                       
+               settings = $.extend( {}, $scrollTo.defaults, settings );
+               // Speed is still recognized for backwards compatibility
+               duration = duration || settings.duration;
+               // Make sure the settings are given right
+               settings.queue = settings.queue && settings.axis.length > 1;
+               
+               if( settings.queue )
+                       // Let's keep the overall duration
+                       duration /= 2;
+               settings.offset = both( settings.offset );
+               settings.over = both( settings.over );
+
+               return this._scrollable().each(function(){
+                       // Null target yields nothing, just like jQuery does
+                       if (target == null) return;
+
+                       var elem = this,
+                               $elem = $(elem),
+                               targ = target, toff, attr = {},
+                               win = $elem.is('html,body');
+
+                       switch( typeof targ ){
+                               // A number will pass the regex
+                               case 'number':
+                               case 'string':
+                                       if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){
+                                               targ = both( targ );
+                                               // We are done
+                                               break;
+                                       }
+                                       // Relative selector, no break!
+                                       targ = $(targ,this);
+                                       if (!targ.length) return;
+                               case 'object':
+                                       // DOMElement / jQuery
+                                       if( targ.is || targ.style )
+                                               // Get the real position of the target 
+                                               toff = (targ = $(targ)).offset();
+                       }
+                       $.each( settings.axis.split(''), function( i, axis ){
+                               var Pos = axis == 'x' ? 'Left' : 'Top',
+                                       pos = Pos.toLowerCase(),
+                                       key = 'scroll' + Pos,
+                                       old = elem[key],
+                                       max = $scrollTo.max(elem, axis);
+
+                               if( toff ){// jQuery / DOMElement
+                                       attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
+
+                                       // If it's a dom element, reduce the margin
+                                       if( settings.margin ){
+                                               attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
+                                               attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
+                                       }
+                                       
+                                       attr[key] += settings.offset[pos] || 0;
+                                       
+                                       if( settings.over[pos] )
+                                               // Scroll to a fraction of its width/height
+                                               attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos];
+                               }else{ 
+                                       var val = targ[pos];
+                                       // Handle percentage values
+                                       attr[key] = val.slice && val.slice(-1) == '%' ? 
+                                               parseFloat(val) / 100 * max
+                                               : val;
+                               }
+
+                               // Number or 'number'
+                               if( settings.limit && /^\d+$/.test(attr[key]) )
+                                       // Check the limits
+                                       attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max );
+
+                               // Queueing axes
+                               if( !i && settings.queue ){
+                                       // Don't waste time animating, if there's no need.
+                                       if( old != attr[key] )
+                                               // Intermediate animation
+                                               animate( settings.onAfterFirst );
+                                       // Don't animate this axis again in the next iteration.
+                                       delete attr[key];
+                               }
+                       });
+
+                       animate( settings.onAfter );                    
+
+                       function animate( callback ){
+                               $elem.animate( attr, duration, settings.easing, callback && function(){
+                                       callback.call(this, target, settings);
+                               });
+                       };
+
+               }).end();
+       };
+       
+       // Max scrolling position, works on quirks mode
+       // It only fails (not too badly) on IE, quirks mode.
+       $scrollTo.max = function( elem, axis ){
+               var Dim = axis == 'x' ? 'Width' : 'Height',
+                       scroll = 'scroll'+Dim;
+               
+               if( !$(elem).is('html,body') )
+                       return elem[scroll] - $(elem)[Dim.toLowerCase()]();
+               
+               var size = 'client' + Dim,
+                       html = elem.ownerDocument.documentElement,
+                       body = elem.ownerDocument.body;
+
+               return Math.max( html[scroll], body[scroll] ) 
+                        - Math.min( html[size]  , body[size]   );
+       };
+
+       function both( val ){
+               return typeof val == 'object' ? val : { top:val, left:val };
+       };
+
+})( jQuery );
\ No newline at end of file
diff --git a/js/libs/jquery/jquery.transform.js b/js/libs/jquery/jquery.transform.js
new file mode 100644 (file)
index 0000000..a81ca1f
--- /dev/null
@@ -0,0 +1,1951 @@
+///////////////////////////////////////////////////////
+// Transform
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * @var Regex identify the matrix filter in IE
+        */
+       var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/,
+               rfxnum = /^([\+\-]=)?([\d+.\-]+)(.*)$/,
+               rperc = /%/;
+       
+       // Steal some code from Modernizr
+       var m = document.createElement( 'modernizr' ),
+               m_style = m.style;
+               
+       function stripUnits(arg) {
+               return parseFloat(arg);
+       }
+       
+       /**
+        * Find the prefix that this browser uses
+        */     
+       function getVendorPrefix() {
+               var property = {
+                       transformProperty : '',
+                       MozTransform : '-moz-',
+                       WebkitTransform : '-webkit-',
+                       OTransform : '-o-',
+                       msTransform : '-ms-'
+               };
+               for (var p in property) {
+                       if (typeof m_style[p] != 'undefined') {
+                               return property[p];
+                       }
+               }
+               return null;
+       }
+       
+       function supportCssTransforms() {
+               if (typeof(window.Modernizr) !== 'undefined') {
+                       return Modernizr.csstransforms;
+               }
+               
+               var props = [ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ];
+               for ( var i in props ) {
+                       if ( m_style[ props[i] ] !== undefined  ) {
+                               return true;
+                       }
+               }
+       }
+               
+       // Capture some basic properties
+       var vendorPrefix                        = getVendorPrefix(),
+               transformProperty               = vendorPrefix !== null ? vendorPrefix + 'transform' : false,
+               transformOriginProperty = vendorPrefix !== null ? vendorPrefix + 'transform-origin' : false;
+       
+       // store support in the jQuery Support object
+       $.support.csstransforms = supportCssTransforms();
+       
+       // IE9 public preview 6 requires the DOM names
+       if (vendorPrefix == '-ms-') {
+               transformProperty = 'msTransform';
+               transformOriginProperty = 'msTransformOrigin';
+       }
+       
+       /**
+        * Class for creating cross-browser transformations
+        * @constructor
+        */
+       $.extend({
+               transform: function(elem) {
+                       // Cache the transform object on the element itself
+                       elem.transform = this;
+                       
+                       /**
+                        * The element we're working with
+                        * @var jQueryCollection
+                        */
+                       this.$elem = $(elem);
+                                               
+                       /**
+                        * Remember the matrix we're applying to help the safeOuterLength func
+                        */
+                       this.applyingMatrix = false;
+                       this.matrix = null;
+                       
+                       /**
+                        * Remember the css height and width to save time
+                        * This is only really used in IE
+                        * @var Number
+                        */
+                       this.height = null;
+                       this.width = null;
+                       this.outerHeight = null;
+                       this.outerWidth = null;
+                       
+                       /**
+                        * We need to know the box-sizing in IE for building the outerHeight and outerWidth
+                        * @var string
+                        */
+                       this.boxSizingValue = null;
+                       this.boxSizingProperty = null;
+                       
+                       this.attr = null;
+                       this.transformProperty = transformProperty;
+                       this.transformOriginProperty = transformOriginProperty;
+               }
+       });
+       
+       $.extend($.transform, {
+               /**
+                * @var Array list of all valid transform functions
+                */
+               funcs: ['matrix', 'origin', 'reflect', 'reflectX', 'reflectXY', 'reflectY', 'rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY']
+       });
+       
+       /**
+        * Create Transform as a jQuery plugin
+        * @param Object funcs
+        * @param Object options
+        */
+       $.fn.transform = function(funcs, options) {
+               return this.each(function() {
+                       var t = this.transform || new $.transform(this);
+                       if (funcs) {
+                               t.exec(funcs, options);
+                       }
+               });
+       };
+       
+       $.transform.prototype = {
+               /**
+                * Applies all of the transformations
+                * @param Object funcs
+                * @param Object options
+                * forceMatrix - uses the matrix in all browsers
+                * preserve - tries to preserve the values from previous runs
+                */
+               exec: function(funcs, options) {
+                       // extend options
+                       options = $.extend(true, {
+                               forceMatrix: false,
+                               preserve: false
+                       }, options);
+       
+                       // preserve the funcs from the previous run
+                       this.attr = null;
+                       if (options.preserve) {
+                               funcs = $.extend(true, this.getAttrs(true, true), funcs);
+                       } else {
+                               funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness
+                       }
+                       
+                       // Record the custom attributes on the element itself
+                       this.setAttrs(funcs);
+                       
+                       // apply the funcs
+                       if ($.support.csstransforms && !options.forceMatrix) {
+                               // CSS3 is supported
+                               return this.execFuncs(funcs);
+                       } else if ($.browser.msie || ($.support.csstransforms && options.forceMatrix)) {
+                               // Internet Explorer or Forced matrix
+                               return this.execMatrix(funcs);
+                       }
+                       return false;
+               },
+               
+               /**
+                * Applies all of the transformations as functions
+                * @param Object funcs
+                */
+               execFuncs: function(funcs) {
+                       var values = [];
+                       
+                       // construct a CSS string
+                       for (var func in funcs) {
+                               // handle origin separately
+                               if (func == 'origin') {
+                                       this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]);
+                               } else if ($.inArray(func, $.transform.funcs) !== -1) {
+                                       values.push(this.createTransformFunc(func, funcs[func]));
+                               }
+                       }
+                       this.$elem.css(transformProperty, values.join(' '));
+                       return true;
+               },
+               
+               /**
+                * Applies all of the transformations as a matrix
+                * @param Object funcs
+                */
+               execMatrix: function(funcs) {
+                       var matrix,
+                               tempMatrix,
+                               args;
+                       
+                       var elem = this.$elem[0],
+                               _this = this;
+                       function normalPixels(val, i) {
+                               if (rperc.test(val)) {
+                                       // this really only applies to translation
+                                       return parseFloat(val) / 100 * _this['safeOuter' + (i ? 'Height' : 'Width')]();
+                               }
+                               return toPx(elem, val);
+                       }
+                       
+                       var rtranslate = /translate[X|Y]?/,
+                               trans = [];
+                               
+                       for (var func in funcs) {
+                               switch ($.type(funcs[func])) {
+                                       case 'array': args = funcs[func]; break;
+                                       case 'string': args = $.map(funcs[func].split(','), $.trim); break;
+                                       default: args = [funcs[func]];
+                               }
+                               
+                               if ($.matrix[func]) {
+                                       
+                                       if ($.cssAngle[func]) {
+                                               // normalize on degrees
+                                               args = $.map(args, $.angle.toDegree);                                           
+                                       } else if (!$.cssNumber[func]) {
+                                               // normalize to pixels
+                                               args = $.map(args, normalPixels);
+                                       } else {
+                                               // strip units
+                                               args = $.map(args, stripUnits);
+                                       }
+                                       
+                                       tempMatrix = $.matrix[func].apply(this, args);
+                                       if (rtranslate.test(func)) {
+                                               //defer translation
+                                               trans.push(tempMatrix);
+                                       } else {
+                                               matrix = matrix ? matrix.x(tempMatrix) : tempMatrix;
+                                       }
+                               } else if (func == 'origin') {
+                                       this[func].apply(this, args);
+                               }
+                       }
+                       
+                       // check that we have a matrix
+                       matrix = matrix || $.matrix.identity();
+                       
+                       // Apply translation
+                       $.each(trans, function(i, val) { matrix = matrix.x(val); });
+
+                       // pull out the relevant values
+                       var a = parseFloat(matrix.e(1,1).toFixed(6)),
+                               b = parseFloat(matrix.e(2,1).toFixed(6)),
+                               c = parseFloat(matrix.e(1,2).toFixed(6)),
+                               d = parseFloat(matrix.e(2,2).toFixed(6)),
+                               tx = matrix.rows === 3 ? parseFloat(matrix.e(1,3).toFixed(6)) : 0,
+                               ty = matrix.rows === 3 ? parseFloat(matrix.e(2,3).toFixed(6)) : 0;
+                       
+                       //apply the transform to the element
+                       if ($.support.csstransforms && vendorPrefix === '-moz-') {
+                               // -moz-
+                               this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)');
+                       } else if ($.support.csstransforms) {
+                               // -webkit, -o-, w3c
+                               // NOTE: WebKit and Opera don't allow units on the translate variables
+                               this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')');
+                       } else if ($.browser.msie) {
+                               // IE requires the special transform Filter
+                               
+                               //TODO: Use Nearest Neighbor during animation FilterType=\'nearest neighbor\'
+                               var filterType = ', FilterType=\'nearest neighbor\''; //bilinear
+                               var style = this.$elem[0].style;
+                               var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(' +
+                                               'M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d +
+                                               ', sizingMethod=\'auto expand\'' + filterType + ')';
+                               var filter = style.filter || $.curCSS( this.$elem[0], "filter" ) || "";
+                               style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter;
+                               
+                               // Let's know that we're applying post matrix fixes and the height/width will be static for a bit
+                               this.applyingMatrix = true;
+                               this.matrix = matrix;
+                               
+                               // IE can't set the origin or translate directly
+                               this.fixPosition(matrix, tx, ty);
+                               
+                               this.applyingMatrix = false;
+                               this.matrix = null;
+                       }
+                       return true;
+               },
+               
+               /**
+                * Sets the transform-origin
+                * This really needs to be percentages
+                * @param Number x length
+                * @param Number y length
+                */
+               origin: function(x, y) {
+                       // use CSS in supported browsers
+                       if ($.support.csstransforms) {
+                               if (typeof y === 'undefined') {
+                                       this.$elem.css(transformOriginProperty, x);
+                               } else {
+                                       this.$elem.css(transformOriginProperty, x + ' ' + y);
+                               }
+                               return true;
+                       }
+                       
+                       // correct for keyword lengths
+                       switch (x) {
+                               case 'left': x = '0'; break;
+                               case 'right': x = '100%'; break;
+                               case 'center': // no break
+                               case undefined: x = '50%';
+                       }
+                       switch (y) {
+                               case 'top': y = '0'; break;
+                               case 'bottom': y = '100%'; break;
+                               case 'center': // no break
+                               case undefined: y = '50%'; //TODO: does this work?
+                       }
+                       
+                       // store mixed values with units, assumed pixels
+                       this.setAttr('origin', [
+                               rperc.test(x) ? x : toPx(this.$elem[0], x) + 'px',
+                               rperc.test(y) ? y : toPx(this.$elem[0], y) + 'px'
+                       ]);
+                       //console.log(this.getAttr('origin'));
+                       return true;
+               },
+               
+               /**
+                * Create a function suitable for a CSS value
+                * @param string func
+                * @param Mixed value
+                */
+               createTransformFunc: function(func, value) {
+                       if (func.substr(0, 7) === 'reflect') {
+                               // let's fake reflection, false value 
+                               // falsey sets an identity matrix
+                               var m = value ? $.matrix[func]() : $.matrix.identity();
+                               return 'matrix(' + m.e(1,1) + ', ' + m.e(2,1) + ', ' + m.e(1,2) + ', ' + m.e(2,2) + ', 0, 0)';
+                       }
+                       
+                       //value = _correctUnits(func, value);
+                       
+                       if (func == 'matrix') {
+                               if (vendorPrefix === '-moz-') {
+                                       value[4] = value[4] ? value[4] + 'px' : 0;
+                                       value[5] = value[5] ? value[5] + 'px' : 0;
+                               }
+                       }
+                       return func + '(' + ($.isArray(value) ? value.join(', ') : value) + ')';
+               },
+               
+               /**
+                * @param Matrix matrix
+                * @param Number tx
+                * @param Number ty
+                * @param Number height
+                * @param Number width
+                */
+               fixPosition: function(matrix, tx, ty, height, width) {
+                       // now we need to fix it!
+                       var     calc = new $.matrix.calc(matrix, this.safeOuterHeight(), this.safeOuterWidth()),
+                               origin = this.getAttr('origin'); // mixed percentages and px
+                       
+                       // translate a 0, 0 origin to the current origin
+                       var offset = calc.originOffset(new $.matrix.V2(
+                               rperc.test(origin[0]) ? parseFloat(origin[0])/100*calc.outerWidth : parseFloat(origin[0]),
+                               rperc.test(origin[1]) ? parseFloat(origin[1])/100*calc.outerHeight : parseFloat(origin[1])
+                       ));
+                       
+                       // IE glues the top-most and left-most pixels of the transformed object to top/left of the original object
+                       //TODO: This seems wrong in the calculations
+                       var sides = calc.sides();
+
+                       // Protect against an item that is already positioned
+                       var cssPosition = this.$elem.css('position');
+                       if (cssPosition == 'static') {
+                               cssPosition = 'relative';
+                       }
+                       
+                       //TODO: if the element is already positioned, we should attempt to respect it (somehow)
+                       //NOTE: we could preserve our offset top and left in an attr on the elem
+                       var pos = {top: 0, left: 0};
+                       
+                       // Approximates transform-origin, tx, and ty
+                       var css = {
+                               'position': cssPosition,
+                               'top': (offset.top + ty + sides.top + pos.top) + 'px',
+                               'left': (offset.left + tx + sides.left + pos.left) + 'px',
+                               'zoom': 1
+                       };
+
+                       this.$elem.css(css);
+               }
+       };
+       
+       /**
+        * Ensure that values have the appropriate units on them
+        * @param string func
+        * @param Mixed value
+        */
+       function toPx(elem, val) {
+               var parts = rfxnum.exec($.trim(val));
+               
+               if (parts[3] && parts[3] !== 'px') {
+                       var prop = 'paddingBottom',
+                               orig = $.style( elem, prop );
+                               
+                       $.style( elem, prop, val );
+                       val = cur( elem, prop );
+                       $.style( elem, prop, orig );
+                       return val;
+               }
+               return parseFloat( val );
+       }
+       
+       function cur(elem, prop) {
+               if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
+                       return elem[ prop ];
+               }
+
+               var r = parseFloat( $.css( elem, prop ) );
+               return r && r > -10000 ? r : 0;
+       }
+})(jQuery, this, this.document);
+
+
+///////////////////////////////////////////////////////
+// Safe Outer Length
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       $.extend($.transform.prototype, {
+               /**
+                * @param void
+                * @return Number
+                */
+               safeOuterHeight: function() {
+                       return this.safeOuterLength('height');
+               },
+               
+               /**
+                * @param void
+                * @return Number
+                */
+               safeOuterWidth: function() {
+                       return this.safeOuterLength('width');
+               },
+               
+               /**
+                * Returns reliable outer dimensions for an object that may have been transformed.
+                * Only use this if the matrix isn't handy
+                * @param String dim height or width
+                * @return Number
+                */
+               safeOuterLength: function(dim) {
+                       var funcName = 'outer' + (dim == 'width' ? 'Width' : 'Height');
+                       
+                       if (!$.support.csstransforms && $.browser.msie) {
+                               // make the variables more generic
+                               dim = dim == 'width' ? 'width' : 'height';
+                               
+                               // if we're transforming and have a matrix; we can shortcut.
+                               // the true outerHeight is the transformed outerHeight divided by the ratio.
+                               // the ratio is equal to the height of a 1px by 1px box that has been transformed by the same matrix.
+                               if (this.applyingMatrix && !this[funcName] && this.matrix) {
+                                       // calculate and return the correct size
+                                       var calc = new $.matrix.calc(this.matrix, 1, 1),
+                                               ratio = calc.offset(),
+                                               length = this.$elem[funcName]() / ratio[dim];
+                                       this[funcName] = length;
+                                       
+                                       return length;
+                               } else if (this.applyingMatrix && this[funcName]) {
+                                       // return the cached calculation
+                                       return this[funcName];
+                               }
+                               
+                               // map dimensions to box sides                  
+                               var side = {
+                                       height: ['top', 'bottom'],
+                                       width: ['left', 'right']
+                               };
+                               
+                               // setup some variables
+                               var elem = this.$elem[0],
+                                       outerLen = parseFloat($.curCSS(elem, dim, true)), //TODO: this can be cached on animations that do not animate height/width
+                                       boxSizingProp = this.boxSizingProperty,
+                                       boxSizingValue = this.boxSizingValue;
+                               
+                               // IE6 && IE7 will never have a box-sizing property, so fake it
+                               if (!this.boxSizingProperty) {
+                                       boxSizingProp = this.boxSizingProperty = _findBoxSizingProperty() || 'box-sizing';
+                                       boxSizingValue = this.boxSizingValue = this.$elem.css(boxSizingProp) || 'content-box';
+                               }
+                               
+                               // return it immediately if we already know it
+                               if (this[funcName] && this[dim] == outerLen) {
+                                       return this[funcName];
+                               } else {
+                                       this[dim] = outerLen;
+                               }
+                               
+                               // add in the padding and border
+                               if (boxSizingProp && (boxSizingValue == 'padding-box' || boxSizingValue == 'content-box')) {
+                                       outerLen += parseFloat($.curCSS(elem, 'padding-' + side[dim][0], true)) || 0 +
+                                                                 parseFloat($.curCSS(elem, 'padding-' + side[dim][1], true)) || 0;
+                               }
+                               if (boxSizingProp && boxSizingValue == 'content-box') {
+                                       outerLen += parseFloat($.curCSS(elem, 'border-' + side[dim][0] + '-width', true)) || 0 +
+                                                                 parseFloat($.curCSS(elem, 'border-' + side[dim][1] + '-width', true)) || 0;
+                               }
+                               
+                               // remember and return the outerHeight
+                               this[funcName] = outerLen;
+                               return outerLen;
+                       }
+                       return this.$elem[funcName]();
+               }
+       });
+       
+       /**
+        * Determine the correct property for checking the box-sizing property
+        * @param void
+        * @return string
+        */
+       var _boxSizingProperty = null;
+       function _findBoxSizingProperty () {
+               if (_boxSizingProperty) {
+                       return _boxSizingProperty;
+               } 
+               
+               var property = {
+                               boxSizing : 'box-sizing',
+                               MozBoxSizing : '-moz-box-sizing',
+                               WebkitBoxSizing : '-webkit-box-sizing',
+                               OBoxSizing : '-o-box-sizing'
+                       },
+                       elem = document.body;
+               
+               for (var p in property) {
+                       if (typeof elem.style[p] != 'undefined') {
+                               _boxSizingProperty = property[p];
+                               return _boxSizingProperty;
+                       }
+               }
+               return null;
+       }
+})(jQuery, this, this.document);
+
+
+///////////////////////////////////////////////////////
+// Attr
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       var rfuncvalue = /([\w\-]*?)\((.*?)\)/g, // with values
+               attr = 'data-transform',
+               rspace = /\s/,
+               rcspace = /,\s?/;
+       
+       $.extend($.transform.prototype, {               
+               /**
+                * This overrides all of the attributes
+                * @param Object funcs a list of transform functions to store on this element
+                * @return void
+                */
+               setAttrs: function(funcs) {
+                       var string = '',
+                               value;
+                       for (var func in funcs) {
+                               value = funcs[func];
+                               if ($.isArray(value)) {
+                                       value = value.join(', ');
+                               }
+                               string += ' ' + func + '(' + value + ')'; 
+                       }
+                       this.attr = $.trim(string);
+                       this.$elem.attr(attr, this.attr);
+               },
+               
+               /**
+                * This sets only a specific atribute
+                * @param string func name of a transform function
+                * @param mixed value with proper units
+                * @return void
+                */
+               setAttr: function(func, value) {
+                       // stringify the value
+                       if ($.isArray(value)) {
+                               value = value.join(', ');
+                       }
+                       
+                       // pull from a local variable to look it up
+                       var transform = this.attr || this.$elem.attr(attr);
+                       if (!transform || transform.indexOf(func) == -1) {
+                               // we don't have any existing values, save it
+                               // we don't have this function yet, save it
+                               this.attr = $.trim(transform + ' ' + func + '(' + value + ')');
+                               this.$elem.attr(attr, this.attr);
+                       } else {
+                               // replace the existing value
+                               var funcs = [], parts;
+                               
+                               // regex split
+                               rfuncvalue.lastIndex = 0; // reset the regex pointer
+                               while (parts = rfuncvalue.exec(transform)) {
+                                       if (func == parts[1]) {
+                                               funcs.push(func + '(' + value + ')');
+                                       } else {
+                                               funcs.push(parts[0]);
+                                       }
+                               }
+                               this.attr = funcs.join(' ');
+                               this.$elem.attr(attr, this.attr);
+                       }
+               },
+               
+               /**
+                * @return Object
+                */
+               getAttrs: function() {
+                       var transform = this.attr || this.$elem.attr(attr);
+                       if (!transform) {
+                               // We don't have any existing values, return empty object
+                               return {};
+                       }
+                       
+                       // replace the existing value
+                       var attrs = {}, parts, value;
+                       
+                       rfuncvalue.lastIndex = 0; // reset the regex pointer
+                       while ((parts = rfuncvalue.exec(transform)) !== null) {
+                               if (parts) {
+                                       value = parts[2].split(rcspace);
+                                       attrs[parts[1]] = value.length == 1 ? value[0] : value;
+                               }
+                       }
+                       return attrs;
+               },
+               
+               /**
+                * @param String func 
+                * @return mixed
+                */
+               getAttr: function(func) {
+                       var attrs = this.getAttrs();
+                       if (typeof attrs[func] !== 'undefined') {
+                               return attrs[func];
+                       }
+                       
+                       //TODO: move the origin to a function
+                       if (func === 'origin' && $.support.csstransforms) {
+                               // supported browsers return percentages always
+                               return this.$elem.css(this.transformOriginProperty).split(rspace);
+                       } else if (func === 'origin') {
+                               // just force IE to also return a percentage
+                               return ['50%', '50%'];
+                       }
+                       
+                       return $.cssDefault[func] || 0;
+               }
+       });
+       
+       // Define 
+       if (typeof($.cssAngle) == 'undefined') {
+               $.cssAngle = {};
+       }
+       $.extend($.cssAngle, {
+               rotate: true,
+               skew: true,
+               skewX: true,
+               skewY: true
+       });
+       
+       // Define default values
+       if (typeof($.cssDefault) == 'undefined') {
+               $.cssDefault = {};
+       }
+       
+       $.extend($.cssDefault, {
+               scale: [1, 1],
+               scaleX: 1,
+               scaleY: 1,
+               matrix: [1, 0, 0, 1, 0, 0],
+               origin: ['50%', '50%'], // TODO: allow this to be a function, like get
+               reflect: [1, 0, 0, 1, 0, 0],
+               reflectX: [1, 0, 0, 1, 0, 0],
+               reflectXY: [1, 0, 0, 1, 0, 0],
+               reflectY: [1, 0, 0, 1, 0, 0]
+       });
+       
+       // Define functons with multiple values
+       if (typeof($.cssMultipleValues) == 'undefined') {
+               $.cssMultipleValues = {};
+       }
+       $.extend($.cssMultipleValues, {
+               matrix: 6,
+               origin: {
+                       length: 2,
+                       duplicate: true
+               },
+               reflect: 6,
+               reflectX: 6,
+               reflectXY: 6,
+               reflectY: 6,
+               scale: {
+                       length: 2,
+                       duplicate: true
+               },
+               skew: 2,
+               translate: 2
+       });
+       
+       // specify unitless funcs
+       $.extend($.cssNumber, {
+               matrix: true,
+               reflect: true,
+               reflectX: true,
+               reflectXY: true,
+               reflectY: true,
+               scale: true,
+               scaleX: true,
+               scaleY: true
+       });
+       
+       // override all of the css functions
+       $.each($.transform.funcs, function(i, func) {
+               $.cssHooks[func] = {
+                       set: function(elem, value) {
+                               var transform = elem.transform || new $.transform(elem),
+                                       funcs = {};
+                               funcs[func] = value;
+                               transform.exec(funcs, {preserve: true});
+                       },
+                       get: function(elem, computed) {
+                               var transform = elem.transform || new $.transform(elem);
+                               return transform.getAttr(func);
+                       }
+               };
+       });
+       
+       // Support Reflection animation better by returning a matrix
+       $.each(['reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
+               $.cssHooks[func].get = function(elem, computed) {
+                       var transform = elem.transform || new $.transform(elem);
+                       return transform.getAttr('matrix') || $.cssDefault[func];
+               };
+       });
+})(jQuery, this, this.document);
+///////////////////////////////////////////////////////
+// Animation
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * @var Regex looks for units on a string
+        */
+       var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
+       
+       /**
+        * Doctors prop values in the event that they contain spaces
+        * @param Object prop
+        * @param String speed
+        * @param String easing
+        * @param Function callback
+        * @return bool
+        */
+       var _animate = $.fn.animate;
+       $.fn.animate = function( prop, speed, easing, callback ) {
+               var optall = $.speed(speed, easing, callback),
+                       mv = $.cssMultipleValues;
+               
+               // Speed always creates a complete function that must be reset
+               optall.complete = optall.old;
+               
+               // Capture multiple values
+               if (!$.isEmptyObject(prop)) {
+                       if (typeof optall.original === 'undefined') {
+                               optall.original = {};
+                       }
+                       $.each( prop, function( name, val ) {
+                               if (mv[name]
+                                       || $.cssAngle[name]
+                                       || (!$.cssNumber[name] && $.inArray(name, $.transform.funcs) !== -1)) {
+                                       
+                                       // Handle special easing
+                                       var specialEasing = null;
+                                       if (jQuery.isArray(prop[name])) {
+                                               var mvlen = 1, len = val.length;
+                                               if (mv[name]) {
+                                                       mvlen = (typeof mv[name].length === 'undefined' ? mv[name] : mv[name].length);
+                                               }
+                                               if ( len > mvlen
+                                                       || (len < mvlen && len == 2)
+                                                       || (len == 2 && mvlen == 2 && isNaN(parseFloat(val[len - 1])))) {
+                                                       
+                                                       specialEasing = val[len - 1];
+                                                       val.splice(len - 1, 1);
+                                               }
+                                       }
+                                       
+                                       // Store the original values onto the optall
+                                       optall.original[name] = val.toString();
+                                       
+                                       // reduce to a unitless number (to trick animate)
+                                       prop[name] = parseFloat(val);
+                               }
+                       } );
+               }
+               
+               //NOTE: we edited prop above to trick animate
+               //NOTE: we pre-convert to an optall so we can doctor it
+               return _animate.apply(this, [arguments[0], optall]);
+       };
+       
+       var prop = 'paddingBottom';
+       function cur(elem, prop) {
+               if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
+                       //return elem[ prop ];
+               }
+
+               var r = parseFloat( $.css( elem, prop ) );
+               return r && r > -10000 ? r : 0;
+       }
+       
+       var _custom = $.fx.prototype.custom;
+       $.fx.prototype.custom = function(from, to, unit) {
+               var multiple = $.cssMultipleValues[this.prop],
+                       angle = $.cssAngle[this.prop];
+               
+               //TODO: simply check for the existence of CSS Hooks?
+               if (multiple || (!$.cssNumber[this.prop] && $.inArray(this.prop, $.transform.funcs) !== -1)) {
+                       this.values = [];
+                       
+                       if (!multiple) {
+                               multiple = 1;
+                       }
+                       
+                       // Pull out the known values
+                       var values = this.options.original[this.prop],
+                               currentValues = $(this.elem).css(this.prop),
+                               defaultValues = $.cssDefault[this.prop] || 0;
+                       
+                       // make sure the current css value is an array
+                       if (!$.isArray(currentValues)) {
+                               currentValues = [currentValues];
+                       }
+                       
+                       // make sure the new values are an array
+                       if (!$.isArray(values)) {
+                               if ($.type(values) === 'string') {
+                                       values = values.split(',');
+                               } else {
+                                       values = [values];
+                               }
+                       }
+                       
+                       // make sure we have enough new values
+                       var length = multiple.length || multiple, i = 0;
+                       while (values.length < length) {
+                               values.push(multiple.duplicate ? values[0] : defaultValues[i] || 0);
+                               i++;
+                       }
+                       
+                       // calculate a start, end and unit for each new value
+                       var start, parts, end, //unit,
+                               fx = this,
+                               transform = fx.elem.transform;
+                               orig = $.style(fx.elem, prop);
+
+                       $.each(values, function(i, val) {
+                               // find a sensible start value
+                               if (currentValues[i]) {
+                                       start = currentValues[i];
+                               } else if (defaultValues[i] && !multiple.duplicate) {
+                                       start = defaultValues[i];
+                               } else if (multiple.duplicate) {
+                                       start = currentValues[0];
+                               } else {
+                                       start = 0;
+                               }
+                               
+                               // Force the correct unit on the start
+                               if (angle) {
+                                       start = $.angle.toDegree(start);
+                               } else if (!$.cssNumber[fx.prop]) {
+                                       parts = rfxnum.exec($.trim(start));
+                                       if (parts[3] && parts[3] !== 'px') {
+                                               if (parts[3] === '%') {
+                                                       start = parseFloat( parts[2] ) / 100 * transform['safeOuter' + (i ? 'Height' : 'Width')]();
+                                               } else {
+                                                       $.style( fx.elem, prop, start);
+                                                       start = cur(fx.elem, prop);
+                                                       $.style( fx.elem, prop, orig);
+                                               }
+                                       }
+                               }
+                               start = parseFloat(start);
+                               
+                               // parse the value with a regex
+                               parts = rfxnum.exec($.trim(val));
+                               
+                               if (parts) {
+                                       // we found a sensible value and unit
+                                       end = parseFloat( parts[2] );
+                                       unit = parts[3] || "px"; //TODO: change to an appropriate default unit
+                                       
+                                       if (angle) {
+                                               end = $.angle.toDegree(end + unit);
+                                               unit = 'deg';
+                                       } else if (!$.cssNumber[fx.prop] && unit === '%') {
+                                               start = (start / transform['safeOuter' + (i ? 'Height' : 'Width')]()) * 100;
+                                       } else if (!$.cssNumber[fx.prop] && unit !== 'px') {
+                                               $.style( fx.elem, prop, (end || 1) + unit);
+                                               start = ((end || 1) / cur(fx.elem, prop)) * start;
+                                               $.style( fx.elem, prop, orig);
+                                       }
+                                       
+                                       // If a +=/-= token was provided, we're doing a relative animation
+                                       if (parts[1]) {
+                                               end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
+                                       }
+                               } else {
+                                       // I don't know when this would happen
+                                       end = val;
+                                       unit = ''; 
+                               }
+                                                               
+                               // Save the values
+                               fx.values.push({
+                                       start: start,
+                                       end: end,
+                                       unit: unit
+                               });                             
+                       });
+               }
+               return _custom.apply(this, arguments);
+       };
+       
+       /**
+        * Animates a multi value attribute
+        * @param Object fx
+        * @return null
+        */
+       $.fx.multipleValueStep = {
+               _default: function(fx) {
+                       $.each(fx.values, function(i, val) {
+                               fx.values[i].now = val.start + ((val.end - val.start) * fx.pos);
+                       });
+               }
+       };
+       $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
+               $.fx.multipleValueStep[func] = function(fx) {
+                       var d = fx.decomposed,
+                               $m = $.matrix;
+                               m = $m.identity();
+                       
+                       d.now = {};
+                       
+                       // increment each part of the decomposition and recompose it            
+                       $.each(d.start, function(k) {                           
+                               // calculate the current value
+                               d.now[k] = parseFloat(d.start[k]) + ((parseFloat(d.end[k]) - parseFloat(d.start[k])) * fx.pos);
+                               
+                               // skip functions that won't affect the transform
+                               if (((k === 'scaleX' || k === 'scaleY') && d.now[k] === 1) ||
+                                       (k !== 'scaleX' && k !== 'scaleY' && d.now[k] === 0)) {
+                                       return true;
+                               }
+                               
+                               // calculating
+                               m = m.x($m[k](d.now[k]));
+                       });
+                       
+                       // save the correct matrix values for the value of now
+                       var val;
+                       $.each(fx.values, function(i) {
+                               switch (i) {
+                                       case 0: val = parseFloat(m.e(1, 1).toFixed(6)); break;
+                                       case 1: val = parseFloat(m.e(2, 1).toFixed(6)); break;
+                                       case 2: val = parseFloat(m.e(1, 2).toFixed(6)); break;
+                                       case 3: val = parseFloat(m.e(2, 2).toFixed(6)); break;
+                                       case 4: val = parseFloat(m.e(1, 3).toFixed(6)); break;
+                                       case 5: val = parseFloat(m.e(2, 3).toFixed(6)); break;
+                               }
+                               fx.values[i].now = val;
+                       });
+               };
+       });
+       /**
+        * Step for animating tranformations
+        */
+       $.each($.transform.funcs, function(i, func) {
+               $.fx.step[func] = function(fx) {
+                       var transform = fx.elem.transform || new $.transform(fx.elem),
+                               funcs = {};
+                       
+                       if ($.cssMultipleValues[func] || (!$.cssNumber[func] && $.inArray(func, $.transform.funcs) !== -1)) {
+                               ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
+                               funcs[fx.prop] = [];
+                               $.each(fx.values, function(i, val) {
+                                       funcs[fx.prop].push(val.now + ($.cssNumber[fx.prop] ? '' : val.unit));
+                               });
+                       } else {
+                               funcs[fx.prop] = fx.now + ($.cssNumber[fx.prop] ? '' : fx.unit);
+                       }
+                       
+                       transform.exec(funcs, {preserve: true});
+               };
+       });
+       
+       // Support matrix animation
+       $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
+               $.fx.step[func] = function(fx) {
+                       var transform = fx.elem.transform || new $.transform(fx.elem),
+                               funcs = {};
+                               
+                       if (!fx.initialized) {
+                               fx.initialized = true;
+
+                               // Reflections need a sensible end value set
+                               if (func !== 'matrix') {
+                                       var values = $.matrix[func]().elements;
+                                       var val;
+                                       $.each(fx.values, function(i) {
+                                               switch (i) {
+                                                       case 0: val = values[0]; break;
+                                                       case 1: val = values[2]; break;
+                                                       case 2: val = values[1]; break;
+                                                       case 3: val = values[3]; break;
+                                                       default: val = 0;
+                                               }
+                                               fx.values[i].end = val;
+                                       });
+                               }
+                               
+                               // Decompose the start and end
+                               fx.decomposed = {};
+                               var v = fx.values;
+                               
+                               fx.decomposed.start = $.matrix.matrix(v[0].start, v[1].start, v[2].start, v[3].start, v[4].start, v[5].start).decompose();
+                               fx.decomposed.end = $.matrix.matrix(v[0].end, v[1].end, v[2].end, v[3].end, v[4].end, v[5].end).decompose();
+                       }
+                       
+                       ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
+                       funcs.matrix = [];
+                       $.each(fx.values, function(i, val) {
+                               funcs.matrix.push(val.now);
+                       });
+                       
+                       transform.exec(funcs, {preserve: true});
+               };
+       });
+})(jQuery, this, this.document);
+///////////////////////////////////////////////////////
+// Angle
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * Converting a radian to a degree
+        * @const
+        */
+       var RAD_DEG = 180/Math.PI;
+       
+       /**
+        * Converting a radian to a grad
+        * @const
+        */
+       var RAD_GRAD = 200/Math.PI;
+       
+       /**
+        * Converting a degree to a radian
+        * @const
+        */
+       var DEG_RAD = Math.PI/180;
+       
+       /**
+        * Converting a degree to a grad
+        * @const
+        */
+       var DEG_GRAD = 2/1.8;
+       
+       /**
+        * Converting a grad to a degree
+        * @const
+        */
+       var GRAD_DEG = 0.9;
+       
+       /**
+        * Converting a grad to a radian
+        * @const
+        */
+       var GRAD_RAD = Math.PI/200;
+       
+       
+       var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
+       
+       /**
+        * Functions for converting angles
+        * @var Object
+        */
+       $.extend({
+               angle: {
+                       /**
+                        * available units for an angle
+                        * @var Regex
+                        */
+                       runit: /(deg|g?rad)/,
+                       
+                       /**
+                        * Convert a radian into a degree
+                        * @param Number rad
+                        * @return Number
+                        */
+                       radianToDegree: function(rad) {
+                               return rad * RAD_DEG;
+                       },
+                       
+                       /**
+                        * Convert a radian into a degree
+                        * @param Number rad
+                        * @return Number
+                        */
+                       radianToGrad: function(rad) {
+                               return rad * RAD_GRAD;
+                       },
+                       
+                       /**
+                        * Convert a degree into a radian
+                        * @param Number deg
+                        * @return Number
+                        */
+                       degreeToRadian: function(deg) {
+                               return deg * DEG_RAD;
+                       },
+                       
+                       /**
+                        * Convert a degree into a radian
+                        * @param Number deg
+                        * @return Number
+                        */
+                       degreeToGrad: function(deg) {
+                               return deg * DEG_GRAD;
+                       },
+                       
+                       /**
+                        * Convert a grad into a degree
+                        * @param Number grad
+                        * @return Number
+                        */
+                       gradToDegree: function(grad) {
+                               return grad * GRAD_DEG;
+                       },
+                       
+                       /**
+                        * Convert a grad into a radian
+                        * @param Number grad
+                        * @return Number
+                        */
+                       gradToRadian: function(grad) {
+                               return grad * GRAD_RAD;
+                       },
+                       
+                       /**
+                        * Convert an angle with a unit to a degree
+                        * @param String val angle with a unit
+                        * @return Number
+                        */
+                       toDegree: function (val) {
+                               var parts = rfxnum.exec(val);
+                               if (parts) {
+                                       val = parseFloat( parts[2] );
+                                       switch (parts[3] || 'deg') {
+                                               case 'grad':
+                                                       val = $.angle.gradToDegree(val);
+                                                       break;
+                                               case 'rad':
+                                                       val = $.angle.radianToDegree(val);
+                                                       break;
+                                       }
+                                       return val;
+                               }
+                               return 0;
+                       }
+               }
+       });
+})(jQuery, this, this.document);
+///////////////////////////////////////////////////////
+// Matrix
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * Matrix object for creating matrices relevant for 2d Transformations
+        * @var Object
+        */
+       if (typeof($.matrix) == 'undefined') {
+               $.extend({
+                       matrix: {}
+               });
+       }
+       var $m = $.matrix;
+       
+       $.extend( $m, {
+               /**
+                * A 2-value vector
+                * @param Number x
+                * @param Number y
+                * @constructor
+                */
+               V2: function(x, y){
+                       if ($.isArray(arguments[0])) {
+                               this.elements = arguments[0].slice(0, 2);
+                       } else {
+                               this.elements = [x, y];
+                       }
+                       this.length = 2;
+               },
+               
+               /**
+                * A 2-value vector
+                * @param Number x
+                * @param Number y
+                * @param Number z
+                * @constructor
+                */
+               V3: function(x, y, z){
+                       if ($.isArray(arguments[0])) {
+                               this.elements = arguments[0].slice(0, 3);
+                       } else {
+                               this.elements = [x, y, z];
+                       }
+                       this.length = 3;
+               },
+               
+               /**
+                * A 2x2 Matrix, useful for 2D-transformations without translations
+                * @param Number mn
+                * @constructor
+                */
+               M2x2: function(m11, m12, m21, m22) {
+                       if ($.isArray(arguments[0])) {
+                               this.elements = arguments[0].slice(0, 4);
+                       } else {
+                               this.elements = Array.prototype.slice.call(arguments).slice(0, 4);
+                       }
+                       this.rows = 2;
+                       this.cols = 2;
+               },
+               
+               /**
+                * A 3x3 Matrix, useful for 3D-transformations without translations
+                * @param Number mn
+                * @constructor
+                */
+               M3x3: function(m11, m12, m13, m21, m22, m23, m31, m32, m33) {
+                       if ($.isArray(arguments[0])) {
+                               this.elements = arguments[0].slice(0, 9);
+                       } else {
+                               this.elements = Array.prototype.slice.call(arguments).slice(0, 9);
+                       }
+                       this.rows = 3;
+                       this.cols = 3;
+               }
+       });
+       
+       /** generic matrix prototype */
+       var Matrix = {
+               /**
+                * Return a specific element from the matrix
+                * @param Number row where 1 is the 0th row
+                * @param Number col where 1 is the 0th column
+                * @return Number
+                */
+               e: function(row, col) {
+                       var rows = this.rows,
+                               cols = this.cols;
+                       
+                       // return 0 on nonsense rows and columns
+                       if (row > rows || col > rows || row < 1 || col < 1) {
+                               return 0;
+                       }
+                       
+                       return this.elements[(row - 1) * cols + col - 1];
+               },
+               
+               /**
+                * Taken from Zoomooz
+            * https://github.com/jaukia/zoomooz/blob/c7a37b9a65a06ba730bd66391bbd6fe8e55d3a49/js/jquery.zoomooz.js
+                */
+               decompose: function() {
+                       var a = this.e(1, 1),
+                               b = this.e(2, 1),
+                               c = this.e(1, 2),
+                               d = this.e(2, 2),
+                               e = this.e(1, 3),
+                               f = this.e(2, 3);
+                               
+                       // In case the matrix can't be decomposed
+                       if (Math.abs(a * d - b * c) < 0.01) {
+                               return {
+                                       rotate: 0 + 'deg',
+                                       skewX: 0 + 'deg',
+                                       scaleX: 1,
+                                       scaleY: 1,
+                                       translateX: 0 + 'px',
+                                       translateY: 0 + 'px'
+                               };
+                       }
+                       
+                       // Translate is easy
+                       var tx = e, ty = f;
+                       
+                       // factor out the X scale
+                       var sx = Math.sqrt(a * a + b * b);
+                       a = a/sx;
+                       b = b/sx;
+                       
+                       // factor out the skew
+                       var k = a * c + b * d;
+                       c -= a * k;
+                       d -= b * k;
+                       
+                       // factor out the Y scale
+                       var sy = Math.sqrt(c * c + d * d);
+                       c = c / sy;
+                       d = d / sy;
+                       k = k / sy;
+                       
+                       // account for negative scale
+                       if ((a * d - b * c) < 0.0) {
+                               a = -a;
+                               b = -b;
+                               //c = -c; // accomplishes nothing to negate it
+                               //d = -d; // accomplishes nothing to negate it
+                               sx = -sx;
+                               //sy = -sy //Scale Y shouldn't ever be negated
+                       }
+                       
+                       // calculate the rotation angle and skew angle
+                       var rad2deg = $.angle.radianToDegree;
+                       var r = rad2deg(Math.atan2(b, a));
+                       k = rad2deg(Math.atan(k));
+                       
+                       return {
+                               rotate: r + 'deg',
+                               skewX: k + 'deg',
+                               scaleX: sx,
+                               scaleY: sy,
+                               translateX: tx + 'px',
+                               translateY: ty + 'px'
+                       };
+               }
+       };
+       
+       /** Extend all of the matrix types with the same prototype */
+       $.extend($m.M2x2.prototype, Matrix, {
+               toM3x3: function() {
+                       var a = this.elements;
+                       return new $m.M3x3(
+                               a[0], a[1], 0,
+                               a[2], a[3], 0,
+                               0,    0,    1
+                       );      
+               },
+               
+               /**
+                * Multiply a 2x2 matrix by a similar matrix or a vector
+                * @param M2x2 | V2 matrix
+                * @return M2x2 | V2
+                */
+               x: function(matrix) {
+                       var isVector = typeof(matrix.rows) === 'undefined';
+                       
+                       // Ensure the right-sized matrix
+                       if (!isVector && matrix.rows == 3) {
+                               return this.toM3x3().x(matrix);
+                       }
+                       
+                       var a = this.elements,
+                               b = matrix.elements;
+                       
+                       if (isVector && b.length == 2) {
+                               // b is actually a vector
+                               return new $m.V2(
+                                       a[0] * b[0] + a[1] * b[1],
+                                       a[2] * b[0] + a[3] * b[1]
+                               );
+                       } else if (b.length == a.length) {
+                               // b is a 2x2 matrix
+                               return new $m.M2x2(
+                                       a[0] * b[0] + a[1] * b[2],
+                                       a[0] * b[1] + a[1] * b[3],
+                                       
+                                       a[2] * b[0] + a[3] * b[2],
+                                       a[2] * b[1] + a[3] * b[3]
+                               );
+                       }
+                       return false; // fail
+               },
+               
+               /**
+                * Generates an inverse of the current matrix
+                * @param void
+                * @return M2x2
+                * @link http://www.dr-lex.be/random/matrix_inv.html
+                */
+               inverse: function() {
+                       var d = 1/this.determinant(),
+                               a = this.elements;
+                       return new $m.M2x2(
+                               d *  a[3], d * -a[1],
+                               d * -a[2], d *  a[0]
+                       );
+               },
+               
+               /**
+                * Calculates the determinant of the current matrix
+                * @param void
+                * @return Number
+                * @link http://www.dr-lex.be/random/matrix_inv.html
+                */
+               determinant: function() {
+                       var a = this.elements;
+                       return a[0] * a[3] - a[1] * a[2];
+               }
+       });
+       
+       $.extend($m.M3x3.prototype, Matrix, {
+               /**
+                * Multiply a 3x3 matrix by a similar matrix or a vector
+                * @param M3x3 | V3 matrix
+                * @return M3x3 | V3
+                */
+               x: function(matrix) {
+                       var isVector = typeof(matrix.rows) === 'undefined';
+                       
+                       // Ensure the right-sized matrix
+                       if (!isVector && matrix.rows < 3) {
+                               matrix = matrix.toM3x3();
+                       }
+                       
+                       var a = this.elements,
+                               b = matrix.elements;
+                       
+                       if (isVector && b.length == 3) {
+                               // b is actually a vector
+                               return new $m.V3(
+                                       a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
+                                       a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
+                                       a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
+                               );
+                       } else if (b.length == a.length) {
+                               // b is a 3x3 matrix
+                               return new $m.M3x3(
+                                       a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
+                                       a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
+                                       a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
+
+                                       a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
+                                       a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
+                                       a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
+
+                                       a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
+                                       a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
+                                       a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
+                               );
+                       }
+                       return false; // fail
+               },
+               
+               /**
+                * Generates an inverse of the current matrix
+                * @param void
+                * @return M3x3
+                * @link http://www.dr-lex.be/random/matrix_inv.html
+                */
+               inverse: function() {
+                       var d = 1/this.determinant(),
+                               a = this.elements;
+                       return new $m.M3x3(
+                               d * (  a[8] * a[4] - a[7] * a[5]),
+                               d * (-(a[8] * a[1] - a[7] * a[2])),
+                               d * (  a[5] * a[1] - a[4] * a[2]),
+                               
+                               d * (-(a[8] * a[3] - a[6] * a[5])),
+                               d * (  a[8] * a[0] - a[6] * a[2]),
+                               d * (-(a[5] * a[0] - a[3] * a[2])),
+                               
+                               d * (  a[7] * a[3] - a[6] * a[4]),
+                               d * (-(a[7] * a[0] - a[6] * a[1])),
+                               d * (  a[4] * a[0] - a[3] * a[1])
+                       );
+               },
+               
+               /**
+                * Calculates the determinant of the current matrix
+                * @param void
+                * @return Number
+                * @link http://www.dr-lex.be/random/matrix_inv.html
+                */
+               determinant: function() {
+                       var a = this.elements;
+                       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]);
+               }
+       });
+       
+       /** generic vector prototype */
+       var Vector = {          
+               /**
+                * Return a specific element from the vector
+                * @param Number i where 1 is the 0th value
+                * @return Number
+                */
+               e: function(i) {
+                       return this.elements[i - 1];
+               }
+       };
+       
+       /** Extend all of the vector types with the same prototype */
+       $.extend($m.V2.prototype, Vector);
+       $.extend($m.V3.prototype, Vector);
+})(jQuery, this, this.document);
+///////////////////////////////////////////////////////
+// Matrix Calculations
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * Matrix object for creating matrices relevant for 2d Transformations
+        * @var Object
+        */
+       if (typeof($.matrix) == 'undefined') {
+               $.extend({
+                       matrix: {}
+               });
+       }
+       
+       $.extend( $.matrix, {
+               /**
+                * Class for calculating coordinates on a matrix
+                * @param Matrix matrix
+                * @param Number outerHeight
+                * @param Number outerWidth
+                * @constructor
+                */
+               calc: function(matrix, outerHeight, outerWidth) {
+                       /**
+                        * @var Matrix
+                        */
+                       this.matrix = matrix;
+                       
+                       /**
+                        * @var Number
+                        */
+                       this.outerHeight = outerHeight;
+                       
+                       /**
+                        * @var Number
+                        */
+                       this.outerWidth = outerWidth;
+               }
+       });
+       
+       $.matrix.calc.prototype = {
+               /**
+                * Calculate a coord on the new object
+                * @return Object
+                */
+               coord: function(x, y, z) {
+                       //default z and w
+                       z = typeof(z) !== 'undefined' ? z : 0;
+                       
+                       var matrix = this.matrix,
+                               vector;
+                               
+                       switch (matrix.rows) {
+                               case 2:
+                                       vector = matrix.x(new $.matrix.V2(x, y));
+                                       break;
+                               case 3:
+                                       vector = matrix.x(new $.matrix.V3(x, y, z));
+                                       break;
+                       }
+                       
+                       return vector;
+               },
+               
+               /**
+                * Calculate the corners of the new object
+                * @return Object
+                */
+               corners: function(x, y) {
+                       // Try to save the corners if this is called a lot
+                       var save = !(typeof(x) !=='undefined' || typeof(y) !=='undefined'),
+                               c;
+                       if (!this.c || !save) {
+                               y = y || this.outerHeight;
+                               x = x || this.outerWidth;
+                               
+                               c = {
+                                       tl: this.coord(0, 0),
+                                       bl: this.coord(0, y),
+                                       tr: this.coord(x, 0),
+                                       br: this.coord(x, y)
+                               };
+                       } else {
+                               c = this.c;
+                       }
+                       
+                       if (save) {
+                               this.c = c;
+                       }
+                       return c;
+               },
+               
+               /**
+                * Calculate the sides of the new object
+                * @return Object
+                */
+               sides: function(corners) {
+                       // The corners of the box
+                       var c = corners || this.corners();
+                       
+                       return {
+                               top: Math.min(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
+                               bottom: Math.max(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
+                               left: Math.min(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1)),
+                               right: Math.max(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1))
+                       };
+               },
+               
+               /**
+                * Calculate the offset of the new object
+                * @return Object
+                */
+               offset: function(corners) {
+                       // The corners of the box
+                       var s = this.sides(corners);
+                       
+                       // return size
+                       return {
+                               height: Math.abs(s.bottom - s.top), 
+                               width: Math.abs(s.right - s.left)
+                       };
+               },
+               
+               /**
+                * Calculate the area of the new object
+                * @return Number
+                * @link http://en.wikipedia.org/wiki/Quadrilateral#Area_of_a_convex_quadrilateral
+                */
+               area: function(corners) {
+                       // The corners of the box
+                       var c = corners || this.corners();
+                       
+                       // calculate the two diagonal vectors
+                       var v1 = {
+                                       x: c.tr.e(1) - c.tl.e(1) + c.br.e(1) - c.bl.e(1),
+                                       y: c.tr.e(2) - c.tl.e(2) + c.br.e(2) - c.bl.e(2)
+                               },
+                               v2 = {
+                                       x: c.bl.e(1) - c.tl.e(1) + c.br.e(1) - c.tr.e(1),
+                                       y: c.bl.e(2) - c.tl.e(2) + c.br.e(2) - c.tr.e(2)
+                               };
+                               
+                       return 0.25 * Math.abs(v1.e(1) * v2.e(2) - v1.e(2) * v2.e(1));
+               },
+               
+               /**
+                * Calculate the non-affinity of the new object
+                * @return Number
+                */
+               nonAffinity: function() {
+                       // The corners of the box
+                       var sides = this.sides(),
+                               xDiff = sides.top - sides.bottom,
+                               yDiff = sides.left - sides.right;
+                       
+                       return parseFloat(parseFloat(Math.abs(
+                               (Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) /
+                               (sides.top * sides.bottom + sides.left * sides.right)
+                       )).toFixed(8));
+               },
+               
+               /**
+                * Calculate a proper top and left for IE
+                * @param Object toOrigin
+                * @param Object fromOrigin
+                * @return Object
+                */
+               originOffset: function(toOrigin, fromOrigin) {
+                       // the origin to translate to
+                       toOrigin = toOrigin ? toOrigin : new $.matrix.V2(
+                               this.outerWidth * 0.5,
+                               this.outerHeight * 0.5
+                       );
+                       
+                       // the origin to translate from (IE has a fixed origin of 0, 0)
+                       fromOrigin = fromOrigin ? fromOrigin : new $.matrix.V2(
+                               0,
+                               0
+                       );
+                       
+                       // transform the origins
+                       var toCenter = this.coord(toOrigin.e(1), toOrigin.e(2));
+                       var fromCenter = this.coord(fromOrigin.e(1), fromOrigin.e(2));
+                       
+                       // return the offset
+                       return {
+                               top: (fromCenter.e(2) - fromOrigin.e(2)) - (toCenter.e(2) - toOrigin.e(2)),
+                               left: (fromCenter.e(1) - fromOrigin.e(1)) - (toCenter.e(1) - toOrigin.e(1))
+                       };
+               }
+       };
+})(jQuery, this, this.document);
+///////////////////////////////////////////////////////
+// 2d Matrix Functions
+///////////////////////////////////////////////////////
+(function($, window, document, undefined) {
+       /**
+        * Matrix object for creating matrices relevant for 2d Transformations
+        * @var Object
+        */
+       if (typeof($.matrix) == 'undefined') {
+               $.extend({
+                       matrix: {}
+               });
+       }
+       var $m = $.matrix,
+               $m2x2 = $m.M2x2,
+               $m3x3 = $m.M3x3;
+       
+       $.extend( $m, {
+               /**
+                * Identity matrix
+                * @param Number size
+                * @return Matrix
+                */
+               identity: function(size) {
+                       size = size || 2;
+                       var length = size * size,
+                               elements = new Array(length),
+                               mod = size + 1;
+                       for (var i = 0; i < length; i++) {
+                               elements[i] = (i % mod) === 0 ? 1 : 0;
+                       }
+                       return new $m['M'+size+'x'+size](elements);
+               },
+               
+               /**
+                * Matrix
+                * @return Matrix
+                */
+               matrix: function() {
+                       var args = Array.prototype.slice.call(arguments);
+                       // arguments are in column-major order
+                       switch (arguments.length) {
+                               case 4:
+                                       return new $m2x2(
+                                               args[0], args[2],
+                                               args[1], args[3]
+                                       );
+                               case 6:
+                                       return new $m3x3(
+                                               args[0], args[2], args[4],
+                                               args[1], args[3], args[5],
+                                               0,       0,       1
+                                       );
+                       }
+               },
+               
+               /**
+                * Reflect (same as rotate(180))
+                * @return Matrix
+                */
+               reflect: function() {
+                       return new $m2x2(
+                               -1,  0,
+                                0, -1
+                       );
+               },
+               
+               /**
+                * Reflect across the x-axis (mirrored upside down)
+                * @return Matrix
+                */
+               reflectX: function() {  
+                       return new $m2x2(
+                               1,  0,
+                               0, -1
+                       );
+               },
+               
+               /**
+                * Reflect by swapping x an y (same as reflectX + rotate(-90))
+                * @return Matrix
+                */
+               reflectXY: function() {
+                       return new $m2x2(
+                               0, 1,
+                               1, 0
+                       );
+               },
+               
+               /**
+                * Reflect across the y-axis (mirrored)
+                * @return Matrix
+                */
+               reflectY: function() {
+                       return new $m2x2(
+                               -1, 0,
+                                0, 1
+                       );
+               },
+               
+               /**
+                * Rotates around the origin
+                * @param Number deg
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#RotationDefined
+                */
+               rotate: function(deg) {
+                       //TODO: detect units
+                       var rad = $.angle.degreeToRadian(deg),
+                               costheta = Math.cos(rad),
+                               sintheta = Math.sin(rad);
+                       
+                       var a = costheta,
+                               b = sintheta,
+                               c = -sintheta,
+                               d = costheta;
+                               
+                       return new $m2x2(
+                               a, c,
+                               b, d
+                       );
+               },
+               
+               /**
+                * Scale
+                * @param Number sx
+                * @param Number sy
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#ScalingDefined
+                */
+               scale: function (sx, sy) {
+                       sx = sx || sx === 0 ? sx : 1;
+                       sy = sy || sy === 0 ? sy : sx;
+                       
+                       return new $m2x2(
+                               sx, 0,
+                               0, sy
+                       );
+               },
+               
+               /**
+                * Scale on the X-axis
+                * @param Number sx
+                * @return Matrix
+                */
+               scaleX: function (sx) {
+                       return $m.scale(sx, 1);
+               },
+               
+               /**
+                * Scale on the Y-axis
+                * @param Number sy
+                * @return Matrix
+                */
+               scaleY: function (sy) {
+                       return $m.scale(1, sy);
+               },
+               
+               /**
+                * Skews on the X-axis and Y-axis
+                * @param Number degX
+                * @param Number degY
+                * @return Matrix
+                */
+               skew: function (degX, degY) {
+                       degX = degX || 0;
+                       degY = degY || 0;
+                       
+                       //TODO: detect units
+                       var radX = $.angle.degreeToRadian(degX),
+                               radY = $.angle.degreeToRadian(degY),
+                               x = Math.tan(radX),
+                               y = Math.tan(radY);
+                       
+                       return new $m2x2(
+                               1, x,
+                               y, 1
+                       );
+               },
+               
+               /**
+                * Skews on the X-axis
+                * @param Number degX
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#SkewXDefined
+                */
+               skewX: function (degX) {
+                       return $m.skew(degX);
+               },
+               
+               /**
+                * Skews on the Y-axis
+                * @param Number degY
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#SkewYDefined
+                */
+               skewY: function (degY) {
+                       return $m.skew(0, degY);
+               },
+               
+               /**
+                * Translate
+                * @param Number tx
+                * @param Number ty
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
+                */
+               translate: function (tx, ty) {
+                       tx = tx || 0;
+                       ty = ty || 0;
+                       
+                       return new $m3x3(
+                               1, 0, tx,
+                               0, 1, ty,
+                               0, 0, 1
+                       );
+               },
+               
+               /**
+                * Translate on the X-axis
+                * @param Number tx
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
+                */
+               translateX: function (tx) {
+                       return $m.translate(tx);
+               },
+               
+               /**
+                * Translate on the Y-axis
+                * @param Number ty
+                * @return Matrix
+                * @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
+                */
+               translateY: function (ty) {
+                       return $m.translate(0, ty);
+               }
+       });
+})(jQuery, this, this.document);
\ No newline at end of file
diff --git a/js/libs/jquery/jquery.transit.js b/js/libs/jquery/jquery.transit.js
new file mode 100644 (file)
index 0000000..1fb0bb7
--- /dev/null
@@ -0,0 +1,674 @@
+/*!
+ * jQuery Transit - CSS3 transitions and transformations
+ * Copyright(c) 2011 Rico Sta. Cruz <rico@ricostacruz.com>
+ * MIT Licensed.
+ *
+ * http://ricostacruz.com/jquery.transit
+ * http://github.com/rstacruz/jquery.transit
+ */
+
+(function($) {
+       "use strict";
+
+       $.transit = {
+               version: "0.1.3",
+               // Map of $.css() keys to values for 'transitionProperty'.
+               // See https://developer.mozilla.org/en/CSS/CSS_transitions#Properties_that_can_be_animated
+               propertyMap: {
+                       marginLeft: 'margin',
+                       marginRight: 'margin',
+                       marginBottom: 'margin',
+                       marginTop: 'margin',
+                       paddingLeft: 'padding',
+                       paddingRight: 'padding',
+                       paddingBottom: 'padding',
+                       paddingTop: 'padding'
+               },
+               // Will simply transition "instantly" if false
+               enabled: true,
+               // Set this to false if you don't want to use the transition end property.
+               useTransitionEnd: false
+       };
+
+       var div = document.createElement('div');
+       var support = {};
+
+       // Helper function to get the proper vendor property name.
+       // (`transition` => `WebkitTransition`)
+       function getVendorPropertyName(prop) {
+               var prefixes = ['Moz', 'Webkit', 'O', 'ms'];
+               var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1);
+
+               if (prop in div.style) {
+                       return prop;
+               }
+
+               for (var i = 0; i < prefixes.length; ++i) {
+                       var vendorProp = prefixes[i] + prop_;
+                       if (vendorProp in div.style) {
+                               return vendorProp;
+                       }
+               }
+       }
+
+       // Helper function to check if transform3D is supported.
+       // Should return true for Webkits and Firefox 10+.
+       function checkTransform3dSupport() {
+               div.style[support.transform] = '';
+               div.style[support.transform] = 'rotateY(90deg)';
+               return div.style[support.transform] !== '';
+       }
+
+       var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
+
+       // Check for the browser's transitions support.
+       // You can access this in jQuery's `$.support.transition`.
+       // As per [jQuery's cssHooks documentation](http://api.jquery.com/jQuery.cssHooks/),
+       // we set $.support.transition to a string of the actual property name used.
+       support.transition = getVendorPropertyName('transition');
+       support.transitionDelay = getVendorPropertyName('transitionDelay');
+       support.transform = getVendorPropertyName('transform');
+       support.transformOrigin = getVendorPropertyName('transformOrigin');
+       support.transform3d = checkTransform3dSupport();
+
+       $.extend($.support, support);
+
+       var eventNames = {
+               'MozTransition': 'transitionend',
+               'OTransition': 'oTransitionEnd',
+               'WebkitTransition': 'webkitTransitionEnd',
+               'msTransition': 'MSTransitionEnd'
+       };
+
+       // Detect the 'transitionend' event needed.
+       var transitionEnd = support.transitionEnd = eventNames[support.transition] || null;
+
+       // Avoid memory leak in IE.
+       div = null;
+
+       // ## $.cssEase
+       // List of easing aliases that you can use with `$.fn.transition`.
+       $.cssEase = {
+               '_default': 'ease',
+               'in': 'ease-in',
+               'out': 'ease-out',
+               'in-out': 'ease-in-out',
+               'snap': 'cubic-bezier(0,1,.5,1)'
+       };
+
+       // ## 'transform' CSS hook
+       // Allows you to use the `transform` property in CSS.
+       // 
+       //     $("#hello").css({ transform: "rotate(90deg)" });
+       //
+       //     $("#hello").css('transform');
+       //     //=> { rotate: '90deg' }
+       //
+       $.cssHooks.transform = {
+               // The getter returns a `Transform` object.
+               get: function(elem) {
+                       return $(elem).data('transform');
+               },
+               // The setter accepts a `Transform` object or a string.
+               set: function(elem, v) {
+                       var value = v;
+
+                       if (!(value instanceof Transform)) {
+                               value = new Transform(value);
+                       }
+
+                       elem.style[support.transform] = value.toString();
+
+
+                       $(elem).data('transform', value);
+               }
+       };
+
+       // ## 'transformOrigin' CSS hook
+       // Allows the use for `transformOrigin` to define where scaling and rotation
+       // is pivoted.
+       //
+       //     $("#hello").css({ transformOrigin: '0 0' });
+       //
+       $.cssHooks.transformOrigin = {
+               get: function(elem) {
+                       return elem.style[support.transformOrigin];
+               },
+               set: function(elem, value) {
+                       elem.style[support.transformOrigin] = value;
+               }
+       };
+
+       // ## Other CSS hooks
+       // Allows you to rotate, scale and translate.
+       registerCssHook('scale');
+       registerCssHook('translate');
+       registerCssHook('rotate');
+       registerCssHook('rotateX');
+       registerCssHook('rotateY');
+       registerCssHook('rotate3d');
+       registerCssHook('perspective');
+       registerCssHook('skewX');
+       registerCssHook('skewY');
+       registerCssHook('x', true);
+       registerCssHook('y', true);
+
+       // ## Transform class
+       // This is the main class of a transformation property that powers
+       // `$.fn.css({ transform: '...' })`.
+       //
+       // This is, in essence, a dictionary object with key/values as `-transform`
+       // properties.
+       //
+       //     var t = new Transform("rotate(90) scale(4)");
+       //
+       //     t.rotate             //=> "90deg"
+       //     t.scale              //=> "4,4"
+       //
+       // Setters are accounted for.
+       //
+       //     t.set('rotate', 4)
+       //     t.rotate             //=> "4deg"
+       //
+       // Convert it to a CSS string using the `toString()` and `toString(true)` (for WebKit)
+       // functions.
+       //
+       //     t.toString()         //=> "rotate(90deg) scale(4,4)"
+       //     t.toString(true)     //=> "rotate(90deg) scale3d(4,4,0)" (WebKit version)
+       //
+       function Transform(str) {
+               if (typeof str === 'string') {
+                       this.parse(str);
+               }
+               return this;
+       }
+
+       Transform.prototype = {
+               // ### setFromString()
+               // Sets a property from a string.
+               //
+               //     t.setFromString('scale', '2,4');
+               //     // Same as set('scale', '2', '4');
+               //
+               setFromString: function(prop, val) {
+                       var args =
+                                       (typeof val === 'string') ? val.split(',') :
+                                       (val.constructor === Array) ? val :
+                                       [val];
+
+                       args.unshift(prop);
+
+                       Transform.prototype.set.apply(this, args);
+               },
+               // ### set()
+               // Sets a property.
+               //
+               //     t.set('scale', 2, 4);
+               //
+               set: function(prop) {
+                       var args = Array.prototype.slice.apply(arguments, [1]);
+                       if (this.setter[prop]) {
+                               this.setter[prop].apply(this, args);
+                       } else {
+                               this[prop] = args.join(',');
+                       }
+               },
+               get: function(prop) {
+                       if (this.getter[prop]) {
+                               return this.getter[prop].apply(this);
+                       } else {
+                               return this[prop] || 0;
+                       }
+               },
+               setter: {
+                       // ### rotate
+                       //
+                       //     .css({ rotate: 30 })
+                       //     .css({ rotate: "30" })
+                       //     .css({ rotate: "30deg" })
+                       //     .css({ rotate: "30deg" })
+                       //
+                       rotate: function(theta) {
+                               this.rotate = unit(theta, 'deg');
+                       },
+                       rotateX: function(theta) {
+                               this.rotateX = unit(theta, 'deg');
+                       },
+                       rotateY: function(theta) {
+                               this.rotateY = unit(theta, 'deg');
+                       },
+                       // ### scale
+                       //
+                       //     .css({ scale: 9 })      //=> "scale(9,9)"
+                       //     .css({ scale: '3,2' })  //=> "scale(3,2)"
+                       //
+                       scale: function(x, y) {
+                               if (y === undefined) {
+                                       y = x;
+                               }
+                               this.scale = x + "," + y;
+                       },
+                       // ### skewX + skewY
+                       skewX: function(x) {
+                               this.skewX = unit(x, 'deg');
+                       },
+                       skewY: function(y) {
+                               this.skewY = unit(y, 'deg');
+                       },
+                       // ### perspectvie
+                       perspective: function(dist) {
+                               this.perspective = unit(dist, 'px');
+                       },
+                       // ### x / y
+                       // Translations. Notice how this keeps the other value.
+                       //
+                       //     .css({ x: 4 })       //=> "translate(4px, 0)"
+                       //     .css({ y: 10 })      //=> "translate(4px, 10px)"
+                       //
+                       x: function(x) {
+                               this.set('translate', x, null);
+                       },
+                       y: function(y) {
+                               this.set('translate', null, y);
+                       },
+                       // ### translate
+                       // Notice how this keeps the other value.
+                       //
+                       //     .css({ translate: '2, 5' })    //=> "translate(2px, 5px)"
+                       //
+                       translate: function(x, y) {
+                               if (this._translateX === undefined) {
+                                       this._translateX = 0;
+                               }
+                               if (this._translateY === undefined) {
+                                       this._translateY = 0;
+                               }
+
+                               if (x !== null) {
+                                       this._translateX = unit(x, 'px');
+                               }
+                               if (y !== null) {
+                                       this._translateY = unit(y, 'px');
+                               }
+
+                               this.translate = this._translateX + "," + this._translateY;
+                       }
+               },
+               getter: {
+                       x: function() {
+                               return this._translateX || 0;
+                       },
+                       y: function() {
+                               return this._translateY || 0;
+                       },
+                       scale: function() {
+                               var s = (this.scale || "1,1").split(',');
+                               if (s[0]) {
+                                       s[0] = parseFloat(s[0]);
+                               }
+                               if (s[1]) {
+                                       s[1] = parseFloat(s[1]);
+                               }
+
+                               // "2.5,2.5" => 2.5
+                               // "2.5,1" => [2.5,1]
+                               return (s[0] === s[1]) ? s[0] : s;
+                       },
+                       rotate3d: function() {
+                               var s = (this.rotate3d || "0,0,0,0deg").split(',');
+                               for (var i = 0; i <= 3; ++i) {
+                                       if (s[i]) {
+                                               s[i] = parseFloat(s[i]);
+                                       }
+                               }
+                               if (s[3]) {
+                                       s[3] = unit(s[3], 'deg');
+                               }
+
+                               return s;
+                       }
+               },
+               // ### parse()
+               // Parses from a string. Called on constructor.
+               parse: function(str) {
+                       var self = this;
+                       str.replace(/([a-zA-Z0-9]+)\((.*?)\)/g, function(x, prop, val) {
+                               self.setFromString(prop, val);
+                       });
+               },
+               // ### toString()
+               // Converts to a `transition` CSS property string. If `use3d` is given,
+               // it converts to a `-webkit-transition` CSS property string instead.
+               toString: function(use3d) {
+                       var re = [];
+
+                       for (var i in this) {
+                               if (this.hasOwnProperty(i)) {
+                                       // Don't use 3D transformations if the browser can't support it.
+                                       if ((!support.transform3d) && (
+                                                       (i === 'rotateX') ||
+                                                       (i === 'rotateY') ||
+                                                       (i === 'perspective') ||
+                                                       (i === 'transformOrigin'))) {
+                                               continue;
+                                       }
+
+                                       if (i[0] !== '_') {
+                                               if (use3d && (i === 'scale')) {
+                                                       re.push(i + "3d(" + this[i] + ",1)");
+                                               } else if (use3d && (i === 'translate')) {
+                                                       re.push(i + "3d(" + this[i] + ",0)");
+                                               } else {
+                                                       re.push(i + "(" + this[i] + ")");
+                                               }
+                                       }
+                               }
+                       }
+
+                       return re.join(" ");
+               }
+       };
+
+       function callOrQueue(self, queue, fn) {
+               if (queue === true) {
+                       self.queue(fn);
+               } else if (queue) {
+                       self.queue(queue, fn);
+               } else {
+                       fn();
+               }
+       }
+
+       // ### getProperties(dict)
+       // Returns properties (for `transition-property`) for dictionary `props`. The
+       // value of `props` is what you would expect in `$.css(...)`.
+       function getProperties(props) {
+               var re = [];
+
+               $.each(props, function(key) {
+                       key = $.camelCase(key); // Convert "text-align" => "textAlign"
+                       key = $.transit.propertyMap[key] || key;
+                       key = uncamel(key); // Convert back to dasherized
+
+                       if ($.inArray(key, re) === -1) {
+                               re.push(key);
+                       }
+               });
+
+               return re;
+       }
+
+       // ### getTransition()
+       // Returns the transition string to be used for the `transition` CSS property.
+       //
+       // Example:
+       //
+       //     getTransition({ opacity: 1, rotate: 30 }, 500, 'ease');
+       //     //=> 'opacity 500ms ease, -webkit-transform 500ms ease'
+       //
+       function getTransition(properties, duration, easing, delay) {
+               // Get the CSS properties needed.
+               var props = getProperties(properties);
+
+               // Account for aliases (`in` => `ease-in`).
+               if ($.cssEase[easing]) {
+                       easing = $.cssEase[easing];
+               }
+
+               // Build the duration/easing/delay attributes for it.
+               var attribs = '' + toMS(duration) + ' ' + easing;
+               if (parseInt(delay, 10) > 0) {
+                       attribs += ' ' + toMS(delay);
+               }
+
+               // For more properties, add them this way:
+               // "margin 200ms ease, padding 200ms ease, ..."
+               var transitions = [];
+               $.each(props, function(i, name) {
+                       transitions.push(name + ' ' + attribs);
+               });
+
+               return transitions.join(', ');
+       }
+
+       // ## $.fn.transition
+       // Works like $.fn.animate(), but uses CSS transitions.
+       //
+       //     $("...").transition({ opacity: 0.1, scale: 0.3 });
+       //
+       //     // Specific duration
+       //     $("...").transition({ opacity: 0.1, scale: 0.3 }, 500);
+       //
+       //     // With duration and easing
+       //     $("...").transition({ opacity: 0.1, scale: 0.3 }, 500, 'in');
+       //
+       //     // With callback
+       //     $("...").transition({ opacity: 0.1, scale: 0.3 }, function() { ... });
+       //
+       //     // With everything
+       //     $("...").transition({ opacity: 0.1, scale: 0.3 }, 500, 'in', function() { ... });
+       //
+       //     // Alternate syntax
+       //     $("...").transition({
+       //       opacity: 0.1,
+       //       duration: 200,
+       //       delay: 40,
+       //       easing: 'in',
+       //       complete: function() { /* ... */ }
+       //      });
+       //
+       $.fn.transition = $.fn.transit = function(properties, duration, easing, callback) {
+               var self = this;
+               var delay = 0;
+               var queue = true;
+
+               // Account for `.transition(properties, callback)`.
+               if (typeof duration === 'function') {
+                       callback = duration;
+                       duration = undefined;
+               }
+
+               // Account for `.transition(properties, duration, callback)`.
+               if (typeof easing === 'function') {
+                       callback = easing;
+                       easing = undefined;
+               }
+
+               // Alternate syntax.
+               if (typeof properties.easing !== 'undefined') {
+                       easing = properties.easing;
+                       delete properties.easing;
+               }
+
+               if (typeof properties.duration !== 'undefined') {
+                       duration = properties.duration;
+                       delete properties.duration;
+               }
+
+               if (typeof properties.complete !== 'undefined') {
+                       callback = properties.complete;
+                       delete properties.complete;
+               }
+
+               if (typeof properties.queue !== 'undefined') {
+                       queue = properties.queue;
+                       delete properties.queue;
+               }
+
+               if (typeof properties.delay !== 'undefined') {
+                       delay = properties.delay;
+                       delete properties.delay;
+               }
+
+               // Set defaults. (`400` duration, `ease` easing)
+               if (typeof duration === 'undefined') {
+                       duration = $.fx.speeds._default;
+               }
+               if (typeof easing === 'undefined') {
+                       easing = $.cssEase._default;
+               }
+
+               duration = toMS(duration);
+
+               // Build the `transition` property.
+               var transitionValue = getTransition(properties, duration, easing, delay);
+
+               // Compute delay until callback.
+               // If this becomes 0, don't bother setting the transition property.
+               var work = $.transit.enabled && support.transition;
+               var i = work ? (parseInt(duration, 10) + parseInt(delay, 10)) : 0;
+
+               // If there's nothing to do...
+               if (i === 0) {
+                       var fn = function(next) {
+                               self.css(properties);
+                               if (callback) {
+                                       callback();
+                               }
+                               next();
+                       };
+
+                       callOrQueue(self, queue, fn);
+                       return self;
+               }
+
+               // Save the old transitions of each element so we can restore it later.
+               var oldTransitions = {};
+
+               var run = function(nextCall) {
+                       var bound = false;
+
+                       // Prepare the callback.
+                       var cb = function() {
+                               if (bound) {
+                                       self.unbind(transitionEnd, cb);
+                               }
+
+                               if (i > 0) {
+                                       self.each(function() {
+                                               this.style[support.transition] = (oldTransitions[this] || null);
+                                       });
+                               }
+
+                               if (typeof callback === 'function') {
+                                       callback.apply(self);
+                               }
+                               if (typeof nextCall === 'function') {
+                                       nextCall();
+                               }
+                       };
+
+                       if ((i > 0) && (transitionEnd) && ($.transit.useTransitionEnd)) {
+                               // Use the 'transitionend' event if it's available.
+                               bound = true;
+                               self.bind(transitionEnd, cb);
+                       } else {
+                               // Fallback to timers if the 'transitionend' event isn't supported.
+                               window.setTimeout(cb, i);
+                       }
+
+                       // Apply transitions.
+                       self.each(function() {
+                               if (i > 0) {
+                                       this.style[support.transition] = transitionValue;
+                               }
+                               $(this).css(properties);
+                       });
+               };
+
+               // Defer running. This allows the browser to paint any pending CSS it hasn't
+               // painted yet before doing the transitions.
+               var deferredRun = function(next) {
+                       var i = 0;
+
+                       // Durations that are too slow will get transitions mixed up.
+                       // (Tested on Mac/FF 7.0.1)
+                       if ((support.transition === 'MozTransition') && (i < 25)) {
+                               i = 25;
+                       }
+
+                       window.setTimeout(function() {
+                               run(next);
+                       }, i);
+               };
+
+               // Use jQuery's fx queue.
+               callOrQueue(self, queue, deferredRun);
+
+               // Chainability.
+               return this;
+       };
+
+       function registerCssHook(prop, isPixels) {
+               // For certain properties, the 'px' should not be implied.
+               if (!isPixels) {
+                       $.cssNumber[prop] = true;
+               }
+
+               $.transit.propertyMap[prop] = support.transform;
+
+               $.cssHooks[prop] = {
+                       get: function(elem) {
+                               var t = $(elem).css('transform') || new Transform();
+                               return t.get(prop);
+                       },
+                       set: function(elem, value) {
+                               var t = $(elem).css('transform') || new Transform();
+                               try {
+                                       t.setFromString(prop, value);
+
+                               } catch (err) {
+
+                               }
+
+                               $(elem).css({
+                                       transform: t
+                               });
+                       }
+               };
+       }
+
+       // ### uncamel(str)
+       // Converts a camelcase string to a dasherized string.
+       // (`marginLeft` => `margin-left`)
+       function uncamel(str) {
+               return str.replace(/([A-Z])/g, function(letter) {
+                       return '-' + letter.toLowerCase();
+               });
+       }
+
+       // ### unit(number, unit)
+       // Ensures that number `number` has a unit. If no unit is found, assume the
+       // default is `unit`.
+       //
+       //     unit(2, 'px')          //=> "2px"
+       //     unit("30deg", 'rad')   //=> "30deg"
+       //
+       function unit(i, units) {
+               if ((typeof i === "string") && (!i.match(/^[\-0-9\.]+$/))) {
+                       return i;
+               } else {
+                       return "" + i + units;
+               }
+       }
+
+       // ### toMS(duration)
+       // Converts given `duration` to a millisecond string.
+       //
+       //     toMS('fast')   //=> '400ms'
+       //     toMS(10)       //=> '10ms'
+       //
+       function toMS(duration) {
+               var i = duration;
+
+               // Allow for string durations like 'fast'.
+               if ($.fx.speeds[i]) {
+                       i = $.fx.speeds[i];
+               }
+
+               return unit(i, 'ms');
+       }
+
+       // Export some functions for testable-ness.
+       $.transit.getTransitionValue = getTransition;
+})(jQuery);
diff --git a/js/libs/json2.js b/js/libs/json2.js
new file mode 100644 (file)
index 0000000..c7745df
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+    json2.js
+    2012-10-08
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (typeof JSON !== 'object') {
+    JSON = {};
+}
+
+(function () {
+    'use strict';
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf())
+                ? this.getUTCFullYear()     + '-' +
+                    f(this.getUTCMonth() + 1) + '-' +
+                    f(this.getUTCDate())      + 'T' +
+                    f(this.getUTCHours())     + ':' +
+                    f(this.getUTCMinutes())   + ':' +
+                    f(this.getUTCSeconds())   + 'Z'
+                : null;
+        };
+
+        String.prototype.toJSON      =
+            Number.prototype.toJSON  =
+            Boolean.prototype.toJSON = function (key) {
+                return this.valueOf();
+            };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string'
+                ? c
+                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0
+                    ? '[]'
+                    : gap
+                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+                    : '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0
+                ? '{}'
+                : gap
+                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+                : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                    typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.prototype.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/
+                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function'
+                    ? walk({'': j}, '')
+                    : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
diff --git a/js/libs/modernizr/modernizr.js b/js/libs/modernizr/modernizr.js
new file mode 100644 (file)
index 0000000..c41c11b
--- /dev/null
@@ -0,0 +1,815 @@
+/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
+ * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load
+ */
+;
+
+
+
+window.Modernizr = (function( window, document, undefined ) {
+
+    var version = '2.6.2',
+
+    Modernizr = {},
+
+    enableClasses = true,
+
+    docElement = document.documentElement,
+
+    mod = 'modernizr',
+    modElem = document.createElement(mod),
+    mStyle = modElem.style,
+
+    inputElem  = document.createElement('input')  ,
+
+    smile = ':)',
+
+    toString = {}.toString,
+
+    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
+
+
+
+    omPrefixes = 'Webkit Moz O ms',
+
+    cssomPrefixes = omPrefixes.split(' '),
+
+    domPrefixes = omPrefixes.toLowerCase().split(' '),
+
+    ns = {'svg': 'http://www.w3.org/2000/svg'},
+
+    tests = {},
+    inputs = {},
+    attrs = {},
+
+    classes = [],
+
+    slice = classes.slice,
+
+    featureName, 
+
+
+    injectElementWithStyles = function( rule, callback, nodes, testnames ) {
+
+      var style, ret, node, docOverflow,
+          div = document.createElement('div'),
+                body = document.body,
+                fakeBody = body || document.createElement('body');
+
+      if ( parseInt(nodes, 10) ) {
+                      while ( nodes-- ) {
+              node = document.createElement('div');
+              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
+              div.appendChild(node);
+          }
+      }
+
+                style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
+      div.id = mod;
+          (body ? div : fakeBody).innerHTML += style;
+      fakeBody.appendChild(div);
+      if ( !body ) {
+                fakeBody.style.background = '';
+                fakeBody.style.overflow = 'hidden';
+          docOverflow = docElement.style.overflow;
+          docElement.style.overflow = 'hidden';
+          docElement.appendChild(fakeBody);
+      }
+
+      ret = callback(div, rule);
+        if ( !body ) {
+          fakeBody.parentNode.removeChild(fakeBody);
+          docElement.style.overflow = docOverflow;
+      } else {
+          div.parentNode.removeChild(div);
+      }
+
+      return !!ret;
+
+    },
+
+
+
+    isEventSupported = (function() {
+
+      var TAGNAMES = {
+        'select': 'input', 'change': 'input',
+        'submit': 'form', 'reset': 'form',
+        'error': 'img', 'load': 'img', 'abort': 'img'
+      };
+
+      function isEventSupported( eventName, element ) {
+
+        element = element || document.createElement(TAGNAMES[eventName] || 'div');
+        eventName = 'on' + eventName;
+
+            var isSupported = eventName in element;
+
+        if ( !isSupported ) {
+                if ( !element.setAttribute ) {
+            element = document.createElement('div');
+          }
+          if ( element.setAttribute && element.removeAttribute ) {
+            element.setAttribute(eventName, '');
+            isSupported = is(element[eventName], 'function');
+
+                    if ( !is(element[eventName], 'undefined') ) {
+              element[eventName] = undefined;
+            }
+            element.removeAttribute(eventName);
+          }
+        }
+
+        element = null;
+        return isSupported;
+      }
+      return isEventSupported;
+    })(),
+
+
+    _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
+
+    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
+      hasOwnProp = function (object, property) {
+        return _hasOwnProperty.call(object, property);
+      };
+    }
+    else {
+      hasOwnProp = function (object, property) { 
+        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
+      };
+    }
+
+
+    if (!Function.prototype.bind) {
+      Function.prototype.bind = function bind(that) {
+
+        var target = this;
+
+        if (typeof target != "function") {
+            throw new TypeError();
+        }
+
+        var args = slice.call(arguments, 1),
+            bound = function () {
+
+            if (this instanceof bound) {
+
+              var F = function(){};
+              F.prototype = target.prototype;
+              var self = new F();
+
+              var result = target.apply(
+                  self,
+                  args.concat(slice.call(arguments))
+              );
+              if (Object(result) === result) {
+                  return result;
+              }
+              return self;
+
+            } else {
+
+              return target.apply(
+                  that,
+                  args.concat(slice.call(arguments))
+              );
+
+            }
+
+        };
+
+        return bound;
+      };
+    }
+
+    function setCss( str ) {
+        mStyle.cssText = str;
+    }
+
+    function setCssAll( str1, str2 ) {
+        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
+    }
+
+    function is( obj, type ) {
+        return typeof obj === type;
+    }
+
+    function contains( str, substr ) {
+        return !!~('' + str).indexOf(substr);
+    }
+
+    function testProps( props, prefixed ) {
+        for ( var i in props ) {
+            var prop = props[i];
+            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
+                return prefixed == 'pfx' ? prop : true;
+            }
+        }
+        return false;
+    }
+
+    function testDOMProps( props, obj, elem ) {
+        for ( var i in props ) {
+            var item = obj[props[i]];
+            if ( item !== undefined) {
+
+                            if (elem === false) return props[i];
+
+                            if (is(item, 'function')){
+                                return item.bind(elem || obj);
+                }
+
+                            return item;
+            }
+        }
+        return false;
+    }
+
+    function testPropsAll( prop, prefixed, elem ) {
+
+        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
+            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
+
+            if(is(prefixed, "string") || is(prefixed, "undefined")) {
+          return testProps(props, prefixed);
+
+            } else {
+          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
+          return testDOMProps(props, prefixed, elem);
+        }
+    }    tests['flexbox'] = function() {
+      return testPropsAll('flexWrap');
+    };    tests['canvas'] = function() {
+        var elem = document.createElement('canvas');
+        return !!(elem.getContext && elem.getContext('2d'));
+    };
+
+    tests['canvastext'] = function() {
+        return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
+    };
+
+
+
+    tests['webgl'] = function() {
+        return !!window.WebGLRenderingContext;
+    };
+
+
+    tests['touch'] = function() {
+        var bool;
+
+        if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+          bool = true;
+        } else {
+          injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
+            bool = node.offsetTop === 9;
+          });
+        }
+
+        return bool;
+    };
+
+
+
+    tests['geolocation'] = function() {
+        return 'geolocation' in navigator;
+    };
+
+
+    tests['postmessage'] = function() {
+      return !!window.postMessage;
+    };
+
+
+    tests['websqldatabase'] = function() {
+      return !!window.openDatabase;
+    };
+
+    tests['indexedDB'] = function() {
+      return !!testPropsAll("indexedDB", window);
+    };
+
+    tests['hashchange'] = function() {
+      return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
+    };
+
+    tests['history'] = function() {
+      return !!(window.history && history.pushState);
+    };
+
+    tests['draganddrop'] = function() {
+        var div = document.createElement('div');
+        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
+    };
+
+    tests['websockets'] = function() {
+        return 'WebSocket' in window || 'MozWebSocket' in window;
+    };
+
+
+    tests['rgba'] = function() {
+        setCss('background-color:rgba(150,255,150,.5)');
+
+        return contains(mStyle.backgroundColor, 'rgba');
+    };
+
+    tests['hsla'] = function() {
+            setCss('background-color:hsla(120,40%,100%,.5)');
+
+        return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
+    };
+
+    tests['multiplebgs'] = function() {
+                setCss('background:url(https://),url(https://),red url(https://)');
+
+            return (/(url\s*\(.*?){3}/).test(mStyle.background);
+    };    tests['backgroundsize'] = function() {
+        return testPropsAll('backgroundSize');
+    };
+
+    tests['borderimage'] = function() {
+        return testPropsAll('borderImage');
+    };
+
+
+
+    tests['borderradius'] = function() {
+        return testPropsAll('borderRadius');
+    };
+
+    tests['boxshadow'] = function() {
+        return testPropsAll('boxShadow');
+    };
+
+    tests['textshadow'] = function() {
+        return document.createElement('div').style.textShadow === '';
+    };
+
+
+    tests['opacity'] = function() {
+                setCssAll('opacity:.55');
+
+                    return (/^0.55$/).test(mStyle.opacity);
+    };
+
+
+    tests['cssanimations'] = function() {
+        return testPropsAll('animationName');
+    };
+
+
+    tests['csscolumns'] = function() {
+        return testPropsAll('columnCount');
+    };
+
+
+    tests['cssgradients'] = function() {
+        var str1 = 'background-image:',
+            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
+            str3 = 'linear-gradient(left top,#9f9, white);';
+
+        setCss(
+                       (str1 + '-webkit- '.split(' ').join(str2 + str1) +
+                       prefixes.join(str3 + str1)).slice(0, -str1.length)
+        );
+
+        return contains(mStyle.backgroundImage, 'gradient');
+    };
+
+
+    tests['cssreflections'] = function() {
+        return testPropsAll('boxReflect');
+    };
+
+
+    tests['csstransforms'] = function() {
+        return !!testPropsAll('transform');
+    };
+
+
+    tests['csstransforms3d'] = function() {
+
+        var ret = !!testPropsAll('perspective');
+
+                        if ( ret && 'webkitPerspective' in docElement.style ) {
+
+                      injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
+            ret = node.offsetLeft === 9 && node.offsetHeight === 3;
+          });
+        }
+        return ret;
+    };
+
+
+    tests['csstransitions'] = function() {
+        return testPropsAll('transition');
+    };
+
+
+
+    tests['fontface'] = function() {
+        var bool;
+
+        injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
+          var style = document.getElementById('smodernizr'),
+              sheet = style.sheet || style.styleSheet,
+              cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
+
+          bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
+        });
+
+        return bool;
+    };
+
+    tests['generatedcontent'] = function() {
+        var bool;
+
+        injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
+          bool = node.offsetHeight >= 3;
+        });
+
+        return bool;
+    };
+    tests['video'] = function() {
+        var elem = document.createElement('video'),
+            bool = false;
+
+            try {
+            if ( bool = !!elem.canPlayType ) {
+                bool      = new Boolean(bool);
+                bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"')      .replace(/^no$/,'');
+
+                            bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
+
+                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
+            }
+
+        } catch(e) { }
+
+        return bool;
+    };
+
+    tests['audio'] = function() {
+        var elem = document.createElement('audio'),
+            bool = false;
+
+        try {
+            if ( bool = !!elem.canPlayType ) {
+                bool      = new Boolean(bool);
+                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
+                bool.mp3  = elem.canPlayType('audio/mpeg;')               .replace(/^no$/,'');
+
+                                                    bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/,'');
+                bool.m4a  = ( elem.canPlayType('audio/x-m4a;')            ||
+                              elem.canPlayType('audio/aac;'))             .replace(/^no$/,'');
+            }
+        } catch(e) { }
+
+        return bool;
+    };
+
+
+    tests['localstorage'] = function() {
+        try {
+            localStorage.setItem(mod, mod);
+            localStorage.removeItem(mod);
+            return true;
+        } catch(e) {
+            return false;
+        }
+    };
+
+    tests['sessionstorage'] = function() {
+        try {
+            sessionStorage.setItem(mod, mod);
+            sessionStorage.removeItem(mod);
+            return true;
+        } catch(e) {
+            return false;
+        }
+    };
+
+
+    tests['webworkers'] = function() {
+        return !!window.Worker;
+    };
+
+
+    tests['applicationcache'] = function() {
+        return !!window.applicationCache;
+    };
+
+
+    tests['svg'] = function() {
+        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
+    };
+
+    tests['inlinesvg'] = function() {
+      var div = document.createElement('div');
+      div.innerHTML = '<svg/>';
+      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
+    };
+
+    tests['smil'] = function() {
+        return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
+    };
+
+
+    tests['svgclippaths'] = function() {
+        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
+    };
+
+    function webforms() {
+                                            Modernizr['input'] = (function( props ) {
+            for ( var i = 0, len = props.length; i < len; i++ ) {
+                attrs[ props[i] ] = !!(props[i] in inputElem);
+            }
+            if (attrs.list){
+                                  attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
+            }
+            return attrs;
+        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
+                            Modernizr['inputtypes'] = (function(props) {
+
+            for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
+
+                inputElem.setAttribute('type', inputElemType = props[i]);
+                bool = inputElem.type !== 'text';
+
+                                                    if ( bool ) {
+
+                    inputElem.value         = smile;
+                    inputElem.style.cssText = 'position:absolute;visibility:hidden;';
+
+                    if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
+
+                      docElement.appendChild(inputElem);
+                      defaultView = document.defaultView;
+
+                                        bool =  defaultView.getComputedStyle &&
+                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
+                                                                                  (inputElem.offsetHeight !== 0);
+
+                      docElement.removeChild(inputElem);
+
+                    } else if ( /^(search|tel)$/.test(inputElemType) ){
+                                                                                    } else if ( /^(url|email)$/.test(inputElemType) ) {
+                                        bool = inputElem.checkValidity && inputElem.checkValidity() === false;
+
+                    } else {
+                                        bool = inputElem.value != smile;
+                    }
+                }
+
+                inputs[ props[i] ] = !!bool;
+            }
+            return inputs;
+        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
+        }
+    for ( var feature in tests ) {
+        if ( hasOwnProp(tests, feature) ) {
+                                    featureName  = feature.toLowerCase();
+            Modernizr[featureName] = tests[feature]();
+
+            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
+        }
+    }
+
+    Modernizr.input || webforms();
+
+
+     Modernizr.addTest = function ( feature, test ) {
+       if ( typeof feature == 'object' ) {
+         for ( var key in feature ) {
+           if ( hasOwnProp( feature, key ) ) {
+             Modernizr.addTest( key, feature[ key ] );
+           }
+         }
+       } else {
+
+         feature = feature.toLowerCase();
+
+         if ( Modernizr[feature] !== undefined ) {
+                                              return Modernizr;
+         }
+
+         test = typeof test == 'function' ? test() : test;
+
+         if (typeof enableClasses !== "undefined" && enableClasses) {
+           docElement.className += ' ' + (test ? '' : 'no-') + feature;
+         }
+         Modernizr[feature] = test;
+
+       }
+
+       return Modernizr; 
+     };
+
+
+    setCss('');
+    modElem = inputElem = null;
+
+    ;(function(window, document) {
+        var options = window.html5 || {};
+
+        var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
+
+        var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
+
+        var supportsHtml5Styles;
+
+        var expando = '_html5shiv';
+
+        var expanID = 0;
+
+        var expandoData = {};
+
+        var supportsUnknownElements;
+
+      (function() {
+        try {
+            var a = document.createElement('a');
+            a.innerHTML = '<xyz></xyz>';
+                    supportsHtml5Styles = ('hidden' in a);
+
+            supportsUnknownElements = a.childNodes.length == 1 || (function() {
+                        (document.createElement)('a');
+              var frag = document.createDocumentFragment();
+              return (
+                typeof frag.cloneNode == 'undefined' ||
+                typeof frag.createDocumentFragment == 'undefined' ||
+                typeof frag.createElement == 'undefined'
+              );
+            }());
+        } catch(e) {
+          supportsHtml5Styles = true;
+          supportsUnknownElements = true;
+        }
+
+      }());        function addStyleSheet(ownerDocument, cssText) {
+        var p = ownerDocument.createElement('p'),
+            parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
+
+        p.innerHTML = 'x<style>' + cssText + '</style>';
+        return parent.insertBefore(p.lastChild, parent.firstChild);
+      }
+
+        function getElements() {
+        var elements = html5.elements;
+        return typeof elements == 'string' ? elements.split(' ') : elements;
+      }
+
+          function getExpandoData(ownerDocument) {
+        var data = expandoData[ownerDocument[expando]];
+        if (!data) {
+            data = {};
+            expanID++;
+            ownerDocument[expando] = expanID;
+            expandoData[expanID] = data;
+        }
+        return data;
+      }
+
+        function createElement(nodeName, ownerDocument, data){
+        if (!ownerDocument) {
+            ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+            return ownerDocument.createElement(nodeName);
+        }
+        if (!data) {
+            data = getExpandoData(ownerDocument);
+        }
+        var node;
+
+        if (data.cache[nodeName]) {
+            node = data.cache[nodeName].cloneNode();
+        } else if (saveClones.test(nodeName)) {
+            node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
+        } else {
+            node = data.createElem(nodeName);
+        }
+
+                                    return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node;
+      }
+
+        function createDocumentFragment(ownerDocument, data){
+        if (!ownerDocument) {
+            ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+            return ownerDocument.createDocumentFragment();
+        }
+        data = data || getExpandoData(ownerDocument);
+        var clone = data.frag.cloneNode(),
+            i = 0,
+            elems = getElements(),
+            l = elems.length;
+        for(;i<l;i++){
+            clone.createElement(elems[i]);
+        }
+        return clone;
+      }
+
+        function shivMethods(ownerDocument, data) {
+        if (!data.cache) {
+            data.cache = {};
+            data.createElem = ownerDocument.createElement;
+            data.createFrag = ownerDocument.createDocumentFragment;
+            data.frag = data.createFrag();
+        }
+
+
+        ownerDocument.createElement = function(nodeName) {
+                if (!html5.shivMethods) {
+              return data.createElem(nodeName);
+          }
+          return createElement(nodeName, ownerDocument, data);
+        };
+
+        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
+          'var n=f.cloneNode(),c=n.createElement;' +
+          'h.shivMethods&&(' +
+                    getElements().join().replace(/\w+/g, function(nodeName) {
+              data.createElem(nodeName);
+              data.frag.createElement(nodeName);
+              return 'c("' + nodeName + '")';
+            }) +
+          ');return n}'
+        )(html5, data.frag);
+      }        function shivDocument(ownerDocument) {
+        if (!ownerDocument) {
+            ownerDocument = document;
+        }
+        var data = getExpandoData(ownerDocument);
+
+        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
+          data.hasCSS = !!addStyleSheet(ownerDocument,
+                    'article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}' +
+                    'mark{background:#FF0;color:#000}'
+          );
+        }
+        if (!supportsUnknownElements) {
+          shivMethods(ownerDocument, data);
+        }
+        return ownerDocument;
+      }        var html5 = {
+
+            'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video',
+
+            'shivCSS': (options.shivCSS !== false),
+
+            'supportsUnknownElements': supportsUnknownElements,
+
+            'shivMethods': (options.shivMethods !== false),
+
+            'type': 'default',
+
+            'shivDocument': shivDocument,
+
+            createElement: createElement,
+
+            createDocumentFragment: createDocumentFragment
+      };        window.html5 = html5;
+
+        shivDocument(document);
+
+    }(this, document));
+
+    Modernizr._version      = version;
+
+    Modernizr._prefixes     = prefixes;
+    Modernizr._domPrefixes  = domPrefixes;
+    Modernizr._cssomPrefixes  = cssomPrefixes;
+
+
+    Modernizr.hasEvent      = isEventSupported;
+
+    Modernizr.testProp      = function(prop){
+        return testProps([prop]);
+    };
+
+    Modernizr.testAllProps  = testPropsAll;
+
+
+    Modernizr.testStyles    = injectElementWithStyles;
+    Modernizr.prefixed      = function(prop, obj, elem){
+      if(!obj) {
+        return testPropsAll(prop, 'pfx');
+      } else {
+            return testPropsAll(prop, obj, elem);
+      }
+    };
+
+
+    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
+
+                                                    (enableClasses ? ' js ' + classes.join(' ') : '');
+
+    return Modernizr;
+
+})(this, this.document);
+/*yepnope1.5.4|WTFPL*/
+(function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}})(this,document);
+Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0));};
+;
\ No newline at end of file
diff --git a/js/libs/modernizr/tests.js b/js/libs/modernizr/tests.js
new file mode 100644 (file)
index 0000000..b4bf889
--- /dev/null
@@ -0,0 +1,32 @@
+Modernizr.addTest('csstransformspreserve3d', function() {
+       var prop,
+                       val,
+                       cssText,
+                       ret;
+
+       prop = 'transform-style';
+       if ('webkitTransformStyle' in document.documentElement.style) {
+               prop = '-webkit-' + prop;
+       }
+       val = 'preserve-3d';
+       cssText = '#modernizr { ' + prop + ': ' + val + '; }';
+       Modernizr.testStyles(cssText, function(el, rule) {
+               ret = window.getComputedStyle ? getComputedStyle(el, null).getPropertyValue(prop) : '';
+       });
+       return (ret === val);
+});
+
+Modernizr.addTest('ftouch', function() {
+    var bool;
+
+    if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch || ('onmsgesturechange' in window)) {
+        bool = true;
+    } else {
+        var query = ['@media (',Modernizr._prefixes.join('touch-enabled),('),'heartz',')','{#modernizr{top:9px;position:absolute}}'].join('');
+        Modernizr.testStyles(query, function( node ) {
+            bool = node.offsetTop === 9;
+        });
+    }
+
+    return bool;
+});
\ No newline at end of file
diff --git a/js/libs/phonegap/2.8.1/cordova-android.js b/js/libs/phonegap/2.8.1/cordova-android.js
new file mode 100644 (file)
index 0000000..5e460e4
--- /dev/null
@@ -0,0 +1,6878 @@
+// Platform: android
+// 2.8.0-0-g6208c95
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+     http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+;(function() {
+var CORDOVA_JS_BUILD_LABEL = '2.8.0-0-g6208c95';
+// file: lib/scripts/require.js
+
+var require,
+    define;
+
+(function () {
+    var modules = {},
+    // Stack of moduleIds currently being built.
+        requireStack = [],
+    // Map of module ID -> index into requireStack of modules currently being built.
+        inProgressModules = {},
+        SEPERATOR = ".";
+
+
+
+    function build(module) {
+        var factory = module.factory,
+            localRequire = function (id) {
+                var resultantId = id;
+                //Its a relative path, so lop off the last portion and add the id (minus "./")
+                if (id.charAt(0) === ".") {
+                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2);
+                }
+                return require(resultantId);
+            };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw "module " + id + " not found";
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw "Cycle in require graph: " + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw "module " + id + " already defined";
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+    channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+    channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+    windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] != 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] != 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] != "undefined") {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] != "undefined") {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent(type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+if(typeof window.console === "undefined") {
+    window.console = {
+        log:function(){}
+    };
+}
+
+var cordova = {
+    define:define,
+    require:require,
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler:function(event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler:function(event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler:function(event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function() {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function(type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] != 'undefined') {
+            if( bNoDetach ) {
+              documentEventHandlers[type].fire(evt);
+            }
+            else {
+              setTimeout(function() {
+                  // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                  if (type == 'deviceready') {
+                      document.dispatchEvent(evt);
+                  }
+                  documentEventHandlers[type].fire(evt);
+              }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function(type, data) {
+        var evt = createEvent(type,data);
+        if (typeof windowEventHandlers[type] != 'undefined') {
+            setTimeout(function() {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks:  {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function(callbackId, args) {
+        try {
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function(callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        try {
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+        var callback = cordova.callbacks[callbackId];
+        if (callback) {
+            if (success && status == cordova.callbackStatus.OK) {
+                callback.success && callback.success.apply(null, args);
+            } else if (!success) {
+                callback.fail && callback.fail.apply(null, args);
+            }
+
+            // Clear callback if not expecting any more results
+            if (!keepCallback) {
+                delete cordova.callbacks[callbackId];
+            }
+        }
+    },
+    addConstructor: function(func) {
+        channel.onCordovaReady.subscribe(function() {
+            try {
+                func();
+            } catch(e) {
+                console.log("Failed to run constructor: " + e);
+            }
+        });
+    }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+  return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i),
+            cUpper = c.toUpperCase(),
+            arg = args[i];
+        // Asterix means allow anything.
+        if (c == '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c == cUpper) {
+            continue;
+        }
+        if (typeName != typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running jake test.
+        if (typeof jasmine == 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue(value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    obj[key] = value;
+    // Getters can only be overridden by getters.
+    if (obj[key] !== value) {
+        utils.defineGetter(obj, key, function() {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function() {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include(parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+          var result = obj.path ? require(obj.path) : {};
+
+          if (clobber) {
+              // Clobber if it doesn't exist.
+              if (typeof parent[key] === 'undefined') {
+                  assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+              } else if (typeof obj.path !== 'undefined') {
+                  // If merging, merge properties onto parent, otherwise, clobber.
+                  if (merge) {
+                      recursiveMerge(parent[key], result);
+                  } else {
+                      assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                  }
+              }
+              result = parent[key];
+          } else {
+            // Overwrite if not currently defined.
+            if (typeof parent[key] == 'undefined') {
+              assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+            } else {
+              // Set result to what already exists, so we can build children into it if they exist.
+              result = parent[key];
+            }
+          }
+
+          if (obj.children) {
+            include(result, obj.children, clobber, merge);
+          }
+        } catch(e) {
+          utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady*         Internal event fired when device properties are available.
+ * onCordovaConnectionReady*   Internal event fired when the connection property has been set.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function(type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+},
+    channel = {
+        /**
+         * Calls the provided function only after all of the channels specified
+         * have been fired. All channels must be sticky channels.
+         */
+        join: function(h, c) {
+            var len = c.length,
+                i = len,
+                f = function() {
+                    if (!(--i)) h();
+                };
+            for (var j=0; j<len; j++) {
+                if (c[j].state === 0) {
+                    throw Error('Can only use join with sticky channels.');
+                }
+                c[j].subscribe(f);
+            }
+            if (!len) h();
+        },
+        create: function(type) {
+            return channel[type] = new Channel(type, false);
+        },
+        createSticky: function(type) {
+            return channel[type] = new Channel(type, true);
+        },
+
+        /**
+         * cordova Channels that must fire before "deviceready" is fired.
+         */
+        deviceReadyChannelsArray: [],
+        deviceReadyChannelsMap: {},
+
+        /**
+         * Indicate that a feature needs to be initialized before it is ready to be used.
+         * This holds up Cordova's "deviceready" event until the feature has been initialized
+         * and Cordova.initComplete(feature) is called.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        waitForInitialization: function(feature) {
+            if (feature) {
+                var c = channel[feature] || this.createSticky(feature);
+                this.deviceReadyChannelsMap[feature] = c;
+                this.deviceReadyChannelsArray.push(c);
+            }
+        },
+
+        /**
+         * Indicate that initialization code has completed and the feature is ready to be used.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        initializationComplete: function(feature) {
+            var c = this.deviceReadyChannelsMap[feature];
+            if (c) {
+                c.fire();
+            }
+        }
+    };
+
+function forceFunction(f) {
+    if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+    // need a function to call
+    forceFunction(f);
+    if (this.state == 2) {
+        f.apply(c || this, this.fireArgs);
+        return;
+    }
+
+    var func = f,
+        guid = f.observer_guid;
+    if (typeof c == "object") { func = utils.close(c, f); }
+
+    if (!guid) {
+        // first time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    func.observer_guid = guid;
+    f.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = func;
+        this.numHandlers++;
+        if (this.numHandlers == 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+    // need a function to unsubscribe
+    forceFunction(f);
+
+    var guid = f.observer_guid,
+        handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+    var fail = false,
+        fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state == 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state == 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib/common/commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add:function(id,proxyObj) {
+        console.log("adding proxy for " + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove:function(id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get:function(service,action) {
+        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+    }
+};
+});
+
+// file: lib/android/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1,
+        // This mode is currently for benchmarking purposes only. It must be enabled
+        // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
+        // constant within CordovaWebViewClient.java before it will work.
+        LOCATION_CHANGE: 2
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        // Uses reflection to access private APIs of the WebView that can send JS
+        // to be executed.
+        // Requires Android 3.2.4 or above.
+        PRIVATE_API: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
+    pollEnabled = false,
+    messagesFromNative = [];
+
+function androidExec(success, fail, service, action, args) {
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i])));
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
+        window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
+    } else {
+        var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
+        // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+        // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+        if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+            androidExec(success, fail, service, action, args);
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+            return;
+        } else {
+            androidExec.processMessages(messages);
+        }
+    }
+}
+
+function pollOnce() {
+    var msg = nativeApiProvider.get().retrieveJsMessages();
+    androidExec.processMessages(msg);
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnce, false);
+    window.addEventListener('offline', pollOnce, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    nativeApiProvider.get().setNativeToJsBridgeMode(mode);
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    try {
+        var firstChar = message.charAt(0);
+        if (firstChar == 'J') {
+            eval(message.slice(1));
+        } else if (firstChar == 'S' || firstChar == 'F') {
+            var success = firstChar == 'S';
+            var keepCallback = message.charAt(1) == '1';
+            var spaceIdx = message.indexOf(' ', 2);
+            var status = +message.slice(2, spaceIdx);
+            var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+            var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+            var payloadKind = message.charAt(nextSpaceIdx + 1);
+            var payload;
+            if (payloadKind == 's') {
+                payload = message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 't') {
+                payload = true;
+            } else if (payloadKind == 'f') {
+                payload = false;
+            } else if (payloadKind == 'N') {
+                payload = null;
+            } else if (payloadKind == 'n') {
+                payload = +message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 'A') {
+                var data = message.slice(nextSpaceIdx + 2);
+                var bytes = window.atob(data);
+                var arraybuffer = new Uint8Array(bytes.length);
+                for (var i = 0; i < bytes.length; i++) {
+                    arraybuffer[i] = bytes.charCodeAt(i);
+                }
+                payload = arraybuffer.buffer;
+            } else if (payloadKind == 'S') {
+                payload = window.atob(message.slice(nextSpaceIdx + 2));
+            } else {
+                payload = JSON.parse(message.slice(nextSpaceIdx + 1));
+            }
+            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
+        } else {
+            console.log("processMessage failed: invalid message:" + message);
+        }
+    } catch (e) {
+        console.log("processMessage failed: Message: " + message);
+        console.log("processMessage failed: Error: " + e);
+        console.log("processMessage failed: Stack: " + e.stack);
+    }
+}
+
+// This is called from the NativeToJsMessageQueue.java.
+androidExec.processMessages = function(messages) {
+    if (messages) {
+        messagesFromNative.push(messages);
+        // Check for the reentrant case, and enqueue the message if that's the case.
+        if (messagesFromNative.length > 1) {
+            return;
+        }
+        while (messagesFromNative.length) {
+            // Don't unshift until the end so that reentrancy can be detected.
+            messages = messagesFromNative[0];
+            // The Java side can send a * message to indicate that it
+            // still has messages waiting to be retrieved.
+            if (messages == '*') {
+                messagesFromNative.shift();
+                window.setTimeout(pollOnce, 0);
+                return;
+            }
+
+            var spaceIdx = messages.indexOf(' ');
+            var msgLen = +messages.slice(0, spaceIdx);
+            var message = messages.substr(spaceIdx + 1, msgLen);
+            messages = messages.slice(spaceIdx + msgLen + 1);
+            processMessage(message);
+            if (messages) {
+                messagesFromNative[0] = messages;
+            } else {
+                messagesFromNative.shift();
+            }
+        }
+    }
+};
+
+module.exports = androidExec;
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+    moduleMap = define.moduleMap,
+    symbolList,
+    deprecationMap;
+
+exports.reset = function() {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) {
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function(context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var module = require(moduleName);
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy == 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+    for (var k in moduleMap) {
+        if (matchingRegExp.exec(k)) {
+            require(k);
+        }
+    }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/android/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+    id: "android",
+    initialize:function() {
+        var channel = require("cordova/channel"),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        modulemapper.mapModules(window);
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.join(function() {
+            exec(null, null, "App", "show", []);
+        }, [channel.onCordovaReady]);
+    }
+};
+
+});
+
+// file: lib/common/plugin/Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+    this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib/common/plugin/Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    Camera = require('cordova/plugin/CameraConstants'),
+    CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+    cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var quality = getValue(options.quality, 50);
+    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+    var targetWidth = getValue(options.targetWidth, -1);
+    var targetHeight = getValue(options.targetHeight, -1);
+    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+    var allowEdit = !!options.allowEdit;
+    var correctOrientation = !!options.correctOrientation;
+    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+    var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+    exec(successCallback, errorCallback, "Camera", "takePicture", args);
+    return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+    exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib/common/plugin/CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+  DestinationType:{
+    DATA_URL: 0,         // Return base64 encoded string
+    FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
+    NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
+  },
+  EncodingType:{
+    JPEG: 0,             // Return JPEG encoded image
+    PNG: 1               // Return PNG encoded image
+  },
+  MediaType:{
+    PICTURE: 0,          // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+    VIDEO: 1,            // allow selection of video only, ONLY RETURNS URL
+    ALLMEDIA : 2         // allow selection from all media types
+  },
+  PictureSourceType:{
+    PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+    CAMERA : 1,          // Take picture from camera
+    SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
+  },
+  PopoverArrowDirection:{
+      ARROW_UP : 1,        // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+      ARROW_DOWN : 2,
+      ARROW_LEFT : 4,
+      ARROW_RIGHT : 8,
+      ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
+  }
+};
+
+});
+
+// file: lib/common/plugin/CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+    this.setPosition = function(popoverOptions) {
+        console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+    };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib/common/plugin/CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+    // information of rectangle that popover should be anchored to
+    this.x = x || 0;
+    this.y = y || 32;
+    this.width = width || 320;
+    this.height = height || 480;
+    // The direction of the popover arrow
+    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib/common/plugin/CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+    // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single sound clip in seconds.
+    this.duration = 0;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib/common/plugin/CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+   this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib/common/plugin/CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+    // Upper limit of images user can take. Value must be equal or greater than 1.
+    this.limit = 1;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib/common/plugin/CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+    // Upper limit of videos user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single video clip in seconds.
+    this.duration = 0;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib/common/plugin/CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ *  CompassError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+    this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib/common/plugin/CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
+  this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib/common/plugin/ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+    // The ASCII-encoded string in lower case representing the media type.
+    this.type = null;
+    // The height attribute represents height of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0.
+    this.height = 0;
+    // The width attribute represents width of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0
+    this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib/common/plugin/Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+        UNKNOWN: "unknown",
+        ETHERNET: "ethernet",
+        WIFI: "wifi",
+        CELL_2G: "2g",
+        CELL_3G: "3g",
+        CELL_4G: "4g",
+        CELL:"cellular",
+        NONE: "none"
+};
+
+});
+
+// file: lib/common/plugin/Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError'),
+    utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+    var value = contact.birthday;
+    try {
+      contact.birthday = new Date(parseFloat(value));
+    } catch (exception){
+      console.log("Cordova Contact convertIn error: exception creating date.");
+    }
+    return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+    var value = contact.birthday;
+    if (value !== null) {
+        // try to make it a Date object if it is not already
+        if (!utils.isDate(value)){
+            try {
+                value = new Date(value);
+            } catch(exception){
+                value = null;
+            }
+        }
+        if (utils.isDate(value)){
+            value = value.valueOf(); // convert to milliseconds
+        }
+        contact.birthday = value;
+    }
+    return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+    ims, organizations, birthday, note, photos, categories, urls) {
+    this.id = id || null;
+    this.rawId = null;
+    this.displayName = displayName || null;
+    this.name = name || null; // ContactName
+    this.nickname = nickname || null;
+    this.phoneNumbers = phoneNumbers || null; // ContactField[]
+    this.emails = emails || null; // ContactField[]
+    this.addresses = addresses || null; // ContactAddress[]
+    this.ims = ims || null; // ContactField[]
+    this.organizations = organizations || null; // ContactOrganization[]
+    this.birthday = birthday || null;
+    this.note = note || null;
+    this.photos = photos || null; // ContactField[]
+    this.categories = categories || null; // ContactField[]
+    this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+    argscheck.checkArgs('FF', 'Contact.remove', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    if (this.id === null) {
+        fail(ContactError.UNKNOWN_ERROR);
+    }
+    else {
+        exec(successCB, fail, "Contacts", "remove", [this.id]);
+    }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+    var clonedContact = utils.clone(this);
+    clonedContact.id = null;
+    clonedContact.rawId = null;
+
+    function nullIds(arr) {
+        if (arr) {
+            for (var i = 0; i < arr.length; ++i) {
+                arr[i].id = null;
+            }
+        }
+    }
+
+    // Loop through and clear out any id's in phones, emails, etc.
+    nullIds(clonedContact.phoneNumbers);
+    nullIds(clonedContact.emails);
+    nullIds(clonedContact.addresses);
+    nullIds(clonedContact.ims);
+    nullIds(clonedContact.organizations);
+    nullIds(clonedContact.categories);
+    nullIds(clonedContact.photos);
+    nullIds(clonedContact.urls);
+    return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+    argscheck.checkArgs('FFO', 'Contact.save', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    var success = function(result) {
+        if (result) {
+            if (successCB) {
+                var fullContact = require('cordova/plugin/contacts').create(result);
+                successCB(convertIn(fullContact));
+            }
+        }
+        else {
+            // no Entry object returned
+            fail(ContactError.UNKNOWN_ERROR);
+        }
+    };
+    var dupContact = convertOut(utils.clone(this));
+    exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib/common/plugin/ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.formatted = formatted || null;
+    this.streetAddress = streetAddress || null;
+    this.locality = locality || null;
+    this.region = region || null;
+    this.postalCode = postalCode || null;
+    this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib/common/plugin/ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ *  ContactError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+    this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib/common/plugin/ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+    this.id = null;
+    this.type = (type && type.toString()) || null;
+    this.value = (value && value.toString()) || null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib/common/plugin/ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+    this.filter = filter || '';
+    this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib/common/plugin/ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+    this.formatted = formatted || null;
+    this.familyName = familyName || null;
+    this.givenName = givenName || null;
+    this.middleName = middle || null;
+    this.honorificPrefix = prefix || null;
+    this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib/common/plugin/ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.name = name || null;
+    this.department = dept || null;
+    this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib/common/plugin/Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+    /**
+     * The latitude of the position.
+     */
+    this.latitude = lat;
+    /**
+     * The longitude of the position,
+     */
+    this.longitude = lng;
+    /**
+     * The accuracy of the position.
+     */
+    this.accuracy = acc;
+    /**
+     * The altitude of the position.
+     */
+    this.altitude = (alt !== undefined ? alt : null);
+    /**
+     * The direction the device is moving at the position.
+     */
+    this.heading = (head !== undefined ? head : null);
+    /**
+     * The velocity with which the device is moving at the position.
+     */
+    this.speed = (vel !== undefined ? vel : null);
+
+    if (this.speed === 0 || this.speed === null) {
+        this.heading = NaN;
+    }
+
+    /**
+     * The altitude accuracy of the position.
+     */
+    this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib/common/plugin/DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileError = require('cordova/plugin/FileError'),
+    DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+     DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+    return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+    var win = successCallback && function(result) {
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+    var win = successCallback && function(result) {
+        var FileEntry = require('cordova/plugin/FileEntry');
+        var entry = new FileEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib/common/plugin/DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+    this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+    var win = typeof successCallback !== 'function' ? null : function(result) {
+        var retVal = [];
+        for (var i=0; i<result.length; i++) {
+            var entry = null;
+            if (result[i].isDirectory) {
+                entry = new (require('cordova/plugin/DirectoryEntry'))();
+            }
+            else if (result[i].isFile) {
+                entry = new (require('cordova/plugin/FileEntry'))();
+            }
+            entry.isDirectory = result[i].isDirectory;
+            entry.isFile = result[i].isFile;
+            entry.name = result[i].name;
+            entry.fullPath = result[i].fullPath;
+            retVal.push(entry);
+        }
+        successCallback(retVal);
+    };
+    var fail = typeof errorCallback !== 'function' ? null : function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib/common/plugin/Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ *            {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ *            {boolean} true if Entry is a directory (readonly)
+ * @param name
+ *            {DOMString} name of the file or directory, excluding the path
+ *            leading to it (readonly)
+ * @param fullPath
+ *            {DOMString} the absolute full path to the file or directory
+ *            (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+    this.isFile = !!isFile;
+    this.isDirectory = !!isDirectory;
+    this.name = name || '';
+    this.fullPath = fullPath || '';
+    this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+    var success = successCallback && function(lastModified) {
+        var metadata = new Metadata(lastModified);
+        successCallback(metadata);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+    exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ * @param metadataObject
+ *            {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+    exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new Entry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+        // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        // success callback
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+    // fullPath attribute contains the full URL
+    return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    // fullPath attribute contains the full URI
+    return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.remove', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+    var win = successCallback && function(result) {
+        var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib/common/plugin/File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+    this.name = name || '';
+    this.fullPath = fullPath || null;
+    this.type = type || null;
+    this.lastModifiedDate = lastModifiedDate || null;
+    this.size = size || 0;
+
+    // These store the absolute start and end for slicing the file.
+    this.start = 0;
+    this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+    var size = this.end - this.start;
+    var newStart = 0;
+    var newEnd = size;
+    if (arguments.length) {
+        if (start < 0) {
+            newStart = Math.max(size + start, 0);
+        } else {
+            newStart = Math.min(size, start);
+        }
+    }
+
+    if (arguments.length >= 2) {
+        if (end < 0) {
+            newEnd = Math.max(size + end, 0);
+        } else {
+            newEnd = Math.min(end, size);
+        }
+    }
+
+    var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+    newFile.start = this.start + newStart;
+    newFile.end = this.start + newEnd;
+    return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib/common/plugin/FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileWriter = require('cordova/plugin/FileWriter'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+     FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+    this.file(function(filePointer) {
+        var writer = new FileWriter(filePointer);
+
+        if (writer.fileName === null || writer.fileName === "") {
+            errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+        } else {
+            successCallback && successCallback(writer);
+        }
+    }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+    var win = successCallback && function(f) {
+        var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+        successCallback(file);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib/common/plugin/FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+  this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib/common/plugin/FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    modulemapper = require('cordova/modulemapper'),
+    utils = require('cordova/utils'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent'),
+    origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+    this._readyState = 0;
+    this._error = null;
+    this._result = null;
+    this._fileName = '';
+    this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+    return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+    return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+    return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+    utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+        return this._realReader[eventName] || null;
+    }, function(value) {
+        this._realReader[eventName] = value;
+    });
+}
+defineEvent('onloadstart');    // When the read starts.
+defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload');         // When the read has successfully completed.
+defineEvent('onerror');        // When the read has failed (see errors).
+defineEvent('onloadend');      // When the request has completed (either in success or failure).
+defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+    // Already loading something
+    if (reader.readyState == FileReader.LOADING) {
+      throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    reader._result = null;
+    reader._error = null;
+    reader._readyState = FileReader.LOADING;
+
+    if (typeof file.fullPath == 'string') {
+        reader._fileName = file.fullPath;
+    } else {
+        reader._fileName = '';
+        return true;
+    }
+
+    reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+    if (origFileReader && !this._fileName) {
+        return this._realReader.abort();
+    }
+    this._result = null;
+
+    if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+      return;
+    }
+
+    this._readyState = FileReader.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {target:this}));
+    }
+    // If load end callback
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target:this}));
+    }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file          {File} File object containing file properties
+ * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsText(file, encoding);
+    }
+
+    // Default encoding is UTF-8
+    var enc = encoding ? encoding : "UTF-8";
+    var me = this;
+    var execArgs = [this._fileName, enc, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // null result
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ *      data:[<mediatype>][;base64],<data>
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsDataURL(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsBinaryString(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsArrayBuffer(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib/common/plugin/FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+    this.name = name || null;
+    if (root) {
+        this.root = new DirectoryEntry(root.name, root.fullPath);
+    }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib/common/plugin/FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    FileTransferError = require('cordova/plugin/FileTransferError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+    var pe = new ProgressEvent();
+    pe.lengthComputable = result.lengthComputable;
+    pe.loaded = result.loaded;
+    pe.total = result.total;
+    return pe;
+}
+
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) !== 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+    this._id = ++idCounter;
+    this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String}           Full path of the file on the device
+* @param server {String}             URL of the server to receive the file
+* @param successCallback (Function}  Callback to be invoked when upload has completed
+* @param errorCallback {Function}    Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+    argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+    // check for options
+    var fileKey = null;
+    var fileName = null;
+    var mimeType = null;
+    var params = null;
+    var chunkedMode = true;
+    var headers = null;
+    var httpMethod = null;
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        options = options || {};
+        options.headers = options.headers || {};
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    if (options) {
+        fileKey = options.fileKey;
+        fileName = options.fileName;
+        mimeType = options.mimeType;
+        headers = options.headers;
+        httpMethod = options.httpMethod || "POST";
+        if (httpMethod.toUpperCase() == "PUT"){
+            httpMethod = "PUT";
+        } else {
+            httpMethod = "POST";
+        }
+        if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+            chunkedMode = options.chunkedMode;
+        }
+        if (options.params) {
+            params = options.params;
+        }
+        else {
+            params = {};
+        }
+    }
+
+    var fail = errorCallback && function(e) {
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+        errorCallback(error);
+    };
+
+    var self = this;
+    var win = function(result) {
+        if (typeof result.lengthComputable != "undefined") {
+            if (self.onprogress) {
+                self.onprogress(newProgressEvent(result));
+            }
+        } else {
+            successCallback && successCallback(result);
+        }
+    };
+    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String}          URL of the server to receive the file
+ * @param target {String}         Full path of the file on the device
+ * @param successCallback (Function}  Callback to be invoked when upload has completed
+ * @param errorCallback {Function}    Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
+    argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+    var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        options = options || {};
+        options.headers = options.headers || {};
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
+    var win = function(result) {
+        if (typeof result.lengthComputable != "undefined") {
+            if (self.onprogress) {
+                return self.onprogress(newProgressEvent(result));
+            }
+        } else if (successCallback) {
+            var entry = null;
+            if (result.isDirectory) {
+                entry = new (require('cordova/plugin/DirectoryEntry'))();
+            }
+            else if (result.isFile) {
+                entry = new (require('cordova/plugin/FileEntry'))();
+            }
+            entry.isDirectory = result.isDirectory;
+            entry.isFile = result.isFile;
+            entry.name = result.name;
+            entry.fullPath = result.fullPath;
+            successCallback(entry);
+        }
+    };
+
+    var fail = errorCallback && function(e) {
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+        errorCallback(error);
+    };
+
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
+ */
+FileTransfer.prototype.abort = function() {
+    exec(null, null, 'FileTransfer', 'abort', [this._id]);
+};
+
+module.exports = FileTransfer;
+
+});
+
+// file: lib/common/plugin/FileTransferError.js
+define("cordova/plugin/FileTransferError", function(require, exports, module) {
+
+/**
+ * FileTransferError
+ * @constructor
+ */
+var FileTransferError = function(code, source, target, status, body) {
+    this.code = code || null;
+    this.source = source || null;
+    this.target = target || null;
+    this.http_status = status || null;
+    this.body = body || null;
+};
+
+FileTransferError.FILE_NOT_FOUND_ERR = 1;
+FileTransferError.INVALID_URL_ERR = 2;
+FileTransferError.CONNECTION_ERR = 3;
+FileTransferError.ABORT_ERR = 4;
+
+module.exports = FileTransferError;
+
+});
+
+// file: lib/common/plugin/FileUploadOptions.js
+define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String}   Name of file request parameter.
+ * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object}    Object with key: value params to send to the server.
+ * @param headers {Object}   Keys are header names, values are header values. Multiple
+ *                           headers of the same name are not supported.
+ */
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
+    this.fileKey = fileKey || null;
+    this.fileName = fileName || null;
+    this.mimeType = mimeType || null;
+    this.params = params || null;
+    this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
+
+// file: lib/common/plugin/FileUploadResult.js
+define("cordova/plugin/FileUploadResult", function(require, exports, module) {
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+var FileUploadResult = function() {
+    this.bytesSent = 0;
+    this.responseCode = null;
+    this.response = null;
+};
+
+module.exports = FileUploadResult;
+
+});
+
+// file: lib/common/plugin/FileWriter.js
+define("cordova/plugin/FileWriter", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function(file) {
+    this.fileName = "";
+    this.length = 0;
+    if (file) {
+        this.fileName = file.fullPath || file;
+        this.length = file.size || 0;
+    }
+    // default is to write at the beginning of the file
+    this.position = 0;
+
+    this.readyState = 0; // EMPTY
+
+    this.result = null;
+
+    // Error
+    this.error = null;
+
+    // Event handlers
+    this.onwritestart = null;   // When writing starts
+    this.onprogress = null;     // While writing the file, and reporting partial file data
+    this.onwrite = null;        // When the write has successfully completed.
+    this.onwriteend = null;     // When the request has completed (either in success or failure).
+    this.onabort = null;        // When the write has been aborted. For instance, by invoking the abort() method.
+    this.onerror = null;        // When the write has failed (see errors).
+};
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function() {
+    // check for invalid state
+    if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // set error
+    this.error = new FileError(FileError.ABORT_ERR);
+
+    this.readyState = FileWriter.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === "function") {
+        this.onabort(new ProgressEvent("abort", {"target":this}));
+    }
+
+    // If write end callback
+    if (typeof this.onwriteend === "function") {
+        this.onwriteend(new ProgressEvent("writeend", {"target":this}));
+    }
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param text to be written
+ */
+FileWriter.prototype.write = function(text) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === "function") {
+        me.onwritestart(new ProgressEvent("writestart", {"target":me}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // position always increases by bytes written because file would be extended
+            me.position += r;
+            // The length of the file is now where we are done writing.
+
+            me.length = me.position;
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // If onwrite callback
+            if (typeof me.onwrite === "function") {
+                me.onwrite(new ProgressEvent("write", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        }, "File", "write", [this.fileName, text, this.position]);
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound.  If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function(offset) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    if (!offset && offset !== 0) {
+        return;
+    }
+
+    // See back from end of file.
+    if (offset < 0) {
+        this.position = Math.max(offset + this.length, 0);
+    }
+    // Offset is bigger than file size so set position
+    // to the end of the file.
+    else if (offset > this.length) {
+        this.position = this.length;
+    }
+    // Offset is between 0 and file size so set the position
+    // to start writing.
+    else {
+        this.position = offset;
+    }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function(size) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === "function") {
+        me.onwritestart(new ProgressEvent("writestart", {"target":this}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Update the length of the file
+            me.length = r;
+            me.position = Math.min(me.position, r);
+
+            // If onwrite callback
+            if (typeof me.onwrite === "function") {
+                me.onwrite(new ProgressEvent("write", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        }, "File", "truncate", [this.fileName, size]);
+};
+
+module.exports = FileWriter;
+
+});
+
+// file: lib/common/plugin/Flags.js
+define("cordova/plugin/Flags", function(require, exports, module) {
+
+/**
+ * Supplies arguments to methods that lookup or create files and directories.
+ *
+ * @param create
+ *            {boolean} file or directory if it doesn't exist
+ * @param exclusive
+ *            {boolean} used with create; if true the command will fail if
+ *            target path exists
+ */
+function Flags(create, exclusive) {
+    this.create = create || false;
+    this.exclusive = exclusive || false;
+}
+
+module.exports = Flags;
+
+});
+
+// file: lib/common/plugin/GlobalizationError.js
+define("cordova/plugin/GlobalizationError", function(require, exports, module) {
+
+
+/**
+ * Globalization error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var GlobalizationError = function(code, message) {
+    this.code = code || null;
+    this.message = message || '';
+};
+
+// Globalization error codes
+GlobalizationError.UNKNOWN_ERROR = 0;
+GlobalizationError.FORMATTING_ERROR = 1;
+GlobalizationError.PARSING_ERROR = 2;
+GlobalizationError.PATTERN_ERROR = 3;
+
+module.exports = GlobalizationError;
+
+});
+
+// file: lib/common/plugin/InAppBrowser.js
+define("cordova/plugin/InAppBrowser", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
+
+function InAppBrowser() {
+   this.channels = {
+        'loadstart': channel.create('loadstart'),
+        'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
+        'exit' : channel.create('exit')
+   };
+}
+
+InAppBrowser.prototype = {
+    _eventHandler: function (event) {
+        if (event.type in this.channels) {
+            this.channels[event.type].fire(event);
+        }
+    },
+    close: function (eventname) {
+        exec(null, null, "InAppBrowser", "close", []);
+    },
+    addEventListener: function (eventname,f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].subscribe(f);
+        }
+    },
+    removeEventListener: function(eventname, f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].unsubscribe(f);
+        }
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
+    }
+};
+
+module.exports = function(strUrl, strWindowName, strWindowFeatures) {
+    var iab = new InAppBrowser();
+    var cb = function(eventname) {
+       iab._eventHandler(eventname);
+    };
+
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    return iab;
+};
+
+
+});
+
+// file: lib/common/plugin/LocalFileSystem.js
+define("cordova/plugin/LocalFileSystem", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Represents a local file system.
+ */
+var LocalFileSystem = function() {
+
+};
+
+LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence
+LocalFileSystem.PERSISTENT = 1; //persistent
+
+module.exports = LocalFileSystem;
+
+});
+
+// file: lib/common/plugin/Media.js
+define("cordova/plugin/Media", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec');
+
+var mediaObjects = {};
+
+/**
+ * This class provides access to the device media, interfaces to both sound and video
+ *
+ * @constructor
+ * @param src                   The file name or url to play
+ * @param successCallback       The callback to be called when the file is done playing or recording.
+ *                                  successCallback()
+ * @param errorCallback         The callback to be called if there is an error.
+ *                                  errorCallback(int errorCode) - OPTIONAL
+ * @param statusCallback        The callback to be called when media status has changed.
+ *                                  statusCallback(int statusCode) - OPTIONAL
+ */
+var Media = function(src, successCallback, errorCallback, statusCallback) {
+    argscheck.checkArgs('SFFF', 'Media', arguments);
+    this.id = utils.createUUID();
+    mediaObjects[this.id] = this;
+    this.src = src;
+    this.successCallback = successCallback;
+    this.errorCallback = errorCallback;
+    this.statusCallback = statusCallback;
+    this._duration = -1;
+    this._position = -1;
+    exec(null, this.errorCallback, "Media", "create", [this.id, this.src]);
+};
+
+// Media messages
+Media.MEDIA_STATE = 1;
+Media.MEDIA_DURATION = 2;
+Media.MEDIA_POSITION = 3;
+Media.MEDIA_ERROR = 9;
+
+// Media states
+Media.MEDIA_NONE = 0;
+Media.MEDIA_STARTING = 1;
+Media.MEDIA_RUNNING = 2;
+Media.MEDIA_PAUSED = 3;
+Media.MEDIA_STOPPED = 4;
+Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
+
+// "static" function to return existing objs.
+Media.get = function(id) {
+    return mediaObjects[id];
+};
+
+/**
+ * Start or resume playing audio file.
+ */
+Media.prototype.play = function(options) {
+    exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]);
+};
+
+/**
+ * Stop playing audio file.
+ */
+Media.prototype.stop = function() {
+    var me = this;
+    exec(function() {
+        me._position = 0;
+    }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
+};
+
+/**
+ * Seek or jump to a new time in the track..
+ */
+Media.prototype.seekTo = function(milliseconds) {
+    var me = this;
+    exec(function(p) {
+        me._position = p;
+    }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]);
+};
+
+/**
+ * Pause playing audio file.
+ */
+Media.prototype.pause = function() {
+    exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]);
+};
+
+/**
+ * Get duration of an audio file.
+ * The duration is only set for audio that is playing, paused or stopped.
+ *
+ * @return      duration or -1 if not known.
+ */
+Media.prototype.getDuration = function() {
+    return this._duration;
+};
+
+/**
+ * Get position of audio.
+ */
+Media.prototype.getCurrentPosition = function(success, fail) {
+    var me = this;
+    exec(function(p) {
+        me._position = p;
+        success(p);
+    }, fail, "Media", "getCurrentPositionAudio", [this.id]);
+};
+
+/**
+ * Start recording audio file.
+ */
+Media.prototype.startRecord = function() {
+    exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
+};
+
+/**
+ * Stop recording audio file.
+ */
+Media.prototype.stopRecord = function() {
+    exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
+};
+
+/**
+ * Release the resources.
+ */
+Media.prototype.release = function() {
+    exec(null, this.errorCallback, "Media", "release", [this.id]);
+};
+
+/**
+ * Adjust the volume.
+ */
+Media.prototype.setVolume = function(volume) {
+    exec(null, null, "Media", "setVolume", [this.id, volume]);
+};
+
+/**
+ * Audio has status update.
+ * PRIVATE
+ *
+ * @param id            The media object id (string)
+ * @param msgType       The 'type' of update this is
+ * @param value         Use of value is determined by the msgType
+ */
+Media.onStatus = function(id, msgType, value) {
+
+    var media = mediaObjects[id];
+
+    if(media) {
+        switch(msgType) {
+            case Media.MEDIA_STATE :
+                media.statusCallback && media.statusCallback(value);
+                if(value == Media.MEDIA_STOPPED) {
+                    media.successCallback && media.successCallback();
+                }
+                break;
+            case Media.MEDIA_DURATION :
+                media._duration = value;
+                break;
+            case Media.MEDIA_ERROR :
+                media.errorCallback && media.errorCallback(value);
+                break;
+            case Media.MEDIA_POSITION :
+                media._position = Number(value);
+                break;
+            default :
+                console.error && console.error("Unhandled Media.onStatus :: " + msgType);
+                break;
+        }
+    }
+    else {
+         console.error && console.error("Received Media.onStatus callback for unknown media :: " + id);
+    }
+
+};
+
+module.exports = Media;
+
+});
+
+// file: lib/common/plugin/MediaError.js
+define("cordova/plugin/MediaError", function(require, exports, module) {
+
+/**
+ * This class contains information about any Media errors.
+*/
+/*
+ According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror
+ We should never be creating these objects, we should just implement the interface
+ which has 1 property for an instance, 'code'
+
+ instead of doing :
+    errorCallbackFunction( new MediaError(3,'msg') );
+we should simply use a literal :
+    errorCallbackFunction( {'code':3} );
+ */
+
+ var _MediaError = window.MediaError;
+
+
+if(!_MediaError) {
+    window.MediaError = _MediaError = function(code, msg) {
+        this.code = (typeof code != 'undefined') ? code : null;
+        this.message = msg || ""; // message is NON-standard! do not use!
+    };
+}
+
+_MediaError.MEDIA_ERR_NONE_ACTIVE    = _MediaError.MEDIA_ERR_NONE_ACTIVE    || 0;
+_MediaError.MEDIA_ERR_ABORTED        = _MediaError.MEDIA_ERR_ABORTED        || 1;
+_MediaError.MEDIA_ERR_NETWORK        = _MediaError.MEDIA_ERR_NETWORK        || 2;
+_MediaError.MEDIA_ERR_DECODE         = _MediaError.MEDIA_ERR_DECODE         || 3;
+_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4;
+// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below.
+// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes
+_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4;
+
+module.exports = _MediaError;
+
+});
+
+// file: lib/common/plugin/MediaFile.js
+define("cordova/plugin/MediaFile", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    File = require('cordova/plugin/File'),
+    CaptureError = require('cordova/plugin/CaptureError');
+/**
+ * Represents a single file.
+ *
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+var MediaFile = function(name, fullPath, type, lastModifiedDate, size){
+    MediaFile.__super__.constructor.apply(this, arguments);
+};
+
+utils.extend(MediaFile, File);
+
+/**
+ * Request capture format data for a specific file and type
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ */
+MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
+    if (typeof this.fullPath === "undefined" || this.fullPath === null) {
+        errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
+    } else {
+        exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
+    }
+};
+
+module.exports = MediaFile;
+
+});
+
+// file: lib/common/plugin/MediaFileData.js
+define("cordova/plugin/MediaFileData", function(require, exports, module) {
+
+/**
+ * MediaFileData encapsulates format information of a media file.
+ *
+ * @param {DOMString} codecs
+ * @param {long} bitrate
+ * @param {long} height
+ * @param {long} width
+ * @param {float} duration
+ */
+var MediaFileData = function(codecs, bitrate, height, width, duration){
+    this.codecs = codecs || null;
+    this.bitrate = bitrate || 0;
+    this.height = height || 0;
+    this.width = width || 0;
+    this.duration = duration || 0;
+};
+
+module.exports = MediaFileData;
+
+});
+
+// file: lib/common/plugin/Metadata.js
+define("cordova/plugin/Metadata", function(require, exports, module) {
+
+/**
+ * Information about the state of the file or directory
+ *
+ * {Date} modificationTime (readonly)
+ */
+var Metadata = function(time) {
+    this.modificationTime = (typeof time != 'undefined'?new Date(time):null);
+};
+
+module.exports = Metadata;
+
+});
+
+// file: lib/common/plugin/Position.js
+define("cordova/plugin/Position", function(require, exports, module) {
+
+var Coordinates = require('cordova/plugin/Coordinates');
+
+var Position = function(coords, timestamp) {
+    if (coords) {
+        this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy);
+    } else {
+        this.coords = new Coordinates();
+    }
+    this.timestamp = (timestamp !== undefined) ? timestamp : new Date();
+};
+
+module.exports = Position;
+
+});
+
+// file: lib/common/plugin/PositionError.js
+define("cordova/plugin/PositionError", function(require, exports, module) {
+
+/**
+ * Position error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var PositionError = function(code, message) {
+    this.code = code || null;
+    this.message = message || '';
+};
+
+PositionError.PERMISSION_DENIED = 1;
+PositionError.POSITION_UNAVAILABLE = 2;
+PositionError.TIMEOUT = 3;
+
+module.exports = PositionError;
+
+});
+
+// file: lib/common/plugin/ProgressEvent.js
+define("cordova/plugin/ProgressEvent", function(require, exports, module) {
+
+// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill
+// Feature test: See if we can instantiate a native ProgressEvent;
+// if so, use that approach,
+// otherwise fill-in with our own implementation.
+//
+// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
+var ProgressEvent = (function() {
+    /*
+    var createEvent = function(data) {
+        var event = document.createEvent('Events');
+        event.initEvent('ProgressEvent', false, false);
+        if (data) {
+            for (var i in data) {
+                if (data.hasOwnProperty(i)) {
+                    event[i] = data[i];
+                }
+            }
+            if (data.target) {
+                // TODO: cannot call <some_custom_object>.dispatchEvent
+                // need to first figure out how to implement EventTarget
+            }
+        }
+        return event;
+    };
+    try {
+        var ev = createEvent({type:"abort",target:document});
+        return function ProgressEvent(type, data) {
+            data.type = type;
+            return createEvent(data);
+        };
+    } catch(e){
+    */
+        return function ProgressEvent(type, dict) {
+            this.type = type;
+            this.bubbles = false;
+            this.cancelBubble = false;
+            this.cancelable = false;
+            this.lengthComputable = false;
+            this.loaded = dict && dict.loaded ? dict.loaded : 0;
+            this.total = dict && dict.total ? dict.total : 0;
+            this.target = dict && dict.target ? dict.target : null;
+        };
+    //}
+})();
+
+module.exports = ProgressEvent;
+
+});
+
+// file: lib/common/plugin/accelerometer.js
+define("cordova/plugin/accelerometer", function(require, exports, module) {
+
+/**
+ * This class provides access to device accelerometer data.
+ * @constructor
+ */
+var argscheck = require('cordova/argscheck'),
+    utils = require("cordova/utils"),
+    exec = require("cordova/exec"),
+    Acceleration = require('cordova/plugin/Acceleration');
+
+// Is the accel sensor running?
+var running = false;
+
+// Keeps reference to watchAcceleration calls.
+var timers = {};
+
+// Array of listeners; used to keep track of when we should call start and stop.
+var listeners = [];
+
+// Last returned acceleration object from native
+var accel = null;
+
+// Tells native to start.
+function start() {
+    exec(function(a) {
+        var tempListeners = listeners.slice(0);
+        accel = new Acceleration(a.x, a.y, a.z, a.timestamp);
+        for (var i = 0, l = tempListeners.length; i < l; i++) {
+            tempListeners[i].win(accel);
+        }
+    }, function(e) {
+        var tempListeners = listeners.slice(0);
+        for (var i = 0, l = tempListeners.length; i < l; i++) {
+            tempListeners[i].fail(e);
+        }
+    }, "Accelerometer", "start", []);
+    running = true;
+}
+
+// Tells native to stop.
+function stop() {
+    exec(null, null, "Accelerometer", "stop", []);
+    running = false;
+}
+
+// Adds a callback pair to the listeners array
+function createCallbackPair(win, fail) {
+    return {win:win, fail:fail};
+}
+
+// Removes a win/fail listener pair from the listeners array
+function removeListeners(l) {
+    var idx = listeners.indexOf(l);
+    if (idx > -1) {
+        listeners.splice(idx, 1);
+        if (listeners.length === 0) {
+            stop();
+        }
+    }
+}
+
+var accelerometer = {
+    /**
+     * Asynchronously acquires the current acceleration.
+     *
+     * @param {Function} successCallback    The function to call when the acceleration data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the acceleration data. (OPTIONAL)
+     * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+     */
+    getCurrentAcceleration: function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments);
+
+        var p;
+        var win = function(a) {
+            removeListeners(p);
+            successCallback(a);
+        };
+        var fail = function(e) {
+            removeListeners(p);
+            errorCallback && errorCallback(e);
+        };
+
+        p = createCallbackPair(win, fail);
+        listeners.push(p);
+
+        if (!running) {
+            start();
+        }
+    },
+
+    /**
+     * Asynchronously acquires the acceleration repeatedly at a given interval.
+     *
+     * @param {Function} successCallback    The function to call each time the acceleration data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the acceleration data. (OPTIONAL)
+     * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+     * @return String                       The watch id that must be passed to #clearWatch to stop watching.
+     */
+    watchAcceleration: function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments);
+        // Default interval (10 sec)
+        var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000;
+
+        // Keep reference to watch id, and report accel readings as often as defined in frequency
+        var id = utils.createUUID();
+
+        var p = createCallbackPair(function(){}, function(e) {
+            removeListeners(p);
+            errorCallback && errorCallback(e);
+        });
+        listeners.push(p);
+
+        timers[id] = {
+            timer:window.setInterval(function() {
+                if (accel) {
+                    successCallback(accel);
+                }
+            }, frequency),
+            listeners:p
+        };
+
+        if (running) {
+            // If we're already running then immediately invoke the success callback
+            // but only if we have retrieved a value, sample code does not check for null ...
+            if (accel) {
+                successCallback(accel);
+            }
+        } else {
+            start();
+        }
+
+        return id;
+    },
+
+    /**
+     * Clears the specified accelerometer watch.
+     *
+     * @param {String} id       The id of the watch returned from #watchAcceleration.
+     */
+    clearWatch: function(id) {
+        // Stop javascript timer & remove from timer list
+        if (id && timers[id]) {
+            window.clearInterval(timers[id].timer);
+            removeListeners(timers[id].listeners);
+            delete timers[id];
+        }
+    }
+};
+
+module.exports = accelerometer;
+
+});
+
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
+// file: lib/android/plugin/android/app.js
+define("cordova/plugin/android/app", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+module.exports = {
+  /**
+   * Clear the resource cache.
+   */
+  clearCache:function() {
+    exec(null, null, "App", "clearCache", []);
+  },
+
+  /**
+   * Load the url into the webview or into new browser instance.
+   *
+   * @param url           The URL to load
+   * @param props         Properties that can be passed in to the activity:
+   *      wait: int                           => wait msec before loading URL
+   *      loadingDialog: "Title,Message"      => display a native loading dialog
+   *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+   *      clearHistory: boolean              => clear webview history (default=false)
+   *      openExternal: boolean              => open in a new browser (default=false)
+   *
+   * Example:
+   *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+   */
+  loadUrl:function(url, props) {
+    exec(null, null, "App", "loadUrl", [url, props]);
+  },
+
+  /**
+   * Cancel loadUrl that is waiting to be loaded.
+   */
+  cancelLoadUrl:function() {
+    exec(null, null, "App", "cancelLoadUrl", []);
+  },
+
+  /**
+   * Clear web history in this web view.
+   * Instead of BACK button loading the previous web page, it will exit the app.
+   */
+  clearHistory:function() {
+    exec(null, null, "App", "clearHistory", []);
+  },
+
+  /**
+   * Go to previous page displayed.
+   * This is the same as pressing the backbutton on Android device.
+   */
+  backHistory:function() {
+    exec(null, null, "App", "backHistory", []);
+  },
+
+  /**
+   * Override the default behavior of the Android back button.
+   * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+   *
+   * Note: The user should not have to call this method.  Instead, when the user
+   *       registers for the "backbutton" event, this is automatically done.
+   *
+   * @param override        T=override, F=cancel override
+   */
+  overrideBackbutton:function(override) {
+    exec(null, null, "App", "overrideBackbutton", [override]);
+  },
+
+  /**
+   * Exit and terminate the application.
+   */
+  exitApp:function() {
+    return exec(null, null, "App", "exitApp", []);
+  }
+};
+
+});
+
+// file: lib/android/plugin/android/device.js
+define("cordova/plugin/android/device", function(require, exports, module) {
+
+var channel = require('cordova/channel'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    app = require('cordova/plugin/android/app');
+
+module.exports = {
+    /*
+     * DEPRECATED
+     * This is only for Android.
+     *
+     * You must explicitly override the back button.
+     */
+    overrideBackButton:function() {
+        console.log("Device.overrideBackButton() is deprecated.  Use App.overrideBackbutton(true).");
+        app.overrideBackbutton(true);
+    },
+
+    /*
+     * DEPRECATED
+     * This is only for Android.
+     *
+     * This resets the back button to the default behavior
+     */
+    resetBackButton:function() {
+        console.log("Device.resetBackButton() is deprecated.  Use App.overrideBackbutton(false).");
+        app.overrideBackbutton(false);
+    },
+
+    /*
+     * DEPRECATED
+     * This is only for Android.
+     *
+     * This terminates the activity!
+     */
+    exitApp:function() {
+        console.log("Device.exitApp() is deprecated.  Use App.exitApp().");
+        app.exitApp();
+    }
+};
+
+});
+
+// file: lib/android/plugin/android/nativeapiprovider.js
+define("cordova/plugin/android/nativeapiprovider", function(require, exports, module) {
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/plugin/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/plugin/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
+
+});
+
+// file: lib/android/plugin/android/notification.js
+define("cordova/plugin/android/notification", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Provides Android enhanced notification API.
+ */
+module.exports = {
+    activityStart : function(title, message) {
+        // If title and message not specified then mimic Android behavior of
+        // using default strings.
+        if (typeof title === "undefined" && typeof message == "undefined") {
+            title = "Busy";
+            message = 'Please wait...';
+        }
+
+        exec(null, null, 'Notification', 'activityStart', [ title, message ]);
+    },
+
+    /**
+     * Close an activity dialog
+     */
+    activityStop : function() {
+        exec(null, null, 'Notification', 'activityStop', []);
+    },
+
+    /**
+     * Display a progress dialog with progress bar that goes from 0 to 100.
+     *
+     * @param {String}
+     *            title Title of the progress dialog.
+     * @param {String}
+     *            message Message to display in the dialog.
+     */
+    progressStart : function(title, message) {
+        exec(null, null, 'Notification', 'progressStart', [ title, message ]);
+    },
+
+    /**
+     * Close the progress dialog.
+     */
+    progressStop : function() {
+        exec(null, null, 'Notification', 'progressStop', []);
+    },
+
+    /**
+     * Set the progress dialog value.
+     *
+     * @param {Number}
+     *            value 0-100
+     */
+    progressValue : function(value) {
+        exec(null, null, 'Notification', 'progressValue', [ value ]);
+    }
+};
+
+});
+
+// file: lib/android/plugin/android/promptbasednativeapi.js
+define("cordova/plugin/android/promptbasednativeapi", function(require, exports, module) {
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used only on the 2.3 simulator, where addJavascriptInterface() is broken.
+ */
+
+module.exports = {
+    exec: function(service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(value) {
+        prompt(value, 'gap_bridge_mode:');
+    },
+    retrieveJsMessages: function() {
+        return prompt('', 'gap_poll:');
+    }
+};
+
+});
+
+// file: lib/android/plugin/android/storage.js
+define("cordova/plugin/android/storage", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    channel = require('cordova/channel');
+
+var queryQueue = {};
+
+/**
+ * SQL result set object
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Rows = function() {
+    this.resultSet = [];    // results array
+    this.length = 0;        // number of rows
+};
+
+/**
+ * Get item from SQL result set
+ *
+ * @param row           The row number to return
+ * @return              The row object
+ */
+DroidDB_Rows.prototype.item = function(row) {
+    return this.resultSet[row];
+};
+
+/**
+ * SQL result set that is returned to user.
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Result = function() {
+    this.rows = new DroidDB_Rows();
+};
+
+/**
+ * Callback from native code when query is complete.
+ * PRIVATE METHOD
+ *
+ * @param id   Query id
+ */
+function completeQuery(id, data) {
+    var query = queryQueue[id];
+    if (query) {
+        try {
+            delete queryQueue[id];
+
+            // Get transaction
+            var tx = query.tx;
+
+            // If transaction hasn't failed
+            // Note: We ignore all query results if previous query
+            //       in the same transaction failed.
+            if (tx && tx.queryList[id]) {
+
+                // Save query results
+                var r = new DroidDB_Result();
+                r.rows.resultSet = data;
+                r.rows.length = data.length;
+                try {
+                    if (typeof query.successCallback === 'function') {
+                        query.successCallback(query.tx, r);
+                    }
+                } catch (ex) {
+                    console.log("executeSql error calling user success callback: "+ex);
+                }
+
+                tx.queryComplete(id);
+            }
+        } catch (e) {
+            console.log("executeSql error: "+e);
+        }
+    }
+}
+
+/**
+ * Callback from native code when query fails
+ * PRIVATE METHOD
+ *
+ * @param reason            Error message
+ * @param id                Query id
+ */
+function failQuery(reason, id) {
+    var query = queryQueue[id];
+    if (query) {
+        try {
+            delete queryQueue[id];
+
+            // Get transaction
+            var tx = query.tx;
+
+            // If transaction hasn't failed
+            // Note: We ignore all query results if previous query
+            //       in the same transaction failed.
+            if (tx && tx.queryList[id]) {
+                tx.queryList = {};
+
+                try {
+                    if (typeof query.errorCallback === 'function') {
+                        query.errorCallback(query.tx, reason);
+                    }
+                } catch (ex) {
+                    console.log("executeSql error calling user error callback: "+ex);
+                }
+
+                tx.queryFailed(id, reason);
+            }
+
+        } catch (e) {
+            console.log("executeSql error: "+e);
+        }
+    }
+}
+
+/**
+ * SQL query object
+ * PRIVATE METHOD
+ *
+ * @constructor
+ * @param tx                The transaction object that this query belongs to
+ */
+var DroidDB_Query = function(tx) {
+
+    // Set the id of the query
+    this.id = utils.createUUID();
+
+    // Add this query to the queue
+    queryQueue[this.id] = this;
+
+    // Init result
+    this.resultSet = [];
+
+    // Set transaction that this query belongs to
+    this.tx = tx;
+
+    // Add this query to transaction list
+    this.tx.queryList[this.id] = this;
+
+    // Callbacks
+    this.successCallback = null;
+    this.errorCallback = null;
+
+};
+
+/**
+ * Transaction object
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Tx = function() {
+
+    // Set the id of the transaction
+    this.id = utils.createUUID();
+
+    // Callbacks
+    this.successCallback = null;
+    this.errorCallback = null;
+
+    // Query list
+    this.queryList = {};
+};
+
+/**
+ * Mark query in transaction as complete.
+ * If all queries are complete, call the user's transaction success callback.
+ *
+ * @param id                Query id
+ */
+DroidDB_Tx.prototype.queryComplete = function(id) {
+    delete this.queryList[id];
+
+    // If no more outstanding queries, then fire transaction success
+    if (this.successCallback) {
+        var count = 0;
+        var i;
+        for (i in this.queryList) {
+            if (this.queryList.hasOwnProperty(i)) {
+                count++;
+            }
+        }
+        if (count === 0) {
+            try {
+                this.successCallback();
+            } catch(e) {
+                console.log("Transaction error calling user success callback: " + e);
+            }
+        }
+    }
+};
+
+/**
+ * Mark query in transaction as failed.
+ *
+ * @param id                Query id
+ * @param reason            Error message
+ */
+DroidDB_Tx.prototype.queryFailed = function(id, reason) {
+
+    // The sql queries in this transaction have already been run, since
+    // we really don't have a real transaction implemented in native code.
+    // However, the user callbacks for the remaining sql queries in transaction
+    // will not be called.
+    this.queryList = {};
+
+    if (this.errorCallback) {
+        try {
+            this.errorCallback(reason);
+        } catch(e) {
+            console.log("Transaction error calling user error callback: " + e);
+        }
+    }
+};
+
+/**
+ * Execute SQL statement
+ *
+ * @param sql                   SQL statement to execute
+ * @param params                Statement parameters
+ * @param successCallback       Success callback
+ * @param errorCallback         Error callback
+ */
+DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) {
+
+    // Init params array
+    if (typeof params === 'undefined') {
+        params = [];
+    }
+
+    // Create query and add to queue
+    var query = new DroidDB_Query(this);
+    queryQueue[query.id] = query;
+
+    // Save callbacks
+    query.successCallback = successCallback;
+    query.errorCallback = errorCallback;
+
+    // Call native code
+    exec(null, null, "Storage", "executeSql", [sql, params, query.id]);
+};
+
+var DatabaseShell = function() {
+};
+
+/**
+ * Start a transaction.
+ * Does not support rollback in event of failure.
+ *
+ * @param process {Function}            The transaction function
+ * @param successCallback {Function}
+ * @param errorCallback {Function}
+ */
+DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
+    var tx = new DroidDB_Tx();
+    tx.successCallback = successCallback;
+    tx.errorCallback = errorCallback;
+    try {
+        process(tx);
+    } catch (e) {
+        console.log("Transaction error: "+e);
+        if (tx.errorCallback) {
+            try {
+                tx.errorCallback(e);
+            } catch (ex) {
+                console.log("Transaction error calling user error callback: "+e);
+            }
+        }
+    }
+};
+
+/**
+ * Open database
+ *
+ * @param name              Database name
+ * @param version           Database version
+ * @param display_name      Database display name
+ * @param size              Database size in bytes
+ * @return                  Database object
+ */
+var DroidDB_openDatabase = function(name, version, display_name, size) {
+    exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
+    var db = new DatabaseShell();
+    return db;
+};
+
+
+module.exports = {
+  openDatabase:DroidDB_openDatabase,
+  failQuery:failQuery,
+  completeQuery:completeQuery
+};
+
+});
+
+// file: lib/android/plugin/android/storage/openDatabase.js
+define("cordova/plugin/android/storage/openDatabase", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper'),
+    storage = require('cordova/plugin/android/storage');
+
+var originalOpenDatabase = modulemapper.getOriginalSymbol(window, 'openDatabase');
+
+module.exports = function(name, version, desc, size) {
+    // First patch WebSQL if necessary
+    if (!originalOpenDatabase) {
+        // Not defined, create an openDatabase function for all to use!
+        return storage.openDatabase.apply(this, arguments);
+    }
+
+    // Defined, but some Android devices will throw a SECURITY_ERR -
+    // so we wrap the whole thing in a try-catch and shim in our own
+    // if the device has Android bug 16175.
+    try {
+        return originalOpenDatabase(name, version, desc, size);
+    } catch (ex) {
+        if (ex.code !== 18) {
+            throw ex;
+        }
+    }
+    return storage.openDatabase(name, version, desc, size);
+};
+
+
+
+});
+
+// file: lib/android/plugin/android/storage/symbols.js
+define("cordova/plugin/android/storage/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/android/storage/openDatabase', 'openDatabase');
+
+
+});
+
+// file: lib/common/plugin/battery.js
+define("cordova/plugin/battery", function(require, exports, module) {
+
+/**
+ * This class contains information about the current battery status.
+ * @constructor
+ */
+var cordova = require('cordova'),
+    exec = require('cordova/exec');
+
+function handlers() {
+  return battery.channels.batterystatus.numHandlers +
+         battery.channels.batterylow.numHandlers +
+         battery.channels.batterycritical.numHandlers;
+}
+
+var Battery = function() {
+    this._level = null;
+    this._isPlugged = null;
+    // Create new event handlers on the window (returns a channel instance)
+    this.channels = {
+      batterystatus:cordova.addWindowEventHandler("batterystatus"),
+      batterylow:cordova.addWindowEventHandler("batterylow"),
+      batterycritical:cordova.addWindowEventHandler("batterycritical")
+    };
+    for (var key in this.channels) {
+        this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange;
+    }
+};
+/**
+ * Event handlers for when callbacks get registered for the battery.
+ * Keep track of how many handlers we have so we can start and stop the native battery listener
+ * appropriately (and hopefully save on battery life!).
+ */
+Battery.onHasSubscribersChange = function() {
+  // If we just registered the first handler, make sure native listener is started.
+  if (this.numHandlers === 1 && handlers() === 1) {
+      exec(battery._status, battery._error, "Battery", "start", []);
+  } else if (handlers() === 0) {
+      exec(null, null, "Battery", "stop", []);
+  }
+};
+
+/**
+ * Callback for battery status
+ *
+ * @param {Object} info            keys: level, isPlugged
+ */
+Battery.prototype._status = function(info) {
+    if (info) {
+        var me = battery;
+    var level = info.level;
+        if (me._level !== level || me._isPlugged !== info.isPlugged) {
+            // Fire batterystatus event
+            cordova.fireWindowEvent("batterystatus", info);
+
+            // Fire low battery event
+            if (level === 20 || level === 5) {
+                if (level === 20) {
+                    cordova.fireWindowEvent("batterylow", info);
+                }
+                else {
+                    cordova.fireWindowEvent("batterycritical", info);
+                }
+            }
+        }
+        me._level = level;
+        me._isPlugged = info.isPlugged;
+    }
+};
+
+/**
+ * Error callback for battery start
+ */
+Battery.prototype._error = function(e) {
+    console.log("Error initializing Battery: " + e);
+};
+
+var battery = new Battery();
+
+module.exports = battery;
+
+});
+
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
+// file: lib/common/plugin/capture.js
+define("cordova/plugin/capture", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    MediaFile = require('cordova/plugin/MediaFile');
+
+/**
+ * Launches a capture of different types.
+ *
+ * @param (DOMString} type
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+function _capture(type, successCallback, errorCallback, options) {
+    var win = function(pluginResult) {
+        var mediaFiles = [];
+        var i;
+        for (i = 0; i < pluginResult.length; i++) {
+            var mediaFile = new MediaFile();
+            mediaFile.name = pluginResult[i].name;
+            mediaFile.fullPath = pluginResult[i].fullPath;
+            mediaFile.type = pluginResult[i].type;
+            mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate;
+            mediaFile.size = pluginResult[i].size;
+            mediaFiles.push(mediaFile);
+        }
+        successCallback(mediaFiles);
+    };
+    exec(win, errorCallback, "Capture", type, [options]);
+}
+/**
+ * The Capture interface exposes an interface to the camera and microphone of the hosting device.
+ */
+function Capture() {
+    this.supportedAudioModes = [];
+    this.supportedImageModes = [];
+    this.supportedVideoModes = [];
+}
+
+/**
+ * Launch audio recorder application for recording audio clip(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureAudioOptions} options
+ */
+Capture.prototype.captureAudio = function(successCallback, errorCallback, options){
+    _capture("captureAudio", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch camera application for taking image(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureImageOptions} options
+ */
+Capture.prototype.captureImage = function(successCallback, errorCallback, options){
+    _capture("captureImage", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch device camera application for recording video(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+Capture.prototype.captureVideo = function(successCallback, errorCallback, options){
+    _capture("captureVideo", successCallback, errorCallback, options);
+};
+
+
+module.exports = new Capture();
+
+});
+
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
+// file: lib/common/plugin/compass.js
+define("cordova/plugin/compass", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    utils = require('cordova/utils'),
+    CompassHeading = require('cordova/plugin/CompassHeading'),
+    CompassError = require('cordova/plugin/CompassError'),
+    timers = {},
+    compass = {
+        /**
+         * Asynchronously acquires the current heading.
+         * @param {Function} successCallback The function to call when the heading
+         * data is available
+         * @param {Function} errorCallback The function to call when there is an error
+         * getting the heading data.
+         * @param {CompassOptions} options The options for getting the heading data (not used).
+         */
+        getCurrentHeading:function(successCallback, errorCallback, options) {
+            argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments);
+
+            var win = function(result) {
+                var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp);
+                successCallback(ch);
+            };
+            var fail = errorCallback && function(code) {
+                var ce = new CompassError(code);
+                errorCallback(ce);
+            };
+
+            // Get heading
+            exec(win, fail, "Compass", "getHeading", [options]);
+        },
+
+        /**
+         * Asynchronously acquires the heading repeatedly at a given interval.
+         * @param {Function} successCallback The function to call each time the heading
+         * data is available
+         * @param {Function} errorCallback The function to call when there is an error
+         * getting the heading data.
+         * @param {HeadingOptions} options The options for getting the heading data
+         * such as timeout and the frequency of the watch. For iOS, filter parameter
+         * specifies to watch via a distance filter rather than time.
+         */
+        watchHeading:function(successCallback, errorCallback, options) {
+            argscheck.checkArgs('fFO', 'compass.watchHeading', arguments);
+            // Default interval (100 msec)
+            var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100;
+            var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0;
+
+            var id = utils.createUUID();
+            if (filter > 0) {
+                // is an iOS request for watch by filter, no timer needed
+                timers[id] = "iOS";
+                compass.getCurrentHeading(successCallback, errorCallback, options);
+            } else {
+                // Start watch timer to get headings
+                timers[id] = window.setInterval(function() {
+                    compass.getCurrentHeading(successCallback, errorCallback);
+                }, frequency);
+            }
+
+            return id;
+        },
+
+        /**
+         * Clears the specified heading watch.
+         * @param {String} watchId The ID of the watch returned from #watchHeading.
+         */
+        clearWatch:function(id) {
+            // Stop javascript timer & remove from timer list
+            if (id && timers[id]) {
+                if (timers[id] != "iOS") {
+                    clearInterval(timers[id]);
+                } else {
+                    // is iOS watch by filter so call into device to stop
+                    exec(null, null, "Compass", "stopHeading", []);
+                }
+                delete timers[id];
+            }
+        }
+    };
+
+module.exports = compass;
+
+});
+
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
+// file: lib/common/plugin/console-via-logger.js
+define("cordova/plugin/console-via-logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+
+var logger = require("cordova/plugin/logger");
+var utils  = require("cordova/utils");
+
+//------------------------------------------------------------------------------
+// object that we're exporting
+//------------------------------------------------------------------------------
+var console = module.exports;
+
+//------------------------------------------------------------------------------
+// copy of the original console object
+//------------------------------------------------------------------------------
+var WinConsole = window.console;
+
+//------------------------------------------------------------------------------
+// whether to use the logger
+//------------------------------------------------------------------------------
+var UseLogger = false;
+
+//------------------------------------------------------------------------------
+// Timers
+//------------------------------------------------------------------------------
+var Timers = {};
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+function noop() {}
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+console.useLogger = function (value) {
+    if (arguments.length) UseLogger = !!value;
+
+    if (UseLogger) {
+        if (logger.useConsole()) {
+            throw new Error("console and logger are too intertwingly");
+        }
+    }
+
+    return UseLogger;
+};
+
+//------------------------------------------------------------------------------
+console.log = function() {
+    if (logger.useConsole()) return;
+    logger.log.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.error = function() {
+    if (logger.useConsole()) return;
+    logger.error.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.warn = function() {
+    if (logger.useConsole()) return;
+    logger.warn.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.info = function() {
+    if (logger.useConsole()) return;
+    logger.info.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.debug = function() {
+    if (logger.useConsole()) return;
+    logger.debug.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.assert = function(expression) {
+    if (expression) return;
+
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
+    console.log("ASSERT: " + message);
+};
+
+//------------------------------------------------------------------------------
+console.clear = function() {};
+
+//------------------------------------------------------------------------------
+console.dir = function(object) {
+    console.log("%o", object);
+};
+
+//------------------------------------------------------------------------------
+console.dirxml = function(node) {
+    console.log(node.innerHTML);
+};
+
+//------------------------------------------------------------------------------
+console.trace = noop;
+
+//------------------------------------------------------------------------------
+console.group = console.log;
+
+//------------------------------------------------------------------------------
+console.groupCollapsed = console.log;
+
+//------------------------------------------------------------------------------
+console.groupEnd = noop;
+
+//------------------------------------------------------------------------------
+console.time = function(name) {
+    Timers[name] = new Date().valueOf();
+};
+
+//------------------------------------------------------------------------------
+console.timeEnd = function(name) {
+    var timeStart = Timers[name];
+    if (!timeStart) {
+        console.warn("unknown timer: " + name);
+        return;
+    }
+
+    var timeElapsed = new Date().valueOf() - timeStart;
+    console.log(name + ": " + timeElapsed + "ms");
+};
+
+//------------------------------------------------------------------------------
+console.timeStamp = noop;
+
+//------------------------------------------------------------------------------
+console.profile = noop;
+
+//------------------------------------------------------------------------------
+console.profileEnd = noop;
+
+//------------------------------------------------------------------------------
+console.count = noop;
+
+//------------------------------------------------------------------------------
+console.exception = console.log;
+
+//------------------------------------------------------------------------------
+console.table = function(data, columns) {
+    console.log("%o", data);
+};
+
+//------------------------------------------------------------------------------
+// return a new function that calls both functions passed as args
+//------------------------------------------------------------------------------
+function wrappedOrigCall(orgFunc, newFunc) {
+    return function() {
+        var args = [].slice.call(arguments);
+        try { orgFunc.apply(WinConsole, args); } catch (e) {}
+        try { newFunc.apply(console,    args); } catch (e) {}
+    };
+}
+
+//------------------------------------------------------------------------------
+// For every function that exists in the original console object, that
+// also exists in the new console object, wrap the new console method
+// with one that calls both
+//------------------------------------------------------------------------------
+for (var key in console) {
+    if (typeof WinConsole[key] == "function") {
+        console[key] = wrappedOrigCall(WinConsole[key], console[key]);
+    }
+}
+
+});
+
+// file: lib/common/plugin/contacts.js
+define("cordova/plugin/contacts", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError'),
+    utils = require('cordova/utils'),
+    Contact = require('cordova/plugin/Contact');
+
+/**
+* Represents a group of Contacts.
+* @constructor
+*/
+var contacts = {
+    /**
+     * Returns an array of Contacts matching the search criteria.
+     * @param fields that should be searched
+     * @param successCB success callback
+     * @param errorCB error callback
+     * @param {ContactFindOptions} options that can be applied to contact searching
+     * @return array of Contacts matching search criteria
+     */
+    find:function(fields, successCB, errorCB, options) {
+        argscheck.checkArgs('afFO', 'contacts.find', arguments);
+        if (!fields.length) {
+            errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR));
+        } else {
+            var win = function(result) {
+                var cs = [];
+                for (var i = 0, l = result.length; i < l; i++) {
+                    cs.push(contacts.create(result[i]));
+                }
+                successCB(cs);
+            };
+            exec(win, errorCB, "Contacts", "search", [fields, options]);
+        }
+    },
+
+    /**
+     * This function creates a new contact, but it does not persist the contact
+     * to device storage. To persist the contact to device storage, invoke
+     * contact.save().
+     * @param properties an object whose properties will be examined to create a new Contact
+     * @returns new Contact object
+     */
+    create:function(properties) {
+        argscheck.checkArgs('O', 'contacts.create', arguments);
+        var contact = new Contact();
+        for (var i in properties) {
+            if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) {
+                contact[i] = properties[i];
+            }
+        }
+        return contact;
+    }
+};
+
+module.exports = contacts;
+
+});
+
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
+// file: lib/common/plugin/device.js
+define("cordova/plugin/device", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    channel = require('cordova/channel'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec');
+
+// Tell cordova channel to wait on the CordovaInfoReady event
+channel.waitForInitialization('onCordovaInfoReady');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device() {
+    this.available = false;
+    this.platform = null;
+    this.version = null;
+    this.uuid = null;
+    this.cordova = null;
+    this.model = null;
+
+    var me = this;
+
+    channel.onCordovaReady.subscribe(function() {
+        me.getInfo(function(info) {
+            var buildLabel = info.cordova;
+            if (buildLabel != CORDOVA_JS_BUILD_LABEL) {
+                buildLabel += ' JS=' + CORDOVA_JS_BUILD_LABEL;
+            }
+            me.available = true;
+            me.platform = info.platform;
+            me.version = info.version;
+            me.uuid = info.uuid;
+            me.cordova = buildLabel;
+            me.model = info.model;
+            channel.onCordovaInfoReady.fire();
+        },function(e) {
+            me.available = false;
+            utils.alert("[ERROR] Error initializing Cordova: " + e);
+        });
+    });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function(successCallback, errorCallback) {
+    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
+    exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
+};
+
+module.exports = new Device();
+
+});
+
+// file: lib/android/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+modulemapper.merges('cordova/plugin/android/device', 'device');
+
+});
+
+// file: lib/common/plugin/echo.js
+define("cordova/plugin/echo", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
+
+/**
+ * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
+ * @param successCallback  invoked with a FileSystem object
+ * @param errorCallback  invoked if error occurs retrieving file system
+ * @param message  The string to be echoed.
+ * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
+ */
+module.exports = function(successCallback, errorCallback, message, forceAsync) {
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
+    }
+
+    exec(successCallback, errorCallback, "Echo", action, args);
+};
+
+
+});
+
+// file: lib/android/plugin/file/symbols.js
+define("cordova/plugin/file/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper'),
+    symbolshelper = require('cordova/plugin/file/symbolshelper');
+
+symbolshelper(modulemapper.clobbers);
+
+});
+
+// file: lib/common/plugin/file/symbolshelper.js
+define("cordova/plugin/file/symbolshelper", function(require, exports, module) {
+
+module.exports = function(exportFunc) {
+    exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry');
+    exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader');
+    exportFunc('cordova/plugin/Entry', 'Entry');
+    exportFunc('cordova/plugin/File', 'File');
+    exportFunc('cordova/plugin/FileEntry', 'FileEntry');
+    exportFunc('cordova/plugin/FileError', 'FileError');
+    exportFunc('cordova/plugin/FileReader', 'FileReader');
+    exportFunc('cordova/plugin/FileSystem', 'FileSystem');
+    exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
+    exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
+    exportFunc('cordova/plugin/FileWriter', 'FileWriter');
+    exportFunc('cordova/plugin/Flags', 'Flags');
+    exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
+    exportFunc('cordova/plugin/Metadata', 'Metadata');
+    exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
+    exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
+    exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
+};
+
+});
+
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
+// file: lib/common/plugin/geolocation.js
+define("cordova/plugin/geolocation", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    PositionError = require('cordova/plugin/PositionError'),
+    Position = require('cordova/plugin/Position');
+
+var timers = {};   // list of timers in use
+
+// Returns default params, overrides if provided with values
+function parseParameters(options) {
+    var opt = {
+        maximumAge: 0,
+        enableHighAccuracy: false,
+        timeout: Infinity
+    };
+
+    if (options) {
+        if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) {
+            opt.maximumAge = options.maximumAge;
+        }
+        if (options.enableHighAccuracy !== undefined) {
+            opt.enableHighAccuracy = options.enableHighAccuracy;
+        }
+        if (options.timeout !== undefined && !isNaN(options.timeout)) {
+            if (options.timeout < 0) {
+                opt.timeout = 0;
+            } else {
+                opt.timeout = options.timeout;
+            }
+        }
+    }
+
+    return opt;
+}
+
+// Returns a timeout failure, closed over a specified timeout value and error callback.
+function createTimeout(errorCallback, timeout) {
+    var t = setTimeout(function() {
+        clearTimeout(t);
+        t = null;
+        errorCallback({
+            code:PositionError.TIMEOUT,
+            message:"Position retrieval timed out."
+        });
+    }, timeout);
+    return t;
+}
+
+var geolocation = {
+    lastPosition:null, // reference to last known (cached) position returned
+    /**
+   * Asynchronously acquires the current position.
+   *
+   * @param {Function} successCallback    The function to call when the position data is available
+   * @param {Function} errorCallback      The function to call when there is an error getting the heading position. (OPTIONAL)
+   * @param {PositionOptions} options     The options for getting the position data. (OPTIONAL)
+   */
+    getCurrentPosition:function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+        options = parseParameters(options);
+
+        // Timer var that will fire an error callback if no position is retrieved from native
+        // before the "timeout" param provided expires
+        var timeoutTimer = {timer:null};
+
+        var win = function(p) {
+            clearTimeout(timeoutTimer.timer);
+            if (!(timeoutTimer.timer)) {
+                // Timeout already happened, or native fired error callback for
+                // this geo request.
+                // Don't continue with success callback.
+                return;
+            }
+            var pos = new Position(
+                {
+                    latitude:p.latitude,
+                    longitude:p.longitude,
+                    altitude:p.altitude,
+                    accuracy:p.accuracy,
+                    heading:p.heading,
+                    velocity:p.velocity,
+                    altitudeAccuracy:p.altitudeAccuracy
+                },
+                (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+            );
+            geolocation.lastPosition = pos;
+            successCallback(pos);
+        };
+        var fail = function(e) {
+            clearTimeout(timeoutTimer.timer);
+            timeoutTimer.timer = null;
+            var err = new PositionError(e.code, e.message);
+            if (errorCallback) {
+                errorCallback(err);
+            }
+        };
+
+        // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just
+        // fire the success callback with the cached position.
+        if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) {
+            successCallback(geolocation.lastPosition);
+        // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object.
+        } else if (options.timeout === 0) {
+            fail({
+                code:PositionError.TIMEOUT,
+                message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter."
+            });
+        // Otherwise we have to call into native to retrieve a position.
+        } else {
+            if (options.timeout !== Infinity) {
+                // If the timeout value was not set to Infinity (default), then
+                // set up a timeout function that will fire the error callback
+                // if no successful position was retrieved before timeout expired.
+                timeoutTimer.timer = createTimeout(fail, options.timeout);
+            } else {
+                // This is here so the check in the win function doesn't mess stuff up
+                // may seem weird but this guarantees timeoutTimer is
+                // always truthy before we call into native
+                timeoutTimer.timer = true;
+            }
+            exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]);
+        }
+        return timeoutTimer;
+    },
+    /**
+     * Asynchronously watches the geolocation for changes to geolocation.  When a change occurs,
+     * the successCallback is called with the new location.
+     *
+     * @param {Function} successCallback    The function to call each time the location data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the location data. (OPTIONAL)
+     * @param {PositionOptions} options     The options for getting the location data such as frequency. (OPTIONAL)
+     * @return String                       The watch id that must be passed to #clearWatch to stop watching.
+     */
+    watchPosition:function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+        options = parseParameters(options);
+
+        var id = utils.createUUID();
+
+        // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition
+        timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options);
+
+        var fail = function(e) {
+            clearTimeout(timers[id].timer);
+            var err = new PositionError(e.code, e.message);
+            if (errorCallback) {
+                errorCallback(err);
+            }
+        };
+
+        var win = function(p) {
+            clearTimeout(timers[id].timer);
+            if (options.timeout !== Infinity) {
+                timers[id].timer = createTimeout(fail, options.timeout);
+            }
+            var pos = new Position(
+                {
+                    latitude:p.latitude,
+                    longitude:p.longitude,
+                    altitude:p.altitude,
+                    accuracy:p.accuracy,
+                    heading:p.heading,
+                    velocity:p.velocity,
+                    altitudeAccuracy:p.altitudeAccuracy
+                },
+                (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+            );
+            geolocation.lastPosition = pos;
+            successCallback(pos);
+        };
+
+        exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]);
+
+        return id;
+    },
+    /**
+     * Clears the specified heading watch.
+     *
+     * @param {String} id       The ID of the watch returned from #watchPosition
+     */
+    clearWatch:function(id) {
+        if (id && timers[id] !== undefined) {
+            clearTimeout(timers[id].timer);
+            timers[id].timer = false;
+            exec(null, null, "Geolocation", "clearWatch", [id]);
+        }
+    }
+};
+
+module.exports = geolocation;
+
+});
+
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
+// file: lib/common/plugin/globalization.js
+define("cordova/plugin/globalization", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    GlobalizationError = require('cordova/plugin/GlobalizationError');
+
+var globalization = {
+
+/**
+* Returns the string identifier for the client's current language.
+* It returns the language identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the language,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The language identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');},
+*                                function () {});
+*/
+getPreferredLanguage:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments);
+    exec(successCB, failureCB, "Globalization","getPreferredLanguage", []);
+},
+
+/**
+* Returns the string identifier for the client's current locale setting.
+* It returns the locale identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the locale,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The locale identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');},
+*                                function () {});
+*/
+getLocaleName:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments);
+    exec(successCB, failureCB, "Globalization","getLocaleName", []);
+},
+
+
+/**
+* Returns a date formatted as a string according to the client's user preferences and
+* calendar using the time zone of the client. It returns the formatted date string to the
+* successCB callback with a properties object as a parameter. If there is an error
+* formatting the date, then the errorCB callback is invoked.
+*
+* The defaults are: formatLenght="short" and selector="date and time"
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return Object.value {String}: The localized date string
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.dateToString(new Date(),
+*                function (date) {alert('date:' + date.value + '\n');},
+*                function (errorCode) {alert(errorCode);},
+*                {formatLength:'short'});
+*/
+dateToString:function(date, successCB, failureCB, options) {
+    argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments);
+    var dateValue = date.valueOf();
+    exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]);
+},
+
+
+/**
+* Parses a date formatted as a string according to the client's user
+* preferences and calendar using the time zone of the client and returns
+* the corresponding date object. It returns the date to the successCB
+* callback with a properties object as a parameter. If there is an error
+* parsing the date string, then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {String} dateString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return    Object.year {Number}: The four digit year
+*            Object.month {Number}: The month from (0 - 11)
+*            Object.day {Number}: The day from (1 - 31)
+*            Object.hour {Number}: The hour from (0 - 23)
+*            Object.minute {Number}: The minute from (0 - 59)
+*            Object.second {Number}: The second from (0 - 59)
+*            Object.millisecond {Number}: The milliseconds (from 0 - 999),
+*                                        not available on all platforms
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+*    globalization.stringToDate('4/11/2011',
+*                function (date) { alert('Month:' + date.month + '\n' +
+*                    'Day:' + date.day + '\n' +
+*                    'Year:' + date.year + '\n');},
+*                function (errorCode) {alert(errorCode);},
+*                {selector:'date'});
+*/
+stringToDate:function(dateString, successCB, failureCB, options) {
+    argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments);
+    exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]);
+},
+
+
+/**
+* Returns a pattern string for formatting and parsing dates according to the client's
+* user preferences. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern,
+* then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return    Object.pattern {String}: The date and time pattern for formatting and parsing dates.
+*                                    The patterns follow Unicode Technical Standard #35
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.timezone {String}: The abbreviated name of the time zone on the client
+*            Object.utc_offset {Number}: The current difference in seconds between the client's
+*                                        time zone and coordinated universal time.
+*            Object.dst_offset {Number}: The current daylight saving time offset in seconds
+*                                        between the client's non-daylight saving's time zone
+*                                        and the client's daylight saving's time zone.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+*    globalization.getDatePattern(
+*                function (date) {alert('pattern:' + date.pattern + '\n');},
+*                function () {},
+*                {formatLength:'short'});
+*/
+getDatePattern:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]);
+},
+
+
+/**
+* Returns an array of either the names of the months or days of the week
+* according to the client's user preferences and calendar. It returns the array of names to the
+* successCB callback with a properties object as a parameter. If there is an error obtaining the
+* names, then the errorCB callback is invoked.
+*
+* The defaults are: type="wide" and item="months"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'narrow' or 'wide'
+*            item {String}: 'months', or 'days'
+*
+* @return Object.value {Array{String}}: The array of names starting from either
+*                                        the first month in the year or the
+*                                        first day of the week.
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getDateNames(function (names) {
+*        for(var i = 0; i < names.value.length; i++) {
+*            alert('Month:' + names.value[i] + '\n');}},
+*        function () {});
+*/
+getDateNames:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments);
+    exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]);
+},
+
+/**
+* Returns whether daylight savings time is in effect for a given date using the client's
+* time zone and calendar. It returns whether or not daylight savings time is in effect
+* to the successCB callback with a properties object as a parameter. If there is an error
+* reading the date, then the errorCB callback is invoked.
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is
+*                                in effect for the given date and "false" indicate that it is not.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.isDayLightSavingsTime(new Date(),
+*                function (date) {alert('dst:' + date.dst + '\n');}
+*                function () {});
+*/
+isDayLightSavingsTime:function(date, successCB, failureCB) {
+    argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments);
+    var dateValue = date.valueOf();
+    exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]);
+},
+
+/**
+* Returns the first day of the week according to the client's user preferences and calendar.
+* The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+* It returns the day to the successCB callback with a properties object as a parameter.
+* If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {Number}: The number of the first day of the week.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getFirstDayOfWeek(function (day)
+*                { alert('Day:' + day.value + '\n');},
+*                function () {});
+*/
+getFirstDayOfWeek:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments);
+    exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []);
+},
+
+
+/**
+* Returns a number formatted as a string according to the client's user preferences.
+* It returns the formatted number string to the successCB callback with a properties object as a
+* parameter. If there is an error formatting the number, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Number} number
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {String}: The formatted number string.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.numberToString(3.25,
+*                function (number) {alert('number:' + number.value + '\n');},
+*                function () {},
+*                {type:'decimal'});
+*/
+numberToString:function(number, successCB, failureCB, options) {
+    argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments);
+    exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]);
+},
+
+/**
+* Parses a number formatted as a string according to the client's user preferences and
+* returns the corresponding number. It returns the number to the successCB callback with a
+* properties object as a parameter. If there is an error parsing the number string, then
+* the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {String} numberString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {Number}: The parsed number.
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+*    globalization.stringToNumber('1234.56',
+*                function (number) {alert('Number:' + number.value + '\n');},
+*                function () { alert('Error parsing number');});
+*/
+stringToNumber:function(numberString, successCB, failureCB, options) {
+    argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments);
+    exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing numbers according to the client's user
+* preferences. It returns the pattern to the successCB callback with a properties object as a
+* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return    Object.pattern {String}: The number pattern for formatting and parsing numbers.
+*                                    The patterns follow Unicode Technical Standard #35.
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.symbol {String}: The symbol to be used when formatting and parsing
+*                                    e.g., percent or currency symbol.
+*            Object.fraction {Number}: The number of fractional digits to use when parsing and
+*                                    formatting numbers.
+*            Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+*            Object.positive {String}: The symbol to use for positive numbers when parsing and formatting.
+*            Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting.
+*            Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+*            Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+*    globalization.getNumberPattern(
+*                function (pattern) {alert('Pattern:' + pattern.pattern + '\n');},
+*                function () {});
+*/
+getNumberPattern:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing currency values according to the client's
+* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB
+* callback is invoked.
+*
+* @param {String} currencyCode
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return    Object.pattern {String}: The currency pattern for formatting and parsing currency values.
+*                                    The patterns follow Unicode Technical Standard #35
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.code {String}: The ISO 4217 currency code for the pattern.
+*            Object.fraction {Number}: The number of fractional digits to use when parsing and
+*                                    formatting currency.
+*            Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+*            Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+*            Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.getCurrencyPattern('EUR',
+*                function (currency) {alert('Pattern:' + currency.pattern + '\n');}
+*                function () {});
+*/
+getCurrencyPattern:function(currencyCode, successCB, failureCB) {
+    argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]);
+}
+
+};
+
+module.exports = globalization;
+
+});
+
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
+// file: lib/android/plugin/inappbrowser/symbols.js
+define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
+// file: lib/common/plugin/logger.js
+define("cordova/plugin/logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+// The logger module exports the following properties/functions:
+//
+// LOG                          - constant for the level LOG
+// ERROR                        - constant for the level ERROR
+// WARN                         - constant for the level WARN
+// INFO                         - constant for the level INFO
+// DEBUG                        - constant for the level DEBUG
+// logLevel()                   - returns current log level
+// logLevel(value)              - sets and returns a new log level
+// useConsole()                 - returns whether logger is using console
+// useConsole(value)            - sets and returns whether logger is using console
+// log(message,...)             - logs a message at level LOG
+// error(message,...)           - logs a message at level ERROR
+// warn(message,...)            - logs a message at level WARN
+// info(message,...)            - logs a message at level INFO
+// debug(message,...)           - logs a message at level DEBUG
+// logLevel(level,message,...)  - logs a message specified level
+//
+//------------------------------------------------------------------------------
+
+var logger = exports;
+
+var exec    = require('cordova/exec');
+var utils   = require('cordova/utils');
+
+var UseConsole   = true;
+var UseLogger    = true;
+var Queued       = [];
+var DeviceReady  = false;
+var CurrentLevel;
+
+var originalConsole = console;
+
+/**
+ * Logging levels
+ */
+
+var Levels = [
+    "LOG",
+    "ERROR",
+    "WARN",
+    "INFO",
+    "DEBUG"
+];
+
+/*
+ * add the logging levels to the logger object and
+ * to a separate levelsMap object for testing
+ */
+
+var LevelsMap = {};
+for (var i=0; i<Levels.length; i++) {
+    var level = Levels[i];
+    LevelsMap[level] = i;
+    logger[level]    = level;
+}
+
+CurrentLevel = LevelsMap.WARN;
+
+/**
+ * Getter/Setter for the logging level
+ *
+ * Returns the current logging level.
+ *
+ * When a value is passed, sets the logging level to that value.
+ * The values should be one of the following constants:
+ *    logger.LOG
+ *    logger.ERROR
+ *    logger.WARN
+ *    logger.INFO
+ *    logger.DEBUG
+ *
+ * The value used determines which messages get printed.  The logging
+ * values above are in order, and only messages logged at the logging
+ * level or above will actually be displayed to the user.  E.g., the
+ * default level is WARN, so only messages logged with LOG, ERROR, or
+ * WARN will be displayed; INFO and DEBUG messages will be ignored.
+ */
+logger.level = function (value) {
+    if (arguments.length) {
+        if (LevelsMap[value] === null) {
+            throw new Error("invalid logging level: " + value);
+        }
+        CurrentLevel = LevelsMap[value];
+    }
+
+    return Levels[CurrentLevel];
+};
+
+/**
+ * Getter/Setter for the useConsole functionality
+ *
+ * When useConsole is true, the logger will log via the
+ * browser 'console' object.
+ */
+logger.useConsole = function (value) {
+    if (arguments.length) UseConsole = !!value;
+
+    if (UseConsole) {
+        if (typeof console == "undefined") {
+            throw new Error("global console object is not defined");
+        }
+
+        if (typeof console.log != "function") {
+            throw new Error("global console object does not have a log function");
+        }
+
+        if (typeof console.useLogger == "function") {
+            if (console.useLogger()) {
+                throw new Error("console and logger are too intertwingly");
+            }
+        }
+    }
+
+    return UseConsole;
+};
+
+/**
+ * Getter/Setter for the useLogger functionality
+ *
+ * When useLogger is true, the logger will log via the
+ * native Logger plugin.
+ */
+logger.useLogger = function (value) {
+    // Enforce boolean
+    if (arguments.length) UseLogger = !!value;
+    return UseLogger;
+};
+
+/**
+ * Logs a message at the LOG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.log   = function(message) { logWithArgs("LOG",   arguments); };
+
+/**
+ * Logs a message at the ERROR level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.error = function(message) { logWithArgs("ERROR", arguments); };
+
+/**
+ * Logs a message at the WARN level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.warn  = function(message) { logWithArgs("WARN",  arguments); };
+
+/**
+ * Logs a message at the INFO level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.info  = function(message) { logWithArgs("INFO",  arguments); };
+
+/**
+ * Logs a message at the DEBUG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.debug = function(message) { logWithArgs("DEBUG", arguments); };
+
+// log at the specified level with args
+function logWithArgs(level, args) {
+    args = [level].concat([].slice.call(args));
+    logger.logLevel.apply(logger, args);
+}
+
+/**
+ * Logs a message at the specified level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.logLevel = function(level /* , ... */) {
+    // format the message with the parameters
+    var formatArgs = [].slice.call(arguments, 1);
+    var message    = logger.format.apply(logger.format, formatArgs);
+
+    if (LevelsMap[level] === null) {
+        throw new Error("invalid logging level: " + level);
+    }
+
+    if (LevelsMap[level] > CurrentLevel) return;
+
+    // queue the message if not yet at deviceready
+    if (!DeviceReady && !UseConsole) {
+        Queued.push([level, message]);
+        return;
+    }
+
+    // Log using the native logger if that is enabled
+    if (UseLogger) {
+        exec(null, null, "Logger", "logLevel", [level, message]);
+    }
+
+    // Log using the console if that is enabled
+    if (UseConsole) {
+        // make sure console is not using logger
+        if (console.__usingCordovaLogger) {
+            throw new Error("console and logger are too intertwingly");
+        }
+
+        // log to the console
+        switch (level) {
+            case logger.LOG:   originalConsole.log(message); break;
+            case logger.ERROR: originalConsole.log("ERROR: " + message); break;
+            case logger.WARN:  originalConsole.log("WARN: "  + message); break;
+            case logger.INFO:  originalConsole.log("INFO: "  + message); break;
+            case logger.DEBUG: originalConsole.log("DEBUG: " + message); break;
+        }
+    }
+};
+
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+    if (formatString === null || formatString === undefined) return [""];
+    if (arguments.length == 1) return [formatString.toString()];
+
+    if (typeof formatString != "string")
+        formatString = formatString.toString();
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest    = formatString;
+    var result  = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg   = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] == '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+    try {
+        switch(formatChar) {
+            case 'j':
+            case 'o': return JSON.stringify(object);
+            case 'c': return '';
+        }
+    }
+    catch (e) {
+        return "error JSON.stringify()ing argument: " + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
+// when deviceready fires, log queued messages
+logger.__onDeviceReady = function() {
+    if (DeviceReady) return;
+
+    DeviceReady = true;
+
+    for (var i=0; i<Queued.length; i++) {
+        var messageArgs = Queued[i];
+        logger.logLevel(messageArgs[0], messageArgs[1]);
+    }
+
+    Queued = null;
+};
+
+// add a deviceready event to log queued messages
+document.addEventListener("deviceready", logger.__onDeviceReady, false);
+
+});
+
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/android/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.clobbers('cordova/plugin/MediaError', 'MediaError');
+
+});
+
+// file: lib/common/plugin/network.js
+define("cordova/plugin/network", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    cordova = require('cordova'),
+    channel = require('cordova/channel'),
+    utils = require('cordova/utils');
+
+// Link the onLine property with the Cordova-supplied network info.
+// This works because we clobber the naviagtor object with our own
+// object in bootstrap.js.
+if (typeof navigator != 'undefined') {
+    utils.defineGetter(navigator, 'onLine', function() {
+        return this.connection.type != 'none';
+    });
+}
+
+function NetworkConnection() {
+    this.type = 'unknown';
+}
+
+/**
+ * Get connection info
+ *
+ * @param {Function} successCallback The function to call when the Connection data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL)
+ */
+NetworkConnection.prototype.getInfo = function(successCallback, errorCallback) {
+    exec(successCallback, errorCallback, "NetworkStatus", "getConnectionInfo", []);
+};
+
+var me = new NetworkConnection();
+var timerId = null;
+var timeout = 500;
+
+channel.onCordovaReady.subscribe(function() {
+    me.getInfo(function(info) {
+        me.type = info;
+        if (info === "none") {
+            // set a timer if still offline at the end of timer send the offline event
+            timerId = setTimeout(function(){
+                cordova.fireDocumentEvent("offline");
+                timerId = null;
+            }, timeout);
+        } else {
+            // If there is a current offline event pending clear it
+            if (timerId !== null) {
+                clearTimeout(timerId);
+                timerId = null;
+            }
+            cordova.fireDocumentEvent("online");
+        }
+
+        // should only fire this once
+        if (channel.onCordovaConnectionReady.state !== 2) {
+            channel.onCordovaConnectionReady.fire();
+        }
+    },
+    function (e) {
+        // If we can't get the network info we should still tell Cordova
+        // to fire the deviceready event.
+        if (channel.onCordovaConnectionReady.state !== 2) {
+            channel.onCordovaConnectionReady.fire();
+        }
+        console.log("Error initializing Network Connection: " + e);
+    });
+});
+
+module.exports = me;
+
+});
+
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
+// file: lib/common/plugin/notification.js
+define("cordova/plugin/notification", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var platform = require('cordova/platform');
+
+/**
+ * Provides access to notifications on the device.
+ */
+
+module.exports = {
+
+    /**
+     * Open a native alert dialog, with a customizable title and button text.
+     *
+     * @param {String} message              Message to print in the body of the alert
+     * @param {Function} completeCallback   The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the alert dialog (default: Alert)
+     * @param {String} buttonLabel          Label of the close button (default: OK)
+     */
+    alert: function(message, completeCallback, title, buttonLabel) {
+        var _title = (title || "Alert");
+        var _buttonLabel = (buttonLabel || "OK");
+        exec(completeCallback, null, "Notification", "alert", [message, _title, _buttonLabel]);
+    },
+
+    /**
+     * Open a native confirm dialog, with a customizable title and button text.
+     * The result that the user selects is returned to the result callback.
+     *
+     * @param {String} message              Message to print in the body of the alert
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the alert dialog (default: Confirm)
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
+     */
+    confirm: function(message, resultCallback, title, buttonLabels) {
+        var _title = (title || "Confirm");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Some platforms take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone" || platform.id == "blackberry10") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
+        exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
+    },
+
+    /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     * @param {String} defaultText          Textbox input value (default: "Default text")
+     */
+    prompt: function(message, resultCallback, title, buttonLabels, defaultText) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        var _defaultText = (defaultText || "Default text");
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels, _defaultText]);
+    },
+
+    /**
+     * Causes the device to vibrate.
+     *
+     * @param {Integer} mills       The number of milliseconds to vibrate for.
+     */
+    vibrate: function(mills) {
+        exec(null, null, "Notification", "vibrate", [mills]);
+    },
+
+    /**
+     * Causes the device to beep.
+     * On Android, the default notification ringtone is played "count" times.
+     *
+     * @param {Integer} count       The number of beeps.
+     */
+    beep: function(count) {
+        exec(null, null, "Notification", "beep", [count]);
+    }
+};
+
+});
+
+// file: lib/android/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/notification', 'navigator.notification');
+modulemapper.merges('cordova/plugin/android/notification', 'navigator.notification');
+
+});
+
+// file: lib/common/plugin/requestFileSystem.js
+define("cordova/plugin/requestFileSystem", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    FileError = require('cordova/plugin/FileError'),
+    FileSystem = require('cordova/plugin/FileSystem'),
+    exec = require('cordova/exec');
+
+/**
+ * Request a file system in which to store application data.
+ * @param type  local file system type
+ * @param size  indicates how much storage space, in bytes, the application expects to need
+ * @param successCallback  invoked with a FileSystem object
+ * @param errorCallback  invoked if error occurs retrieving file system
+ */
+var requestFileSystem = function(type, size, successCallback, errorCallback) {
+    argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
+    var fail = function(code) {
+        errorCallback && errorCallback(new FileError(code));
+    };
+
+    if (type < 0 || type > 3) {
+        fail(FileError.SYNTAX_ERR);
+    } else {
+        // if successful, return a FileSystem object
+        var success = function(file_system) {
+            if (file_system) {
+                if (successCallback) {
+                    // grab the name and root from the file system object
+                    var result = new FileSystem(file_system.name, file_system.root);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no FileSystem object returned
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+        exec(success, fail, "File", "requestFileSystem", [type, size]);
+    }
+};
+
+module.exports = requestFileSystem;
+
+});
+
+// file: lib/common/plugin/resolveLocalFileSystemURI.js
+define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
+    FileEntry = require('cordova/plugin/FileEntry'),
+    FileError = require('cordova/plugin/FileError'),
+    exec = require('cordova/exec');
+
+/**
+ * Look up file system Entry referred to by local URI.
+ * @param {DOMString} uri  URI referring to a local file or directory
+ * @param successCallback  invoked with Entry object corresponding to URI
+ * @param errorCallback    invoked if error occurs retrieving file system entry
+ */
+module.exports = function(uri, successCallback, errorCallback) {
+    argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
+    // error callback
+    var fail = function(error) {
+        errorCallback && errorCallback(new FileError(error));
+    };
+    // sanity check for 'not:valid:filename'
+    if(!uri || uri.split(":").length > 2) {
+        setTimeout( function() {
+            fail(FileError.ENCODING_ERR);
+        },0);
+        return;
+    }
+    // if successful, return either a file or directory entry
+    var success = function(entry) {
+        var result;
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath);
+                successCallback(result);
+            }
+        }
+        else {
+            // no Entry object returned
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    };
+
+    exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]);
+};
+
+});
+
+// file: lib/common/plugin/splashscreen.js
+define("cordova/plugin/splashscreen", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+var splashscreen = {
+    show:function() {
+        exec(null, null, "SplashScreen", "show", []);
+    },
+    hide:function() {
+        exec(null, null, "SplashScreen", "hide", []);
+    }
+};
+
+module.exports = splashscreen;
+
+});
+
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
+// file: lib/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function(a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] == item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function(a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index != -1) {
+        a.splice(index, 1);
+    }
+    return index != -1;
+};
+
+utils.typeName = function(val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = function(a) {
+    return utils.typeName(a) == 'Array';
+};
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function(d) {
+    return utils.typeName(d) == 'Date';
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function(obj) {
+    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if(utils.isArray(obj)){
+        retVal = [];
+        for(i = 0; i < obj.length; ++i){
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for(i in obj){
+        if(!(i in retVal) || retVal[i] != obj[i]) {
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function(context, func, params) {
+    if (typeof params == 'undefined') {
+        return function() {
+            return func.apply(context, arguments);
+        };
+    } else {
+        return function() {
+            return func.apply(context, params);
+        };
+    }
+};
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function() {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function() {
+    // proxy used to establish prototype chain
+    var F = function() {};
+    // extend Child from Parent
+    return function(Child, Parent) {
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function(msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+
+//------------------------------------------------------------------------------
+function UUIDcreatePart(length) {
+    var uuidpart = "";
+    for (var i=0; i<length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length == 1) {
+            uuidchar = "0" + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+
+});
+
+window.cordova = require('cordova');
+// file: lib/scripts/bootstrap.js
+
+(function (context) {
+    if (context._cordovaJsLoaded) {
+        throw new Error('cordova.js included multiple times.');
+    }
+    context._cordovaJsLoaded = true;
+
+    var channel = require('cordova/channel');
+    var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+    function logUnfiredChannels(arr) {
+        for (var i = 0; i < arr.length; ++i) {
+            if (arr[i].state != 2) {
+                console.log('Channel not fired: ' + arr[i].type);
+            }
+        }
+    }
+
+    window.setTimeout(function() {
+        if (channel.onDeviceReady.state != 2) {
+            console.log('deviceready has not fired after 5 seconds.');
+            logUnfiredChannels(platformInitChannelsArray);
+            logUnfiredChannels(channel.deviceReadyChannelsArray);
+        }
+    }, 5000);
+
+    // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+    // We replace it so that properties that can't be clobbered can instead be overridden.
+    function replaceNavigator(origNavigator) {
+        var CordovaNavigator = function() {};
+        CordovaNavigator.prototype = origNavigator;
+        var newNavigator = new CordovaNavigator();
+        // This work-around really only applies to new APIs that are newer than Function.bind.
+        // Without it, APIs such as getGamepads() break.
+        if (CordovaNavigator.bind) {
+            for (var key in origNavigator) {
+                if (typeof origNavigator[key] == 'function') {
+                    newNavigator[key] = origNavigator[key].bind(origNavigator);
+                }
+            }
+        }
+        return newNavigator;
+    }
+    if (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
+    }
+
+    // _nativeReady is global variable that the native side can set
+    // to signify that the native code is ready. It is a global since
+    // it may be called before any cordova JS is ready.
+    if (window._nativeReady) {
+        channel.onNativeReady.fire();
+    }
+
+    /**
+     * Create all cordova objects once native side is ready.
+     */
+    channel.join(function() {
+        // Call the platform-specific initialization
+        require('cordova/platform').initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once page has fully loaded, all
+        // constructors have run and cordova info has been received from native
+        // side.
+        // This join call is deliberately made after platform.initialize() in
+        // order that plugins may manipulate channel.deviceReadyChannelsArray
+        // if necessary.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, platformInitChannelsArray);
+
+}(window));
+
+// file: lib/scripts/bootstrap-android.js
+
+require('cordova/channel').onNativeReady.fire();
+
+// file: lib/scripts/plugin_loader.js
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json content.
+    // See plugman's plugin_loader.js for the details of this object.
+    // This function is only called if the really is a plugins array that isn't empty.
+    // Otherwise the XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules, path) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
+
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
+
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    context.cordova.require(module.id);
+                }
+            }
+
+            finishPluginLoading();
+        };
+
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(path + modules[i].file);
+        }
+    }
+
+    // Find the root of the app
+    var path = '';
+    var scripts = document.getElementsByTagName('script');
+    var term = 'cordova.js';
+    for (var n = scripts.length-1; n>-1; n--) {
+        var src = scripts[n].src;
+        if (src.indexOf(term) == (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length);
+            break;
+        }
+    }
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new XMLHttpRequest();
+    xhr.onload = function() {
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        var obj;
+        try {
+            obj = (this.status == 0 || this.status == 200) && this.responseText && JSON.parse(this.responseText);
+        } catch (err) {
+            // obj will be undefined.
+        }
+        if (Array.isArray(obj) && obj.length > 0) {
+            handlePluginsObject(obj, path);
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.onerror = function() {
+        finishPluginLoading();
+    };
+    var plugins_json = path + 'cordova_plugins.json';
+    try { // we commented we were going to try, so let us actually try and catch
+        xhr.open('GET', plugins_json, true); // Async
+        xhr.send();
+    } catch(err){
+        finishPluginLoading();
+    }
+}(window));
+
+
+})();
\ No newline at end of file
diff --git a/js/libs/phonegap/2.8.1/cordova-ios.js b/js/libs/phonegap/2.8.1/cordova-ios.js
new file mode 100644 (file)
index 0000000..d90a720
--- /dev/null
@@ -0,0 +1,6452 @@
+// Platform: ios
+// 2.8.0-0-g6208c95
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+     http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+;(function() {
+var CORDOVA_JS_BUILD_LABEL = '2.8.0-0-g6208c95';
+// file: lib/scripts/require.js
+
+var require,
+    define;
+
+(function () {
+    var modules = {},
+    // Stack of moduleIds currently being built.
+        requireStack = [],
+    // Map of module ID -> index into requireStack of modules currently being built.
+        inProgressModules = {},
+        SEPERATOR = ".";
+
+
+
+    function build(module) {
+        var factory = module.factory,
+            localRequire = function (id) {
+                var resultantId = id;
+                //Its a relative path, so lop off the last portion and add the id (minus "./")
+                if (id.charAt(0) === ".") {
+                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2);
+                }
+                return require(resultantId);
+            };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw "module " + id + " not found";
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw "Cycle in require graph: " + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw "module " + id + " already defined";
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+    channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+    channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+    windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] != 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] != 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] != "undefined") {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] != "undefined") {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent(type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+if(typeof window.console === "undefined") {
+    window.console = {
+        log:function(){}
+    };
+}
+
+var cordova = {
+    define:define,
+    require:require,
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler:function(event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler:function(event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler:function(event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function() {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function(type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] != 'undefined') {
+            if( bNoDetach ) {
+              documentEventHandlers[type].fire(evt);
+            }
+            else {
+              setTimeout(function() {
+                  // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                  if (type == 'deviceready') {
+                      document.dispatchEvent(evt);
+                  }
+                  documentEventHandlers[type].fire(evt);
+              }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function(type, data) {
+        var evt = createEvent(type,data);
+        if (typeof windowEventHandlers[type] != 'undefined') {
+            setTimeout(function() {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks:  {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function(callbackId, args) {
+        try {
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function(callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        try {
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+        var callback = cordova.callbacks[callbackId];
+        if (callback) {
+            if (success && status == cordova.callbackStatus.OK) {
+                callback.success && callback.success.apply(null, args);
+            } else if (!success) {
+                callback.fail && callback.fail.apply(null, args);
+            }
+
+            // Clear callback if not expecting any more results
+            if (!keepCallback) {
+                delete cordova.callbacks[callbackId];
+            }
+        }
+    },
+    addConstructor: function(func) {
+        channel.onCordovaReady.subscribe(function() {
+            try {
+                func();
+            } catch(e) {
+                console.log("Failed to run constructor: " + e);
+            }
+        });
+    }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+  return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i),
+            cUpper = c.toUpperCase(),
+            arg = args[i];
+        // Asterix means allow anything.
+        if (c == '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c == cUpper) {
+            continue;
+        }
+        if (typeName != typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running jake test.
+        if (typeof jasmine == 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue(value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    obj[key] = value;
+    // Getters can only be overridden by getters.
+    if (obj[key] !== value) {
+        utils.defineGetter(obj, key, function() {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function() {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include(parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+          var result = obj.path ? require(obj.path) : {};
+
+          if (clobber) {
+              // Clobber if it doesn't exist.
+              if (typeof parent[key] === 'undefined') {
+                  assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+              } else if (typeof obj.path !== 'undefined') {
+                  // If merging, merge properties onto parent, otherwise, clobber.
+                  if (merge) {
+                      recursiveMerge(parent[key], result);
+                  } else {
+                      assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                  }
+              }
+              result = parent[key];
+          } else {
+            // Overwrite if not currently defined.
+            if (typeof parent[key] == 'undefined') {
+              assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+            } else {
+              // Set result to what already exists, so we can build children into it if they exist.
+              result = parent[key];
+            }
+          }
+
+          if (obj.children) {
+            include(result, obj.children, clobber, merge);
+          }
+        } catch(e) {
+          utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady*         Internal event fired when device properties are available.
+ * onCordovaConnectionReady*   Internal event fired when the connection property has been set.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function(type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+},
+    channel = {
+        /**
+         * Calls the provided function only after all of the channels specified
+         * have been fired. All channels must be sticky channels.
+         */
+        join: function(h, c) {
+            var len = c.length,
+                i = len,
+                f = function() {
+                    if (!(--i)) h();
+                };
+            for (var j=0; j<len; j++) {
+                if (c[j].state === 0) {
+                    throw Error('Can only use join with sticky channels.');
+                }
+                c[j].subscribe(f);
+            }
+            if (!len) h();
+        },
+        create: function(type) {
+            return channel[type] = new Channel(type, false);
+        },
+        createSticky: function(type) {
+            return channel[type] = new Channel(type, true);
+        },
+
+        /**
+         * cordova Channels that must fire before "deviceready" is fired.
+         */
+        deviceReadyChannelsArray: [],
+        deviceReadyChannelsMap: {},
+
+        /**
+         * Indicate that a feature needs to be initialized before it is ready to be used.
+         * This holds up Cordova's "deviceready" event until the feature has been initialized
+         * and Cordova.initComplete(feature) is called.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        waitForInitialization: function(feature) {
+            if (feature) {
+                var c = channel[feature] || this.createSticky(feature);
+                this.deviceReadyChannelsMap[feature] = c;
+                this.deviceReadyChannelsArray.push(c);
+            }
+        },
+
+        /**
+         * Indicate that initialization code has completed and the feature is ready to be used.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        initializationComplete: function(feature) {
+            var c = this.deviceReadyChannelsMap[feature];
+            if (c) {
+                c.fire();
+            }
+        }
+    };
+
+function forceFunction(f) {
+    if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+    // need a function to call
+    forceFunction(f);
+    if (this.state == 2) {
+        f.apply(c || this, this.fireArgs);
+        return;
+    }
+
+    var func = f,
+        guid = f.observer_guid;
+    if (typeof c == "object") { func = utils.close(c, f); }
+
+    if (!guid) {
+        // first time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    func.observer_guid = guid;
+    f.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = func;
+        this.numHandlers++;
+        if (this.numHandlers == 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+    // need a function to unsubscribe
+    forceFunction(f);
+
+    var guid = f.observer_guid,
+        handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+    var fail = false,
+        fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state == 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state == 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib/common/commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add:function(id,proxyObj) {
+        console.log("adding proxy for " + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove:function(id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get:function(service,action) {
+        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+    }
+};
+});
+
+// file: lib/ios/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Creates a gap bridge iframe used to notify the native code about queued
+ * commands.
+ *
+ * @private
+ */
+var cordova = require('cordova'),
+    channel = require('cordova/channel'),
+    utils = require('cordova/utils'),
+    jsToNativeModes = {
+        IFRAME_NAV: 0,
+        XHR_NO_PAYLOAD: 1,
+        XHR_WITH_PAYLOAD: 2,
+        XHR_OPTIONAL_PAYLOAD: 3
+    },
+    bridgeMode,
+    execIframe,
+    execXhr,
+    requestCount = 0,
+    vcHeaderValue = null,
+    commandQueue = [], // Contains pending JS->Native messages.
+    isInContextOfEvalJs = 0;
+
+function createExecIframe() {
+    var iframe = document.createElement("iframe");
+    iframe.style.display = 'none';
+    document.body.appendChild(iframe);
+    return iframe;
+}
+
+function shouldBundleCommandJson() {
+    if (bridgeMode == jsToNativeModes.XHR_WITH_PAYLOAD) {
+        return true;
+    }
+    if (bridgeMode == jsToNativeModes.XHR_OPTIONAL_PAYLOAD) {
+        var payloadLength = 0;
+        for (var i = 0; i < commandQueue.length; ++i) {
+            payloadLength += commandQueue[i].length;
+        }
+        // The value here was determined using the benchmark within CordovaLibApp on an iPad 3.
+        return payloadLength < 4500;
+    }
+    return false;
+}
+
+function massageArgsJsToNative(args) {
+    if (!args || utils.typeName(args) != 'Array') {
+       return args;
+    }
+    var ret = [];
+    var encodeArrayBufferAs8bitString = function(ab) {
+        return String.fromCharCode.apply(null, new Uint8Array(ab));
+    };
+    var encodeArrayBufferAsBase64 = function(ab) {
+        return window.btoa(encodeArrayBufferAs8bitString(ab));
+    };
+    args.forEach(function(arg, i) {
+        if (utils.typeName(arg) == 'ArrayBuffer') {
+            ret.push({
+                'CDVType': 'ArrayBuffer',
+                'data': encodeArrayBufferAsBase64(arg)
+            });
+        } else {
+            ret.push(arg);
+        }
+    });
+    return ret;
+}
+
+function massageMessageNativeToJs(message) {
+    if (message.CDVType == 'ArrayBuffer') {
+        var stringToArrayBuffer = function(str) {
+            var ret = new Uint8Array(str.length);
+            for (var i = 0; i < str.length; i++) {
+                ret[i] = str.charCodeAt(i);
+            }
+            return ret.buffer;
+        };
+        var base64ToArrayBuffer = function(b64) {
+            return stringToArrayBuffer(atob(b64));
+        };
+        message = base64ToArrayBuffer(message.data);
+    }
+    return message;
+}
+
+function convertMessageToArgsNativeToJs(message) {
+    var args = [];
+    if (!message || !message.hasOwnProperty('CDVType')) {
+        args.push(message);
+    } else if (message.CDVType == 'MultiPart') {
+        message.messages.forEach(function(e) {
+            args.push(massageMessageNativeToJs(e));
+        });
+    } else {
+        args.push(massageMessageNativeToJs(message));
+    }
+    return args;
+}
+
+function iOSExec() {
+    // XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices.
+    // XHR mode's main advantage is working around a bug in -webkit-scroll, which
+    // doesn't exist in 4.X devices anyways.
+    if (bridgeMode === undefined) {
+        bridgeMode = navigator.userAgent.indexOf(' 4_') == -1 ? jsToNativeModes.XHR_NO_PAYLOAD : jsToNativeModes.IFRAME_NAV;
+    }
+
+    var successCallback, failCallback, service, action, actionArgs, splitCommand;
+    var callbackId = null;
+    if (typeof arguments[0] !== "string") {
+        // FORMAT ONE
+        successCallback = arguments[0];
+        failCallback = arguments[1];
+        service = arguments[2];
+        action = arguments[3];
+        actionArgs = arguments[4];
+
+        // Since we need to maintain backwards compatibility, we have to pass
+        // an invalid callbackId even if no callback was provided since plugins
+        // will be expecting it. The Cordova.exec() implementation allocates
+        // an invalid callbackId and passes it even if no callbacks were given.
+        callbackId = 'INVALID';
+    } else {
+        // FORMAT TWO, REMOVED
+       try {
+           splitCommand = arguments[0].split(".");
+           action = splitCommand.pop();
+           service = splitCommand.join(".");
+           actionArgs = Array.prototype.splice.call(arguments, 1);
+
+           console.log('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' +
+                       "cordova.exec(null, null, \"" + service + "\", " + action + "\"," + JSON.stringify(actionArgs) + ");"
+                       );
+           return;
+       } catch (e) {
+       }
+    }
+
+    // Register the callbacks and add the callbackId to the positional
+    // arguments if given.
+    if (successCallback || failCallback) {
+        callbackId = service + cordova.callbackId++;
+        cordova.callbacks[callbackId] =
+            {success:successCallback, fail:failCallback};
+    }
+
+    actionArgs = massageArgsJsToNative(actionArgs);
+
+    var command = [callbackId, service, action, actionArgs];
+
+    // Stringify and queue the command. We stringify to command now to
+    // effectively clone the command arguments in case they are mutated before
+    // the command is executed.
+    commandQueue.push(JSON.stringify(command));
+
+    // If we're in the context of a stringByEvaluatingJavaScriptFromString call,
+    // then the queue will be flushed when it returns; no need for a poke.
+    // Also, if there is already a command in the queue, then we've already
+    // poked the native side, so there is no reason to do so again.
+    if (!isInContextOfEvalJs && commandQueue.length == 1) {
+        if (bridgeMode != jsToNativeModes.IFRAME_NAV) {
+            // This prevents sending an XHR when there is already one being sent.
+            // This should happen only in rare circumstances (refer to unit tests).
+            if (execXhr && execXhr.readyState != 4) {
+                execXhr = null;
+            }
+            // Re-using the XHR improves exec() performance by about 10%.
+            execXhr = execXhr || new XMLHttpRequest();
+            // Changing this to a GET will make the XHR reach the URIProtocol on 4.2.
+            // For some reason it still doesn't work though...
+            // Add a timestamp to the query param to prevent caching.
+            execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
+            if (!vcHeaderValue) {
+                vcHeaderValue = /.*\((.*)\)/.exec(navigator.userAgent)[1];
+            }
+            execXhr.setRequestHeader('vc', vcHeaderValue);
+            execXhr.setRequestHeader('rc', ++requestCount);
+            if (shouldBundleCommandJson()) {
+                execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
+            }
+            execXhr.send(null);
+        } else {
+            execIframe = execIframe || createExecIframe();
+            execIframe.src = "gap://ready";
+        }
+    }
+}
+
+iOSExec.jsToNativeModes = jsToNativeModes;
+
+iOSExec.setJsToNativeBridgeMode = function(mode) {
+    // Remove the iFrame since it may be no longer required, and its existence
+    // can trigger browser bugs.
+    // https://issues.apache.org/jira/browse/CB-593
+    if (execIframe) {
+        execIframe.parentNode.removeChild(execIframe);
+        execIframe = null;
+    }
+    bridgeMode = mode;
+};
+
+iOSExec.nativeFetchMessages = function() {
+    // Each entry in commandQueue is a JSON string already.
+    if (!commandQueue.length) {
+        return '';
+    }
+    var json = '[' + commandQueue.join(',') + ']';
+    commandQueue.length = 0;
+    return json;
+};
+
+iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) {
+    return iOSExec.nativeEvalAndFetch(function() {
+        var success = status === 0 || status === 1;
+        var args = convertMessageToArgsNativeToJs(message);
+        cordova.callbackFromNative(callbackId, success, status, args, keepCallback);
+    });
+};
+
+iOSExec.nativeEvalAndFetch = function(func) {
+    // This shouldn't be nested, but better to be safe.
+    isInContextOfEvalJs++;
+    try {
+        func();
+        return iOSExec.nativeFetchMessages();
+    } finally {
+        isInContextOfEvalJs--;
+    }
+};
+
+module.exports = iOSExec;
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+    moduleMap = define.moduleMap,
+    symbolList,
+    deprecationMap;
+
+exports.reset = function() {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) {
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function(context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var module = require(moduleName);
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy == 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+    for (var k in moduleMap) {
+        if (matchingRegExp.exec(k)) {
+            require(k);
+        }
+    }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/ios/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+    id: "ios",
+    initialize:function() {
+        var modulemapper = require('cordova/modulemapper');
+
+        modulemapper.loadMatchingModules(/cordova.*\/plugininit$/);
+
+        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+        modulemapper.mapModules(window);
+    }
+};
+
+
+});
+
+// file: lib/common/plugin/Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+    this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib/common/plugin/Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    Camera = require('cordova/plugin/CameraConstants'),
+    CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+    cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var quality = getValue(options.quality, 50);
+    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+    var targetWidth = getValue(options.targetWidth, -1);
+    var targetHeight = getValue(options.targetHeight, -1);
+    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+    var allowEdit = !!options.allowEdit;
+    var correctOrientation = !!options.correctOrientation;
+    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+    var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+    exec(successCallback, errorCallback, "Camera", "takePicture", args);
+    return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+    exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib/common/plugin/CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+  DestinationType:{
+    DATA_URL: 0,         // Return base64 encoded string
+    FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
+    NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
+  },
+  EncodingType:{
+    JPEG: 0,             // Return JPEG encoded image
+    PNG: 1               // Return PNG encoded image
+  },
+  MediaType:{
+    PICTURE: 0,          // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+    VIDEO: 1,            // allow selection of video only, ONLY RETURNS URL
+    ALLMEDIA : 2         // allow selection from all media types
+  },
+  PictureSourceType:{
+    PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+    CAMERA : 1,          // Take picture from camera
+    SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
+  },
+  PopoverArrowDirection:{
+      ARROW_UP : 1,        // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+      ARROW_DOWN : 2,
+      ARROW_LEFT : 4,
+      ARROW_RIGHT : 8,
+      ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
+  }
+};
+
+});
+
+// file: lib/ios/plugin/CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+    this.setPosition = function(popoverOptions) {
+        var args = [ popoverOptions ];
+        exec(null, null, "Camera", "repositionPopover", args);
+    };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib/common/plugin/CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+    // information of rectangle that popover should be anchored to
+    this.x = x || 0;
+    this.y = y || 32;
+    this.width = width || 320;
+    this.height = height || 480;
+    // The direction of the popover arrow
+    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib/common/plugin/CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+    // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single sound clip in seconds.
+    this.duration = 0;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib/common/plugin/CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+   this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib/common/plugin/CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+    // Upper limit of images user can take. Value must be equal or greater than 1.
+    this.limit = 1;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib/common/plugin/CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+    // Upper limit of videos user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single video clip in seconds.
+    this.duration = 0;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib/common/plugin/CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ *  CompassError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+    this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib/common/plugin/CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
+  this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib/common/plugin/ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+    // The ASCII-encoded string in lower case representing the media type.
+    this.type = null;
+    // The height attribute represents height of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0.
+    this.height = 0;
+    // The width attribute represents width of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0
+    this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib/common/plugin/Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+        UNKNOWN: "unknown",
+        ETHERNET: "ethernet",
+        WIFI: "wifi",
+        CELL_2G: "2g",
+        CELL_3G: "3g",
+        CELL_4G: "4g",
+        CELL:"cellular",
+        NONE: "none"
+};
+
+});
+
+// file: lib/common/plugin/Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError'),
+    utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+    var value = contact.birthday;
+    try {
+      contact.birthday = new Date(parseFloat(value));
+    } catch (exception){
+      console.log("Cordova Contact convertIn error: exception creating date.");
+    }
+    return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+    var value = contact.birthday;
+    if (value !== null) {
+        // try to make it a Date object if it is not already
+        if (!utils.isDate(value)){
+            try {
+                value = new Date(value);
+            } catch(exception){
+                value = null;
+            }
+        }
+        if (utils.isDate(value)){
+            value = value.valueOf(); // convert to milliseconds
+        }
+        contact.birthday = value;
+    }
+    return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+    ims, organizations, birthday, note, photos, categories, urls) {
+    this.id = id || null;
+    this.rawId = null;
+    this.displayName = displayName || null;
+    this.name = name || null; // ContactName
+    this.nickname = nickname || null;
+    this.phoneNumbers = phoneNumbers || null; // ContactField[]
+    this.emails = emails || null; // ContactField[]
+    this.addresses = addresses || null; // ContactAddress[]
+    this.ims = ims || null; // ContactField[]
+    this.organizations = organizations || null; // ContactOrganization[]
+    this.birthday = birthday || null;
+    this.note = note || null;
+    this.photos = photos || null; // ContactField[]
+    this.categories = categories || null; // ContactField[]
+    this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+    argscheck.checkArgs('FF', 'Contact.remove', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    if (this.id === null) {
+        fail(ContactError.UNKNOWN_ERROR);
+    }
+    else {
+        exec(successCB, fail, "Contacts", "remove", [this.id]);
+    }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+    var clonedContact = utils.clone(this);
+    clonedContact.id = null;
+    clonedContact.rawId = null;
+
+    function nullIds(arr) {
+        if (arr) {
+            for (var i = 0; i < arr.length; ++i) {
+                arr[i].id = null;
+            }
+        }
+    }
+
+    // Loop through and clear out any id's in phones, emails, etc.
+    nullIds(clonedContact.phoneNumbers);
+    nullIds(clonedContact.emails);
+    nullIds(clonedContact.addresses);
+    nullIds(clonedContact.ims);
+    nullIds(clonedContact.organizations);
+    nullIds(clonedContact.categories);
+    nullIds(clonedContact.photos);
+    nullIds(clonedContact.urls);
+    return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+    argscheck.checkArgs('FFO', 'Contact.save', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    var success = function(result) {
+        if (result) {
+            if (successCB) {
+                var fullContact = require('cordova/plugin/contacts').create(result);
+                successCB(convertIn(fullContact));
+            }
+        }
+        else {
+            // no Entry object returned
+            fail(ContactError.UNKNOWN_ERROR);
+        }
+    };
+    var dupContact = convertOut(utils.clone(this));
+    exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib/common/plugin/ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.formatted = formatted || null;
+    this.streetAddress = streetAddress || null;
+    this.locality = locality || null;
+    this.region = region || null;
+    this.postalCode = postalCode || null;
+    this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib/common/plugin/ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ *  ContactError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+    this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib/common/plugin/ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+    this.id = null;
+    this.type = (type && type.toString()) || null;
+    this.value = (value && value.toString()) || null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib/common/plugin/ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+    this.filter = filter || '';
+    this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib/common/plugin/ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+    this.formatted = formatted || null;
+    this.familyName = familyName || null;
+    this.givenName = givenName || null;
+    this.middleName = middle || null;
+    this.honorificPrefix = prefix || null;
+    this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib/common/plugin/ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.name = name || null;
+    this.department = dept || null;
+    this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib/common/plugin/Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+    /**
+     * The latitude of the position.
+     */
+    this.latitude = lat;
+    /**
+     * The longitude of the position,
+     */
+    this.longitude = lng;
+    /**
+     * The accuracy of the position.
+     */
+    this.accuracy = acc;
+    /**
+     * The altitude of the position.
+     */
+    this.altitude = (alt !== undefined ? alt : null);
+    /**
+     * The direction the device is moving at the position.
+     */
+    this.heading = (head !== undefined ? head : null);
+    /**
+     * The velocity with which the device is moving at the position.
+     */
+    this.speed = (vel !== undefined ? vel : null);
+
+    if (this.speed === 0 || this.speed === null) {
+        this.heading = NaN;
+    }
+
+    /**
+     * The altitude accuracy of the position.
+     */
+    this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib/common/plugin/DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileError = require('cordova/plugin/FileError'),
+    DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+     DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+    return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+    var win = successCallback && function(result) {
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+    var win = successCallback && function(result) {
+        var FileEntry = require('cordova/plugin/FileEntry');
+        var entry = new FileEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib/common/plugin/DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+    this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+    var win = typeof successCallback !== 'function' ? null : function(result) {
+        var retVal = [];
+        for (var i=0; i<result.length; i++) {
+            var entry = null;
+            if (result[i].isDirectory) {
+                entry = new (require('cordova/plugin/DirectoryEntry'))();
+            }
+            else if (result[i].isFile) {
+                entry = new (require('cordova/plugin/FileEntry'))();
+            }
+            entry.isDirectory = result[i].isDirectory;
+            entry.isFile = result[i].isFile;
+            entry.name = result[i].name;
+            entry.fullPath = result[i].fullPath;
+            retVal.push(entry);
+        }
+        successCallback(retVal);
+    };
+    var fail = typeof errorCallback !== 'function' ? null : function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib/common/plugin/Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ *            {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ *            {boolean} true if Entry is a directory (readonly)
+ * @param name
+ *            {DOMString} name of the file or directory, excluding the path
+ *            leading to it (readonly)
+ * @param fullPath
+ *            {DOMString} the absolute full path to the file or directory
+ *            (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+    this.isFile = !!isFile;
+    this.isDirectory = !!isDirectory;
+    this.name = name || '';
+    this.fullPath = fullPath || '';
+    this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+    var success = successCallback && function(lastModified) {
+        var metadata = new Metadata(lastModified);
+        successCallback(metadata);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+    exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ * @param metadataObject
+ *            {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+    exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new Entry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+        // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        // success callback
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+    // fullPath attribute contains the full URL
+    return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    // fullPath attribute contains the full URI
+    return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.remove', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+    var win = successCallback && function(result) {
+        var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib/common/plugin/File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+    this.name = name || '';
+    this.fullPath = fullPath || null;
+    this.type = type || null;
+    this.lastModifiedDate = lastModifiedDate || null;
+    this.size = size || 0;
+
+    // These store the absolute start and end for slicing the file.
+    this.start = 0;
+    this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+    var size = this.end - this.start;
+    var newStart = 0;
+    var newEnd = size;
+    if (arguments.length) {
+        if (start < 0) {
+            newStart = Math.max(size + start, 0);
+        } else {
+            newStart = Math.min(size, start);
+        }
+    }
+
+    if (arguments.length >= 2) {
+        if (end < 0) {
+            newEnd = Math.max(size + end, 0);
+        } else {
+            newEnd = Math.min(end, size);
+        }
+    }
+
+    var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+    newFile.start = this.start + newStart;
+    newFile.end = this.start + newEnd;
+    return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib/common/plugin/FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileWriter = require('cordova/plugin/FileWriter'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+     FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+    this.file(function(filePointer) {
+        var writer = new FileWriter(filePointer);
+
+        if (writer.fileName === null || writer.fileName === "") {
+            errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+        } else {
+            successCallback && successCallback(writer);
+        }
+    }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+    var win = successCallback && function(f) {
+        var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+        successCallback(file);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib/common/plugin/FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+  this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib/common/plugin/FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    modulemapper = require('cordova/modulemapper'),
+    utils = require('cordova/utils'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent'),
+    origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+    this._readyState = 0;
+    this._error = null;
+    this._result = null;
+    this._fileName = '';
+    this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+    return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+    return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+    return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+    utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+        return this._realReader[eventName] || null;
+    }, function(value) {
+        this._realReader[eventName] = value;
+    });
+}
+defineEvent('onloadstart');    // When the read starts.
+defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload');         // When the read has successfully completed.
+defineEvent('onerror');        // When the read has failed (see errors).
+defineEvent('onloadend');      // When the request has completed (either in success or failure).
+defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+    // Already loading something
+    if (reader.readyState == FileReader.LOADING) {
+      throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    reader._result = null;
+    reader._error = null;
+    reader._readyState = FileReader.LOADING;
+
+    if (typeof file.fullPath == 'string') {
+        reader._fileName = file.fullPath;
+    } else {
+        reader._fileName = '';
+        return true;
+    }
+
+    reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+    if (origFileReader && !this._fileName) {
+        return this._realReader.abort();
+    }
+    this._result = null;
+
+    if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+      return;
+    }
+
+    this._readyState = FileReader.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {target:this}));
+    }
+    // If load end callback
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target:this}));
+    }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file          {File} File object containing file properties
+ * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsText(file, encoding);
+    }
+
+    // Default encoding is UTF-8
+    var enc = encoding ? encoding : "UTF-8";
+    var me = this;
+    var execArgs = [this._fileName, enc, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // null result
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ *      data:[<mediatype>][;base64],<data>
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsDataURL(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsBinaryString(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsArrayBuffer(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib/common/plugin/FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+    this.name = name || null;
+    if (root) {
+        this.root = new DirectoryEntry(root.name, root.fullPath);
+    }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib/common/plugin/FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    FileTransferError = require('cordova/plugin/FileTransferError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+    var pe = new ProgressEvent();
+    pe.lengthComputable = result.lengthComputable;
+    pe.loaded = result.loaded;
+    pe.total = result.total;
+    return pe;
+}
+
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) !== 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+    this._id = ++idCounter;
+    this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String}           Full path of the file on the device
+* @param server {String}             URL of the server to receive the file
+* @param successCallback (Function}  Callback to be invoked when upload has completed
+* @param errorCallback {Function}    Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+    argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+    // check for options
+    var fileKey = null;
+    var fileName = null;
+    var mimeType = null;
+    var params = null;
+    var chunkedMode = true;
+    var headers = null;
+    var httpMethod = null;
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        options = options || {};
+        options.headers = options.headers || {};
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    if (options) {
+        fileKey = options.fileKey;
+        fileName = options.fileName;
+        mimeType = options.mimeType;
+        headers = options.headers;
+        httpMethod = options.httpMethod || "POST";
+        if (httpMethod.toUpperCase() == "PUT"){
+            httpMethod = "PUT";
+        } else {
+            httpMethod = "POST";
+        }
+        if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+            chunkedMode = options.chunkedMode;
+        }
+        if (options.params) {
+            params = options.params;
+        }
+        else {
+            params = {};
+        }
+    }
+
+    var fail = errorCallback && function(e) {
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+        errorCallback(error);
+    };
+
+    var self = this;
+    var win = function(result) {
+        if (typeof result.lengthComputable != "undefined") {
+            if (self.onprogress) {
+                self.onprogress(newProgressEvent(result));
+            }
+        } else {
+            successCallback && successCallback(result);
+        }
+    };
+    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String}          URL of the server to receive the file
+ * @param target {String}         Full path of the file on the device
+ * @param successCallback (Function}  Callback to be invoked when upload has completed
+ * @param errorCallback {Function}    Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
+    argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+    var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        options = options || {};
+        options.headers = options.headers || {};
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
+    var win = function(result) {
+        if (typeof result.lengthComputable != "undefined") {
+            if (self.onprogress) {
+                return self.onprogress(newProgressEvent(result));
+            }
+        } else if (successCallback) {
+            var entry = null;
+            if (result.isDirectory) {
+                entry = new (require('cordova/plugin/DirectoryEntry'))();
+            }
+            else if (result.isFile) {
+                entry = new (require('cordova/plugin/FileEntry'))();
+            }
+            entry.isDirectory = result.isDirectory;
+            entry.isFile = result.isFile;
+            entry.name = result.name;
+            entry.fullPath = result.fullPath;
+            successCallback(entry);
+        }
+    };
+
+    var fail = errorCallback && function(e) {
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+        errorCallback(error);
+    };
+
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
+ */
+FileTransfer.prototype.abort = function() {
+    exec(null, null, 'FileTransfer', 'abort', [this._id]);
+};
+
+module.exports = FileTransfer;
+
+});
+
+// file: lib/common/plugin/FileTransferError.js
+define("cordova/plugin/FileTransferError", function(require, exports, module) {
+
+/**
+ * FileTransferError
+ * @constructor
+ */
+var FileTransferError = function(code, source, target, status, body) {
+    this.code = code || null;
+    this.source = source || null;
+    this.target = target || null;
+    this.http_status = status || null;
+    this.body = body || null;
+};
+
+FileTransferError.FILE_NOT_FOUND_ERR = 1;
+FileTransferError.INVALID_URL_ERR = 2;
+FileTransferError.CONNECTION_ERR = 3;
+FileTransferError.ABORT_ERR = 4;
+
+module.exports = FileTransferError;
+
+});
+
+// file: lib/common/plugin/FileUploadOptions.js
+define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String}   Name of file request parameter.
+ * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object}    Object with key: value params to send to the server.
+ * @param headers {Object}   Keys are header names, values are header values. Multiple
+ *                           headers of the same name are not supported.
+ */
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
+    this.fileKey = fileKey || null;
+    this.fileName = fileName || null;
+    this.mimeType = mimeType || null;
+    this.params = params || null;
+    this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
+
+// file: lib/common/plugin/FileUploadResult.js
+define("cordova/plugin/FileUploadResult", function(require, exports, module) {
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+var FileUploadResult = function() {
+    this.bytesSent = 0;
+    this.responseCode = null;
+    this.response = null;
+};
+
+module.exports = FileUploadResult;
+
+});
+
+// file: lib/common/plugin/FileWriter.js
+define("cordova/plugin/FileWriter", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function(file) {
+    this.fileName = "";
+    this.length = 0;
+    if (file) {
+        this.fileName = file.fullPath || file;
+        this.length = file.size || 0;
+    }
+    // default is to write at the beginning of the file
+    this.position = 0;
+
+    this.readyState = 0; // EMPTY
+
+    this.result = null;
+
+    // Error
+    this.error = null;
+
+    // Event handlers
+    this.onwritestart = null;   // When writing starts
+    this.onprogress = null;     // While writing the file, and reporting partial file data
+    this.onwrite = null;        // When the write has successfully completed.
+    this.onwriteend = null;     // When the request has completed (either in success or failure).
+    this.onabort = null;        // When the write has been aborted. For instance, by invoking the abort() method.
+    this.onerror = null;        // When the write has failed (see errors).
+};
+
+// States
+FileWriter.INIT = 0;
+FileWriter.WRITING = 1;
+FileWriter.DONE = 2;
+
+/**
+ * Abort writing file.
+ */
+FileWriter.prototype.abort = function() {
+    // check for invalid state
+    if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // set error
+    this.error = new FileError(FileError.ABORT_ERR);
+
+    this.readyState = FileWriter.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === "function") {
+        this.onabort(new ProgressEvent("abort", {"target":this}));
+    }
+
+    // If write end callback
+    if (typeof this.onwriteend === "function") {
+        this.onwriteend(new ProgressEvent("writeend", {"target":this}));
+    }
+};
+
+/**
+ * Writes data to the file
+ *
+ * @param text to be written
+ */
+FileWriter.prototype.write = function(text) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === "function") {
+        me.onwritestart(new ProgressEvent("writestart", {"target":me}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // position always increases by bytes written because file would be extended
+            me.position += r;
+            // The length of the file is now where we are done writing.
+
+            me.length = me.position;
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // If onwrite callback
+            if (typeof me.onwrite === "function") {
+                me.onwrite(new ProgressEvent("write", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        }, "File", "write", [this.fileName, text, this.position]);
+};
+
+/**
+ * Moves the file pointer to the location specified.
+ *
+ * If the offset is a negative number the position of the file
+ * pointer is rewound.  If the offset is greater than the file
+ * size the position is set to the end of the file.
+ *
+ * @param offset is the location to move the file pointer to.
+ */
+FileWriter.prototype.seek = function(offset) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    if (!offset && offset !== 0) {
+        return;
+    }
+
+    // See back from end of file.
+    if (offset < 0) {
+        this.position = Math.max(offset + this.length, 0);
+    }
+    // Offset is bigger than file size so set position
+    // to the end of the file.
+    else if (offset > this.length) {
+        this.position = this.length;
+    }
+    // Offset is between 0 and file size so set the position
+    // to start writing.
+    else {
+        this.position = offset;
+    }
+};
+
+/**
+ * Truncates the file to the size specified.
+ *
+ * @param size to chop the file at.
+ */
+FileWriter.prototype.truncate = function(size) {
+    // Throw an exception if we are already writing a file
+    if (this.readyState === FileWriter.WRITING) {
+        throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    // WRITING state
+    this.readyState = FileWriter.WRITING;
+
+    var me = this;
+
+    // If onwritestart callback
+    if (typeof me.onwritestart === "function") {
+        me.onwritestart(new ProgressEvent("writestart", {"target":this}));
+    }
+
+    // Write file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Update the length of the file
+            me.length = r;
+            me.position = Math.min(me.position, r);
+
+            // If onwrite callback
+            if (typeof me.onwrite === "function") {
+                me.onwrite(new ProgressEvent("write", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me.readyState === FileWriter.DONE) {
+                return;
+            }
+
+            // DONE state
+            me.readyState = FileWriter.DONE;
+
+            // Save error
+            me.error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {"target":me}));
+            }
+
+            // If onwriteend callback
+            if (typeof me.onwriteend === "function") {
+                me.onwriteend(new ProgressEvent("writeend", {"target":me}));
+            }
+        }, "File", "truncate", [this.fileName, size]);
+};
+
+module.exports = FileWriter;
+
+});
+
+// file: lib/common/plugin/Flags.js
+define("cordova/plugin/Flags", function(require, exports, module) {
+
+/**
+ * Supplies arguments to methods that lookup or create files and directories.
+ *
+ * @param create
+ *            {boolean} file or directory if it doesn't exist
+ * @param exclusive
+ *            {boolean} used with create; if true the command will fail if
+ *            target path exists
+ */
+function Flags(create, exclusive) {
+    this.create = create || false;
+    this.exclusive = exclusive || false;
+}
+
+module.exports = Flags;
+
+});
+
+// file: lib/common/plugin/GlobalizationError.js
+define("cordova/plugin/GlobalizationError", function(require, exports, module) {
+
+
+/**
+ * Globalization error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var GlobalizationError = function(code, message) {
+    this.code = code || null;
+    this.message = message || '';
+};
+
+// Globalization error codes
+GlobalizationError.UNKNOWN_ERROR = 0;
+GlobalizationError.FORMATTING_ERROR = 1;
+GlobalizationError.PARSING_ERROR = 2;
+GlobalizationError.PATTERN_ERROR = 3;
+
+module.exports = GlobalizationError;
+
+});
+
+// file: lib/common/plugin/InAppBrowser.js
+define("cordova/plugin/InAppBrowser", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
+
+function InAppBrowser() {
+   this.channels = {
+        'loadstart': channel.create('loadstart'),
+        'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
+        'exit' : channel.create('exit')
+   };
+}
+
+InAppBrowser.prototype = {
+    _eventHandler: function (event) {
+        if (event.type in this.channels) {
+            this.channels[event.type].fire(event);
+        }
+    },
+    close: function (eventname) {
+        exec(null, null, "InAppBrowser", "close", []);
+    },
+    addEventListener: function (eventname,f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].subscribe(f);
+        }
+    },
+    removeEventListener: function(eventname, f) {
+        if (eventname in this.channels) {
+            this.channels[eventname].unsubscribe(f);
+        }
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
+    }
+};
+
+module.exports = function(strUrl, strWindowName, strWindowFeatures) {
+    var iab = new InAppBrowser();
+    var cb = function(eventname) {
+       iab._eventHandler(eventname);
+    };
+
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    return iab;
+};
+
+
+});
+
+// file: lib/common/plugin/LocalFileSystem.js
+define("cordova/plugin/LocalFileSystem", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Represents a local file system.
+ */
+var LocalFileSystem = function() {
+
+};
+
+LocalFileSystem.TEMPORARY = 0; //temporary, with no guarantee of persistence
+LocalFileSystem.PERSISTENT = 1; //persistent
+
+module.exports = LocalFileSystem;
+
+});
+
+// file: lib/common/plugin/Media.js
+define("cordova/plugin/Media", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec');
+
+var mediaObjects = {};
+
+/**
+ * This class provides access to the device media, interfaces to both sound and video
+ *
+ * @constructor
+ * @param src                   The file name or url to play
+ * @param successCallback       The callback to be called when the file is done playing or recording.
+ *                                  successCallback()
+ * @param errorCallback         The callback to be called if there is an error.
+ *                                  errorCallback(int errorCode) - OPTIONAL
+ * @param statusCallback        The callback to be called when media status has changed.
+ *                                  statusCallback(int statusCode) - OPTIONAL
+ */
+var Media = function(src, successCallback, errorCallback, statusCallback) {
+    argscheck.checkArgs('SFFF', 'Media', arguments);
+    this.id = utils.createUUID();
+    mediaObjects[this.id] = this;
+    this.src = src;
+    this.successCallback = successCallback;
+    this.errorCallback = errorCallback;
+    this.statusCallback = statusCallback;
+    this._duration = -1;
+    this._position = -1;
+    exec(null, this.errorCallback, "Media", "create", [this.id, this.src]);
+};
+
+// Media messages
+Media.MEDIA_STATE = 1;
+Media.MEDIA_DURATION = 2;
+Media.MEDIA_POSITION = 3;
+Media.MEDIA_ERROR = 9;
+
+// Media states
+Media.MEDIA_NONE = 0;
+Media.MEDIA_STARTING = 1;
+Media.MEDIA_RUNNING = 2;
+Media.MEDIA_PAUSED = 3;
+Media.MEDIA_STOPPED = 4;
+Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
+
+// "static" function to return existing objs.
+Media.get = function(id) {
+    return mediaObjects[id];
+};
+
+/**
+ * Start or resume playing audio file.
+ */
+Media.prototype.play = function(options) {
+    exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]);
+};
+
+/**
+ * Stop playing audio file.
+ */
+Media.prototype.stop = function() {
+    var me = this;
+    exec(function() {
+        me._position = 0;
+    }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
+};
+
+/**
+ * Seek or jump to a new time in the track..
+ */
+Media.prototype.seekTo = function(milliseconds) {
+    var me = this;
+    exec(function(p) {
+        me._position = p;
+    }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]);
+};
+
+/**
+ * Pause playing audio file.
+ */
+Media.prototype.pause = function() {
+    exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]);
+};
+
+/**
+ * Get duration of an audio file.
+ * The duration is only set for audio that is playing, paused or stopped.
+ *
+ * @return      duration or -1 if not known.
+ */
+Media.prototype.getDuration = function() {
+    return this._duration;
+};
+
+/**
+ * Get position of audio.
+ */
+Media.prototype.getCurrentPosition = function(success, fail) {
+    var me = this;
+    exec(function(p) {
+        me._position = p;
+        success(p);
+    }, fail, "Media", "getCurrentPositionAudio", [this.id]);
+};
+
+/**
+ * Start recording audio file.
+ */
+Media.prototype.startRecord = function() {
+    exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
+};
+
+/**
+ * Stop recording audio file.
+ */
+Media.prototype.stopRecord = function() {
+    exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
+};
+
+/**
+ * Release the resources.
+ */
+Media.prototype.release = function() {
+    exec(null, this.errorCallback, "Media", "release", [this.id]);
+};
+
+/**
+ * Adjust the volume.
+ */
+Media.prototype.setVolume = function(volume) {
+    exec(null, null, "Media", "setVolume", [this.id, volume]);
+};
+
+/**
+ * Audio has status update.
+ * PRIVATE
+ *
+ * @param id            The media object id (string)
+ * @param msgType       The 'type' of update this is
+ * @param value         Use of value is determined by the msgType
+ */
+Media.onStatus = function(id, msgType, value) {
+
+    var media = mediaObjects[id];
+
+    if(media) {
+        switch(msgType) {
+            case Media.MEDIA_STATE :
+                media.statusCallback && media.statusCallback(value);
+                if(value == Media.MEDIA_STOPPED) {
+                    media.successCallback && media.successCallback();
+                }
+                break;
+            case Media.MEDIA_DURATION :
+                media._duration = value;
+                break;
+            case Media.MEDIA_ERROR :
+                media.errorCallback && media.errorCallback(value);
+                break;
+            case Media.MEDIA_POSITION :
+                media._position = Number(value);
+                break;
+            default :
+                console.error && console.error("Unhandled Media.onStatus :: " + msgType);
+                break;
+        }
+    }
+    else {
+         console.error && console.error("Received Media.onStatus callback for unknown media :: " + id);
+    }
+
+};
+
+module.exports = Media;
+
+});
+
+// file: lib/common/plugin/MediaError.js
+define("cordova/plugin/MediaError", function(require, exports, module) {
+
+/**
+ * This class contains information about any Media errors.
+*/
+/*
+ According to :: http://dev.w3.org/html5/spec-author-view/video.html#mediaerror
+ We should never be creating these objects, we should just implement the interface
+ which has 1 property for an instance, 'code'
+
+ instead of doing :
+    errorCallbackFunction( new MediaError(3,'msg') );
+we should simply use a literal :
+    errorCallbackFunction( {'code':3} );
+ */
+
+ var _MediaError = window.MediaError;
+
+
+if(!_MediaError) {
+    window.MediaError = _MediaError = function(code, msg) {
+        this.code = (typeof code != 'undefined') ? code : null;
+        this.message = msg || ""; // message is NON-standard! do not use!
+    };
+}
+
+_MediaError.MEDIA_ERR_NONE_ACTIVE    = _MediaError.MEDIA_ERR_NONE_ACTIVE    || 0;
+_MediaError.MEDIA_ERR_ABORTED        = _MediaError.MEDIA_ERR_ABORTED        || 1;
+_MediaError.MEDIA_ERR_NETWORK        = _MediaError.MEDIA_ERR_NETWORK        || 2;
+_MediaError.MEDIA_ERR_DECODE         = _MediaError.MEDIA_ERR_DECODE         || 3;
+_MediaError.MEDIA_ERR_NONE_SUPPORTED = _MediaError.MEDIA_ERR_NONE_SUPPORTED || 4;
+// TODO: MediaError.MEDIA_ERR_NONE_SUPPORTED is legacy, the W3 spec now defines it as below.
+// as defined by http://dev.w3.org/html5/spec-author-view/video.html#error-codes
+_MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = _MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || 4;
+
+module.exports = _MediaError;
+
+});
+
+// file: lib/common/plugin/MediaFile.js
+define("cordova/plugin/MediaFile", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    File = require('cordova/plugin/File'),
+    CaptureError = require('cordova/plugin/CaptureError');
+/**
+ * Represents a single file.
+ *
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+var MediaFile = function(name, fullPath, type, lastModifiedDate, size){
+    MediaFile.__super__.constructor.apply(this, arguments);
+};
+
+utils.extend(MediaFile, File);
+
+/**
+ * Request capture format data for a specific file and type
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ */
+MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
+    if (typeof this.fullPath === "undefined" || this.fullPath === null) {
+        errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
+    } else {
+        exec(successCallback, errorCallback, "Capture", "getFormatData", [this.fullPath, this.type]);
+    }
+};
+
+module.exports = MediaFile;
+
+});
+
+// file: lib/common/plugin/MediaFileData.js
+define("cordova/plugin/MediaFileData", function(require, exports, module) {
+
+/**
+ * MediaFileData encapsulates format information of a media file.
+ *
+ * @param {DOMString} codecs
+ * @param {long} bitrate
+ * @param {long} height
+ * @param {long} width
+ * @param {float} duration
+ */
+var MediaFileData = function(codecs, bitrate, height, width, duration){
+    this.codecs = codecs || null;
+    this.bitrate = bitrate || 0;
+    this.height = height || 0;
+    this.width = width || 0;
+    this.duration = duration || 0;
+};
+
+module.exports = MediaFileData;
+
+});
+
+// file: lib/common/plugin/Metadata.js
+define("cordova/plugin/Metadata", function(require, exports, module) {
+
+/**
+ * Information about the state of the file or directory
+ *
+ * {Date} modificationTime (readonly)
+ */
+var Metadata = function(time) {
+    this.modificationTime = (typeof time != 'undefined'?new Date(time):null);
+};
+
+module.exports = Metadata;
+
+});
+
+// file: lib/common/plugin/Position.js
+define("cordova/plugin/Position", function(require, exports, module) {
+
+var Coordinates = require('cordova/plugin/Coordinates');
+
+var Position = function(coords, timestamp) {
+    if (coords) {
+        this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy);
+    } else {
+        this.coords = new Coordinates();
+    }
+    this.timestamp = (timestamp !== undefined) ? timestamp : new Date();
+};
+
+module.exports = Position;
+
+});
+
+// file: lib/common/plugin/PositionError.js
+define("cordova/plugin/PositionError", function(require, exports, module) {
+
+/**
+ * Position error object
+ *
+ * @constructor
+ * @param code
+ * @param message
+ */
+var PositionError = function(code, message) {
+    this.code = code || null;
+    this.message = message || '';
+};
+
+PositionError.PERMISSION_DENIED = 1;
+PositionError.POSITION_UNAVAILABLE = 2;
+PositionError.TIMEOUT = 3;
+
+module.exports = PositionError;
+
+});
+
+// file: lib/common/plugin/ProgressEvent.js
+define("cordova/plugin/ProgressEvent", function(require, exports, module) {
+
+// If ProgressEvent exists in global context, use it already, otherwise use our own polyfill
+// Feature test: See if we can instantiate a native ProgressEvent;
+// if so, use that approach,
+// otherwise fill-in with our own implementation.
+//
+// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
+var ProgressEvent = (function() {
+    /*
+    var createEvent = function(data) {
+        var event = document.createEvent('Events');
+        event.initEvent('ProgressEvent', false, false);
+        if (data) {
+            for (var i in data) {
+                if (data.hasOwnProperty(i)) {
+                    event[i] = data[i];
+                }
+            }
+            if (data.target) {
+                // TODO: cannot call <some_custom_object>.dispatchEvent
+                // need to first figure out how to implement EventTarget
+            }
+        }
+        return event;
+    };
+    try {
+        var ev = createEvent({type:"abort",target:document});
+        return function ProgressEvent(type, data) {
+            data.type = type;
+            return createEvent(data);
+        };
+    } catch(e){
+    */
+        return function ProgressEvent(type, dict) {
+            this.type = type;
+            this.bubbles = false;
+            this.cancelBubble = false;
+            this.cancelable = false;
+            this.lengthComputable = false;
+            this.loaded = dict && dict.loaded ? dict.loaded : 0;
+            this.total = dict && dict.total ? dict.total : 0;
+            this.target = dict && dict.target ? dict.target : null;
+        };
+    //}
+})();
+
+module.exports = ProgressEvent;
+
+});
+
+// file: lib/common/plugin/accelerometer.js
+define("cordova/plugin/accelerometer", function(require, exports, module) {
+
+/**
+ * This class provides access to device accelerometer data.
+ * @constructor
+ */
+var argscheck = require('cordova/argscheck'),
+    utils = require("cordova/utils"),
+    exec = require("cordova/exec"),
+    Acceleration = require('cordova/plugin/Acceleration');
+
+// Is the accel sensor running?
+var running = false;
+
+// Keeps reference to watchAcceleration calls.
+var timers = {};
+
+// Array of listeners; used to keep track of when we should call start and stop.
+var listeners = [];
+
+// Last returned acceleration object from native
+var accel = null;
+
+// Tells native to start.
+function start() {
+    exec(function(a) {
+        var tempListeners = listeners.slice(0);
+        accel = new Acceleration(a.x, a.y, a.z, a.timestamp);
+        for (var i = 0, l = tempListeners.length; i < l; i++) {
+            tempListeners[i].win(accel);
+        }
+    }, function(e) {
+        var tempListeners = listeners.slice(0);
+        for (var i = 0, l = tempListeners.length; i < l; i++) {
+            tempListeners[i].fail(e);
+        }
+    }, "Accelerometer", "start", []);
+    running = true;
+}
+
+// Tells native to stop.
+function stop() {
+    exec(null, null, "Accelerometer", "stop", []);
+    running = false;
+}
+
+// Adds a callback pair to the listeners array
+function createCallbackPair(win, fail) {
+    return {win:win, fail:fail};
+}
+
+// Removes a win/fail listener pair from the listeners array
+function removeListeners(l) {
+    var idx = listeners.indexOf(l);
+    if (idx > -1) {
+        listeners.splice(idx, 1);
+        if (listeners.length === 0) {
+            stop();
+        }
+    }
+}
+
+var accelerometer = {
+    /**
+     * Asynchronously acquires the current acceleration.
+     *
+     * @param {Function} successCallback    The function to call when the acceleration data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the acceleration data. (OPTIONAL)
+     * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+     */
+    getCurrentAcceleration: function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'accelerometer.getCurrentAcceleration', arguments);
+
+        var p;
+        var win = function(a) {
+            removeListeners(p);
+            successCallback(a);
+        };
+        var fail = function(e) {
+            removeListeners(p);
+            errorCallback && errorCallback(e);
+        };
+
+        p = createCallbackPair(win, fail);
+        listeners.push(p);
+
+        if (!running) {
+            start();
+        }
+    },
+
+    /**
+     * Asynchronously acquires the acceleration repeatedly at a given interval.
+     *
+     * @param {Function} successCallback    The function to call each time the acceleration data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the acceleration data. (OPTIONAL)
+     * @param {AccelerationOptions} options The options for getting the accelerometer data such as timeout. (OPTIONAL)
+     * @return String                       The watch id that must be passed to #clearWatch to stop watching.
+     */
+    watchAcceleration: function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'accelerometer.watchAcceleration', arguments);
+        // Default interval (10 sec)
+        var frequency = (options && options.frequency && typeof options.frequency == 'number') ? options.frequency : 10000;
+
+        // Keep reference to watch id, and report accel readings as often as defined in frequency
+        var id = utils.createUUID();
+
+        var p = createCallbackPair(function(){}, function(e) {
+            removeListeners(p);
+            errorCallback && errorCallback(e);
+        });
+        listeners.push(p);
+
+        timers[id] = {
+            timer:window.setInterval(function() {
+                if (accel) {
+                    successCallback(accel);
+                }
+            }, frequency),
+            listeners:p
+        };
+
+        if (running) {
+            // If we're already running then immediately invoke the success callback
+            // but only if we have retrieved a value, sample code does not check for null ...
+            if (accel) {
+                successCallback(accel);
+            }
+        } else {
+            start();
+        }
+
+        return id;
+    },
+
+    /**
+     * Clears the specified accelerometer watch.
+     *
+     * @param {String} id       The id of the watch returned from #watchAcceleration.
+     */
+    clearWatch: function(id) {
+        // Stop javascript timer & remove from timer list
+        if (id && timers[id]) {
+            window.clearInterval(timers[id].timer);
+            removeListeners(timers[id].listeners);
+            delete timers[id];
+        }
+    }
+};
+
+module.exports = accelerometer;
+
+});
+
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
+// file: lib/common/plugin/battery.js
+define("cordova/plugin/battery", function(require, exports, module) {
+
+/**
+ * This class contains information about the current battery status.
+ * @constructor
+ */
+var cordova = require('cordova'),
+    exec = require('cordova/exec');
+
+function handlers() {
+  return battery.channels.batterystatus.numHandlers +
+         battery.channels.batterylow.numHandlers +
+         battery.channels.batterycritical.numHandlers;
+}
+
+var Battery = function() {
+    this._level = null;
+    this._isPlugged = null;
+    // Create new event handlers on the window (returns a channel instance)
+    this.channels = {
+      batterystatus:cordova.addWindowEventHandler("batterystatus"),
+      batterylow:cordova.addWindowEventHandler("batterylow"),
+      batterycritical:cordova.addWindowEventHandler("batterycritical")
+    };
+    for (var key in this.channels) {
+        this.channels[key].onHasSubscribersChange = Battery.onHasSubscribersChange;
+    }
+};
+/**
+ * Event handlers for when callbacks get registered for the battery.
+ * Keep track of how many handlers we have so we can start and stop the native battery listener
+ * appropriately (and hopefully save on battery life!).
+ */
+Battery.onHasSubscribersChange = function() {
+  // If we just registered the first handler, make sure native listener is started.
+  if (this.numHandlers === 1 && handlers() === 1) {
+      exec(battery._status, battery._error, "Battery", "start", []);
+  } else if (handlers() === 0) {
+      exec(null, null, "Battery", "stop", []);
+  }
+};
+
+/**
+ * Callback for battery status
+ *
+ * @param {Object} info            keys: level, isPlugged
+ */
+Battery.prototype._status = function(info) {
+    if (info) {
+        var me = battery;
+    var level = info.level;
+        if (me._level !== level || me._isPlugged !== info.isPlugged) {
+            // Fire batterystatus event
+            cordova.fireWindowEvent("batterystatus", info);
+
+            // Fire low battery event
+            if (level === 20 || level === 5) {
+                if (level === 20) {
+                    cordova.fireWindowEvent("batterylow", info);
+                }
+                else {
+                    cordova.fireWindowEvent("batterycritical", info);
+                }
+            }
+        }
+        me._level = level;
+        me._isPlugged = info.isPlugged;
+    }
+};
+
+/**
+ * Error callback for battery start
+ */
+Battery.prototype._error = function(e) {
+    console.log("Error initializing Battery: " + e);
+};
+
+var battery = new Battery();
+
+module.exports = battery;
+
+});
+
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
+// file: lib/common/plugin/capture.js
+define("cordova/plugin/capture", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    MediaFile = require('cordova/plugin/MediaFile');
+
+/**
+ * Launches a capture of different types.
+ *
+ * @param (DOMString} type
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+function _capture(type, successCallback, errorCallback, options) {
+    var win = function(pluginResult) {
+        var mediaFiles = [];
+        var i;
+        for (i = 0; i < pluginResult.length; i++) {
+            var mediaFile = new MediaFile();
+            mediaFile.name = pluginResult[i].name;
+            mediaFile.fullPath = pluginResult[i].fullPath;
+            mediaFile.type = pluginResult[i].type;
+            mediaFile.lastModifiedDate = pluginResult[i].lastModifiedDate;
+            mediaFile.size = pluginResult[i].size;
+            mediaFiles.push(mediaFile);
+        }
+        successCallback(mediaFiles);
+    };
+    exec(win, errorCallback, "Capture", type, [options]);
+}
+/**
+ * The Capture interface exposes an interface to the camera and microphone of the hosting device.
+ */
+function Capture() {
+    this.supportedAudioModes = [];
+    this.supportedImageModes = [];
+    this.supportedVideoModes = [];
+}
+
+/**
+ * Launch audio recorder application for recording audio clip(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureAudioOptions} options
+ */
+Capture.prototype.captureAudio = function(successCallback, errorCallback, options){
+    _capture("captureAudio", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch camera application for taking image(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureImageOptions} options
+ */
+Capture.prototype.captureImage = function(successCallback, errorCallback, options){
+    _capture("captureImage", successCallback, errorCallback, options);
+};
+
+/**
+ * Launch device camera application for recording video(s).
+ *
+ * @param {Function} successCB
+ * @param {Function} errorCB
+ * @param {CaptureVideoOptions} options
+ */
+Capture.prototype.captureVideo = function(successCallback, errorCallback, options){
+    _capture("captureVideo", successCallback, errorCallback, options);
+};
+
+
+module.exports = new Capture();
+
+});
+
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
+// file: lib/common/plugin/compass.js
+define("cordova/plugin/compass", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    utils = require('cordova/utils'),
+    CompassHeading = require('cordova/plugin/CompassHeading'),
+    CompassError = require('cordova/plugin/CompassError'),
+    timers = {},
+    compass = {
+        /**
+         * Asynchronously acquires the current heading.
+         * @param {Function} successCallback The function to call when the heading
+         * data is available
+         * @param {Function} errorCallback The function to call when there is an error
+         * getting the heading data.
+         * @param {CompassOptions} options The options for getting the heading data (not used).
+         */
+        getCurrentHeading:function(successCallback, errorCallback, options) {
+            argscheck.checkArgs('fFO', 'compass.getCurrentHeading', arguments);
+
+            var win = function(result) {
+                var ch = new CompassHeading(result.magneticHeading, result.trueHeading, result.headingAccuracy, result.timestamp);
+                successCallback(ch);
+            };
+            var fail = errorCallback && function(code) {
+                var ce = new CompassError(code);
+                errorCallback(ce);
+            };
+
+            // Get heading
+            exec(win, fail, "Compass", "getHeading", [options]);
+        },
+
+        /**
+         * Asynchronously acquires the heading repeatedly at a given interval.
+         * @param {Function} successCallback The function to call each time the heading
+         * data is available
+         * @param {Function} errorCallback The function to call when there is an error
+         * getting the heading data.
+         * @param {HeadingOptions} options The options for getting the heading data
+         * such as timeout and the frequency of the watch. For iOS, filter parameter
+         * specifies to watch via a distance filter rather than time.
+         */
+        watchHeading:function(successCallback, errorCallback, options) {
+            argscheck.checkArgs('fFO', 'compass.watchHeading', arguments);
+            // Default interval (100 msec)
+            var frequency = (options !== undefined && options.frequency !== undefined) ? options.frequency : 100;
+            var filter = (options !== undefined && options.filter !== undefined) ? options.filter : 0;
+
+            var id = utils.createUUID();
+            if (filter > 0) {
+                // is an iOS request for watch by filter, no timer needed
+                timers[id] = "iOS";
+                compass.getCurrentHeading(successCallback, errorCallback, options);
+            } else {
+                // Start watch timer to get headings
+                timers[id] = window.setInterval(function() {
+                    compass.getCurrentHeading(successCallback, errorCallback);
+                }, frequency);
+            }
+
+            return id;
+        },
+
+        /**
+         * Clears the specified heading watch.
+         * @param {String} watchId The ID of the watch returned from #watchHeading.
+         */
+        clearWatch:function(id) {
+            // Stop javascript timer & remove from timer list
+            if (id && timers[id]) {
+                if (timers[id] != "iOS") {
+                    clearInterval(timers[id]);
+                } else {
+                    // is iOS watch by filter so call into device to stop
+                    exec(null, null, "Compass", "stopHeading", []);
+                }
+                delete timers[id];
+            }
+        }
+    };
+
+module.exports = compass;
+
+});
+
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
+// file: lib/common/plugin/console-via-logger.js
+define("cordova/plugin/console-via-logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+
+var logger = require("cordova/plugin/logger");
+var utils  = require("cordova/utils");
+
+//------------------------------------------------------------------------------
+// object that we're exporting
+//------------------------------------------------------------------------------
+var console = module.exports;
+
+//------------------------------------------------------------------------------
+// copy of the original console object
+//------------------------------------------------------------------------------
+var WinConsole = window.console;
+
+//------------------------------------------------------------------------------
+// whether to use the logger
+//------------------------------------------------------------------------------
+var UseLogger = false;
+
+//------------------------------------------------------------------------------
+// Timers
+//------------------------------------------------------------------------------
+var Timers = {};
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+function noop() {}
+
+//------------------------------------------------------------------------------
+// used for unimplemented methods
+//------------------------------------------------------------------------------
+console.useLogger = function (value) {
+    if (arguments.length) UseLogger = !!value;
+
+    if (UseLogger) {
+        if (logger.useConsole()) {
+            throw new Error("console and logger are too intertwingly");
+        }
+    }
+
+    return UseLogger;
+};
+
+//------------------------------------------------------------------------------
+console.log = function() {
+    if (logger.useConsole()) return;
+    logger.log.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.error = function() {
+    if (logger.useConsole()) return;
+    logger.error.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.warn = function() {
+    if (logger.useConsole()) return;
+    logger.warn.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.info = function() {
+    if (logger.useConsole()) return;
+    logger.info.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.debug = function() {
+    if (logger.useConsole()) return;
+    logger.debug.apply(logger, [].slice.call(arguments));
+};
+
+//------------------------------------------------------------------------------
+console.assert = function(expression) {
+    if (expression) return;
+
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
+    console.log("ASSERT: " + message);
+};
+
+//------------------------------------------------------------------------------
+console.clear = function() {};
+
+//------------------------------------------------------------------------------
+console.dir = function(object) {
+    console.log("%o", object);
+};
+
+//------------------------------------------------------------------------------
+console.dirxml = function(node) {
+    console.log(node.innerHTML);
+};
+
+//------------------------------------------------------------------------------
+console.trace = noop;
+
+//------------------------------------------------------------------------------
+console.group = console.log;
+
+//------------------------------------------------------------------------------
+console.groupCollapsed = console.log;
+
+//------------------------------------------------------------------------------
+console.groupEnd = noop;
+
+//------------------------------------------------------------------------------
+console.time = function(name) {
+    Timers[name] = new Date().valueOf();
+};
+
+//------------------------------------------------------------------------------
+console.timeEnd = function(name) {
+    var timeStart = Timers[name];
+    if (!timeStart) {
+        console.warn("unknown timer: " + name);
+        return;
+    }
+
+    var timeElapsed = new Date().valueOf() - timeStart;
+    console.log(name + ": " + timeElapsed + "ms");
+};
+
+//------------------------------------------------------------------------------
+console.timeStamp = noop;
+
+//------------------------------------------------------------------------------
+console.profile = noop;
+
+//------------------------------------------------------------------------------
+console.profileEnd = noop;
+
+//------------------------------------------------------------------------------
+console.count = noop;
+
+//------------------------------------------------------------------------------
+console.exception = console.log;
+
+//------------------------------------------------------------------------------
+console.table = function(data, columns) {
+    console.log("%o", data);
+};
+
+//------------------------------------------------------------------------------
+// return a new function that calls both functions passed as args
+//------------------------------------------------------------------------------
+function wrappedOrigCall(orgFunc, newFunc) {
+    return function() {
+        var args = [].slice.call(arguments);
+        try { orgFunc.apply(WinConsole, args); } catch (e) {}
+        try { newFunc.apply(console,    args); } catch (e) {}
+    };
+}
+
+//------------------------------------------------------------------------------
+// For every function that exists in the original console object, that
+// also exists in the new console object, wrap the new console method
+// with one that calls both
+//------------------------------------------------------------------------------
+for (var key in console) {
+    if (typeof WinConsole[key] == "function") {
+        console[key] = wrappedOrigCall(WinConsole[key], console[key]);
+    }
+}
+
+});
+
+// file: lib/common/plugin/contacts.js
+define("cordova/plugin/contacts", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError'),
+    utils = require('cordova/utils'),
+    Contact = require('cordova/plugin/Contact');
+
+/**
+* Represents a group of Contacts.
+* @constructor
+*/
+var contacts = {
+    /**
+     * Returns an array of Contacts matching the search criteria.
+     * @param fields that should be searched
+     * @param successCB success callback
+     * @param errorCB error callback
+     * @param {ContactFindOptions} options that can be applied to contact searching
+     * @return array of Contacts matching search criteria
+     */
+    find:function(fields, successCB, errorCB, options) {
+        argscheck.checkArgs('afFO', 'contacts.find', arguments);
+        if (!fields.length) {
+            errorCB && errorCB(new ContactError(ContactError.INVALID_ARGUMENT_ERROR));
+        } else {
+            var win = function(result) {
+                var cs = [];
+                for (var i = 0, l = result.length; i < l; i++) {
+                    cs.push(contacts.create(result[i]));
+                }
+                successCB(cs);
+            };
+            exec(win, errorCB, "Contacts", "search", [fields, options]);
+        }
+    },
+
+    /**
+     * This function creates a new contact, but it does not persist the contact
+     * to device storage. To persist the contact to device storage, invoke
+     * contact.save().
+     * @param properties an object whose properties will be examined to create a new Contact
+     * @returns new Contact object
+     */
+    create:function(properties) {
+        argscheck.checkArgs('O', 'contacts.create', arguments);
+        var contact = new Contact();
+        for (var i in properties) {
+            if (typeof contact[i] !== 'undefined' && properties.hasOwnProperty(i)) {
+                contact[i] = properties[i];
+            }
+        }
+        return contact;
+    }
+};
+
+module.exports = contacts;
+
+});
+
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
+// file: lib/common/plugin/device.js
+define("cordova/plugin/device", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    channel = require('cordova/channel'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec');
+
+// Tell cordova channel to wait on the CordovaInfoReady event
+channel.waitForInitialization('onCordovaInfoReady');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device() {
+    this.available = false;
+    this.platform = null;
+    this.version = null;
+    this.uuid = null;
+    this.cordova = null;
+    this.model = null;
+
+    var me = this;
+
+    channel.onCordovaReady.subscribe(function() {
+        me.getInfo(function(info) {
+            var buildLabel = info.cordova;
+            if (buildLabel != CORDOVA_JS_BUILD_LABEL) {
+                buildLabel += ' JS=' + CORDOVA_JS_BUILD_LABEL;
+            }
+            me.available = true;
+            me.platform = info.platform;
+            me.version = info.version;
+            me.uuid = info.uuid;
+            me.cordova = buildLabel;
+            me.model = info.model;
+            channel.onCordovaInfoReady.fire();
+        },function(e) {
+            me.available = false;
+            utils.alert("[ERROR] Error initializing Cordova: " + e);
+        });
+    });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function(successCallback, errorCallback) {
+    argscheck.checkArgs('fF', 'Device.getInfo', arguments);
+    exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
+};
+
+module.exports = new Device();
+
+});
+
+// file: lib/common/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+
+});
+
+// file: lib/common/plugin/echo.js
+define("cordova/plugin/echo", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
+
+/**
+ * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
+ * @param successCallback  invoked with a FileSystem object
+ * @param errorCallback  invoked if error occurs retrieving file system
+ * @param message  The string to be echoed.
+ * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
+ */
+module.exports = function(successCallback, errorCallback, message, forceAsync) {
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
+    }
+
+    exec(successCallback, errorCallback, "Echo", action, args);
+};
+
+
+});
+
+// file: lib/ios/plugin/file/symbols.js
+define("cordova/plugin/file/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper'),
+    symbolshelper = require('cordova/plugin/file/symbolshelper');
+
+symbolshelper(modulemapper.clobbers);
+modulemapper.merges('cordova/plugin/ios/Entry', 'Entry');
+
+});
+
+// file: lib/common/plugin/file/symbolshelper.js
+define("cordova/plugin/file/symbolshelper", function(require, exports, module) {
+
+module.exports = function(exportFunc) {
+    exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry');
+    exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader');
+    exportFunc('cordova/plugin/Entry', 'Entry');
+    exportFunc('cordova/plugin/File', 'File');
+    exportFunc('cordova/plugin/FileEntry', 'FileEntry');
+    exportFunc('cordova/plugin/FileError', 'FileError');
+    exportFunc('cordova/plugin/FileReader', 'FileReader');
+    exportFunc('cordova/plugin/FileSystem', 'FileSystem');
+    exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
+    exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
+    exportFunc('cordova/plugin/FileWriter', 'FileWriter');
+    exportFunc('cordova/plugin/Flags', 'Flags');
+    exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
+    exportFunc('cordova/plugin/Metadata', 'Metadata');
+    exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
+    exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
+    exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
+};
+
+});
+
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
+// file: lib/common/plugin/geolocation.js
+define("cordova/plugin/geolocation", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    PositionError = require('cordova/plugin/PositionError'),
+    Position = require('cordova/plugin/Position');
+
+var timers = {};   // list of timers in use
+
+// Returns default params, overrides if provided with values
+function parseParameters(options) {
+    var opt = {
+        maximumAge: 0,
+        enableHighAccuracy: false,
+        timeout: Infinity
+    };
+
+    if (options) {
+        if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) {
+            opt.maximumAge = options.maximumAge;
+        }
+        if (options.enableHighAccuracy !== undefined) {
+            opt.enableHighAccuracy = options.enableHighAccuracy;
+        }
+        if (options.timeout !== undefined && !isNaN(options.timeout)) {
+            if (options.timeout < 0) {
+                opt.timeout = 0;
+            } else {
+                opt.timeout = options.timeout;
+            }
+        }
+    }
+
+    return opt;
+}
+
+// Returns a timeout failure, closed over a specified timeout value and error callback.
+function createTimeout(errorCallback, timeout) {
+    var t = setTimeout(function() {
+        clearTimeout(t);
+        t = null;
+        errorCallback({
+            code:PositionError.TIMEOUT,
+            message:"Position retrieval timed out."
+        });
+    }, timeout);
+    return t;
+}
+
+var geolocation = {
+    lastPosition:null, // reference to last known (cached) position returned
+    /**
+   * Asynchronously acquires the current position.
+   *
+   * @param {Function} successCallback    The function to call when the position data is available
+   * @param {Function} errorCallback      The function to call when there is an error getting the heading position. (OPTIONAL)
+   * @param {PositionOptions} options     The options for getting the position data. (OPTIONAL)
+   */
+    getCurrentPosition:function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+        options = parseParameters(options);
+
+        // Timer var that will fire an error callback if no position is retrieved from native
+        // before the "timeout" param provided expires
+        var timeoutTimer = {timer:null};
+
+        var win = function(p) {
+            clearTimeout(timeoutTimer.timer);
+            if (!(timeoutTimer.timer)) {
+                // Timeout already happened, or native fired error callback for
+                // this geo request.
+                // Don't continue with success callback.
+                return;
+            }
+            var pos = new Position(
+                {
+                    latitude:p.latitude,
+                    longitude:p.longitude,
+                    altitude:p.altitude,
+                    accuracy:p.accuracy,
+                    heading:p.heading,
+                    velocity:p.velocity,
+                    altitudeAccuracy:p.altitudeAccuracy
+                },
+                (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+            );
+            geolocation.lastPosition = pos;
+            successCallback(pos);
+        };
+        var fail = function(e) {
+            clearTimeout(timeoutTimer.timer);
+            timeoutTimer.timer = null;
+            var err = new PositionError(e.code, e.message);
+            if (errorCallback) {
+                errorCallback(err);
+            }
+        };
+
+        // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just
+        // fire the success callback with the cached position.
+        if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) {
+            successCallback(geolocation.lastPosition);
+        // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object.
+        } else if (options.timeout === 0) {
+            fail({
+                code:PositionError.TIMEOUT,
+                message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceeds provided PositionOptions' maximumAge parameter."
+            });
+        // Otherwise we have to call into native to retrieve a position.
+        } else {
+            if (options.timeout !== Infinity) {
+                // If the timeout value was not set to Infinity (default), then
+                // set up a timeout function that will fire the error callback
+                // if no successful position was retrieved before timeout expired.
+                timeoutTimer.timer = createTimeout(fail, options.timeout);
+            } else {
+                // This is here so the check in the win function doesn't mess stuff up
+                // may seem weird but this guarantees timeoutTimer is
+                // always truthy before we call into native
+                timeoutTimer.timer = true;
+            }
+            exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]);
+        }
+        return timeoutTimer;
+    },
+    /**
+     * Asynchronously watches the geolocation for changes to geolocation.  When a change occurs,
+     * the successCallback is called with the new location.
+     *
+     * @param {Function} successCallback    The function to call each time the location data is available
+     * @param {Function} errorCallback      The function to call when there is an error getting the location data. (OPTIONAL)
+     * @param {PositionOptions} options     The options for getting the location data such as frequency. (OPTIONAL)
+     * @return String                       The watch id that must be passed to #clearWatch to stop watching.
+     */
+    watchPosition:function(successCallback, errorCallback, options) {
+        argscheck.checkArgs('fFO', 'geolocation.getCurrentPosition', arguments);
+        options = parseParameters(options);
+
+        var id = utils.createUUID();
+
+        // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition
+        timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options);
+
+        var fail = function(e) {
+            clearTimeout(timers[id].timer);
+            var err = new PositionError(e.code, e.message);
+            if (errorCallback) {
+                errorCallback(err);
+            }
+        };
+
+        var win = function(p) {
+            clearTimeout(timers[id].timer);
+            if (options.timeout !== Infinity) {
+                timers[id].timer = createTimeout(fail, options.timeout);
+            }
+            var pos = new Position(
+                {
+                    latitude:p.latitude,
+                    longitude:p.longitude,
+                    altitude:p.altitude,
+                    accuracy:p.accuracy,
+                    heading:p.heading,
+                    velocity:p.velocity,
+                    altitudeAccuracy:p.altitudeAccuracy
+                },
+                (p.timestamp === undefined ? new Date() : ((p.timestamp instanceof Date) ? p.timestamp : new Date(p.timestamp)))
+            );
+            geolocation.lastPosition = pos;
+            successCallback(pos);
+        };
+
+        exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]);
+
+        return id;
+    },
+    /**
+     * Clears the specified heading watch.
+     *
+     * @param {String} id       The ID of the watch returned from #watchPosition
+     */
+    clearWatch:function(id) {
+        if (id && timers[id] !== undefined) {
+            clearTimeout(timers[id].timer);
+            timers[id].timer = false;
+            exec(null, null, "Geolocation", "clearWatch", [id]);
+        }
+    }
+};
+
+module.exports = geolocation;
+
+});
+
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
+// file: lib/common/plugin/globalization.js
+define("cordova/plugin/globalization", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    GlobalizationError = require('cordova/plugin/GlobalizationError');
+
+var globalization = {
+
+/**
+* Returns the string identifier for the client's current language.
+* It returns the language identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the language,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The language identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getPreferredLanguage(function (language) {alert('language:' + language.value + '\n');},
+*                                function () {});
+*/
+getPreferredLanguage:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getPreferredLanguage', arguments);
+    exec(successCB, failureCB, "Globalization","getPreferredLanguage", []);
+},
+
+/**
+* Returns the string identifier for the client's current locale setting.
+* It returns the locale identifier string to the successCB callback with a
+* properties object as a parameter. If there is an error getting the locale,
+* then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {String}: The locale identifier
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getLocaleName(function (locale) {alert('locale:' + locale.value + '\n');},
+*                                function () {});
+*/
+getLocaleName:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getLocaleName', arguments);
+    exec(successCB, failureCB, "Globalization","getLocaleName", []);
+},
+
+
+/**
+* Returns a date formatted as a string according to the client's user preferences and
+* calendar using the time zone of the client. It returns the formatted date string to the
+* successCB callback with a properties object as a parameter. If there is an error
+* formatting the date, then the errorCB callback is invoked.
+*
+* The defaults are: formatLenght="short" and selector="date and time"
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return Object.value {String}: The localized date string
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.dateToString(new Date(),
+*                function (date) {alert('date:' + date.value + '\n');},
+*                function (errorCode) {alert(errorCode);},
+*                {formatLength:'short'});
+*/
+dateToString:function(date, successCB, failureCB, options) {
+    argscheck.checkArgs('dfFO', 'Globalization.dateToString', arguments);
+    var dateValue = date.valueOf();
+    exec(successCB, failureCB, "Globalization", "dateToString", [{"date": dateValue, "options": options}]);
+},
+
+
+/**
+* Parses a date formatted as a string according to the client's user
+* preferences and calendar using the time zone of the client and returns
+* the corresponding date object. It returns the date to the successCB
+* callback with a properties object as a parameter. If there is an error
+* parsing the date string, then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {String} dateString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return    Object.year {Number}: The four digit year
+*            Object.month {Number}: The month from (0 - 11)
+*            Object.day {Number}: The day from (1 - 31)
+*            Object.hour {Number}: The hour from (0 - 23)
+*            Object.minute {Number}: The minute from (0 - 59)
+*            Object.second {Number}: The second from (0 - 59)
+*            Object.millisecond {Number}: The milliseconds (from 0 - 999),
+*                                        not available on all platforms
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+*    globalization.stringToDate('4/11/2011',
+*                function (date) { alert('Month:' + date.month + '\n' +
+*                    'Day:' + date.day + '\n' +
+*                    'Year:' + date.year + '\n');},
+*                function (errorCode) {alert(errorCode);},
+*                {selector:'date'});
+*/
+stringToDate:function(dateString, successCB, failureCB, options) {
+    argscheck.checkArgs('sfFO', 'Globalization.stringToDate', arguments);
+    exec(successCB, failureCB, "Globalization", "stringToDate", [{"dateString": dateString, "options": options}]);
+},
+
+
+/**
+* Returns a pattern string for formatting and parsing dates according to the client's
+* user preferences. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern,
+* then the errorCB callback is invoked.
+*
+* The defaults are: formatLength="short" and selector="date and time"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            formatLength {String}: 'short', 'medium', 'long', or 'full'
+*            selector {String}: 'date', 'time', or 'date and time'
+*
+* @return    Object.pattern {String}: The date and time pattern for formatting and parsing dates.
+*                                    The patterns follow Unicode Technical Standard #35
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.timezone {String}: The abbreviated name of the time zone on the client
+*            Object.utc_offset {Number}: The current difference in seconds between the client's
+*                                        time zone and coordinated universal time.
+*            Object.dst_offset {Number}: The current daylight saving time offset in seconds
+*                                        between the client's non-daylight saving's time zone
+*                                        and the client's daylight saving's time zone.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+*    globalization.getDatePattern(
+*                function (date) {alert('pattern:' + date.pattern + '\n');},
+*                function () {},
+*                {formatLength:'short'});
+*/
+getDatePattern:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getDatePattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getDatePattern", [{"options": options}]);
+},
+
+
+/**
+* Returns an array of either the names of the months or days of the week
+* according to the client's user preferences and calendar. It returns the array of names to the
+* successCB callback with a properties object as a parameter. If there is an error obtaining the
+* names, then the errorCB callback is invoked.
+*
+* The defaults are: type="wide" and item="months"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'narrow' or 'wide'
+*            item {String}: 'months', or 'days'
+*
+* @return Object.value {Array{String}}: The array of names starting from either
+*                                        the first month in the year or the
+*                                        first day of the week.
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getDateNames(function (names) {
+*        for(var i = 0; i < names.value.length; i++) {
+*            alert('Month:' + names.value[i] + '\n');}},
+*        function () {});
+*/
+getDateNames:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getDateNames', arguments);
+    exec(successCB, failureCB, "Globalization", "getDateNames", [{"options": options}]);
+},
+
+/**
+* Returns whether daylight savings time is in effect for a given date using the client's
+* time zone and calendar. It returns whether or not daylight savings time is in effect
+* to the successCB callback with a properties object as a parameter. If there is an error
+* reading the date, then the errorCB callback is invoked.
+*
+* @param {Date} date
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.dst {Boolean}: The value "true" indicates that daylight savings time is
+*                                in effect for the given date and "false" indicate that it is not.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.isDayLightSavingsTime(new Date(),
+*                function (date) {alert('dst:' + date.dst + '\n');}
+*                function () {});
+*/
+isDayLightSavingsTime:function(date, successCB, failureCB) {
+    argscheck.checkArgs('dfF', 'Globalization.isDayLightSavingsTime', arguments);
+    var dateValue = date.valueOf();
+    exec(successCB, failureCB, "Globalization", "isDayLightSavingsTime", [{"date": dateValue}]);
+},
+
+/**
+* Returns the first day of the week according to the client's user preferences and calendar.
+* The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+* It returns the day to the successCB callback with a properties object as a parameter.
+* If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return Object.value {Number}: The number of the first day of the week.
+*
+* @error GlobalizationError.UNKNOWN_ERROR
+*
+* Example
+*    globalization.getFirstDayOfWeek(function (day)
+*                { alert('Day:' + day.value + '\n');},
+*                function () {});
+*/
+getFirstDayOfWeek:function(successCB, failureCB) {
+    argscheck.checkArgs('fF', 'Globalization.getFirstDayOfWeek', arguments);
+    exec(successCB, failureCB, "Globalization", "getFirstDayOfWeek", []);
+},
+
+
+/**
+* Returns a number formatted as a string according to the client's user preferences.
+* It returns the formatted number string to the successCB callback with a properties object as a
+* parameter. If there is an error formatting the number, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Number} number
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {String}: The formatted number string.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.numberToString(3.25,
+*                function (number) {alert('number:' + number.value + '\n');},
+*                function () {},
+*                {type:'decimal'});
+*/
+numberToString:function(number, successCB, failureCB, options) {
+    argscheck.checkArgs('nfFO', 'Globalization.numberToString', arguments);
+    exec(successCB, failureCB, "Globalization", "numberToString", [{"number": number, "options": options}]);
+},
+
+/**
+* Parses a number formatted as a string according to the client's user preferences and
+* returns the corresponding number. It returns the number to the successCB callback with a
+* properties object as a parameter. If there is an error parsing the number string, then
+* the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {String} numberString
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return Object.value {Number}: The parsed number.
+*
+* @error GlobalizationError.PARSING_ERROR
+*
+* Example
+*    globalization.stringToNumber('1234.56',
+*                function (number) {alert('Number:' + number.value + '\n');},
+*                function () { alert('Error parsing number');});
+*/
+stringToNumber:function(numberString, successCB, failureCB, options) {
+    argscheck.checkArgs('sfFO', 'Globalization.stringToNumber', arguments);
+    exec(successCB, failureCB, "Globalization", "stringToNumber", [{"numberString": numberString, "options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing numbers according to the client's user
+* preferences. It returns the pattern to the successCB callback with a properties object as a
+* parameter. If there is an error obtaining the pattern, then the errorCB callback is invoked.
+*
+* The defaults are: type="decimal"
+*
+* @param {Function} successCB
+* @param {Function} errorCB
+* @param {Object} options {optional}
+*            type {String}: 'decimal', "percent", or 'currency'
+*
+* @return    Object.pattern {String}: The number pattern for formatting and parsing numbers.
+*                                    The patterns follow Unicode Technical Standard #35.
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.symbol {String}: The symbol to be used when formatting and parsing
+*                                    e.g., percent or currency symbol.
+*            Object.fraction {Number}: The number of fractional digits to use when parsing and
+*                                    formatting numbers.
+*            Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+*            Object.positive {String}: The symbol to use for positive numbers when parsing and formatting.
+*            Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting.
+*            Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+*            Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.PATTERN_ERROR
+*
+* Example
+*    globalization.getNumberPattern(
+*                function (pattern) {alert('Pattern:' + pattern.pattern + '\n');},
+*                function () {});
+*/
+getNumberPattern:function(successCB, failureCB, options) {
+    argscheck.checkArgs('fFO', 'Globalization.getNumberPattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getNumberPattern", [{"options": options}]);
+},
+
+/**
+* Returns a pattern string for formatting and parsing currency values according to the client's
+* user preferences and ISO 4217 currency code. It returns the pattern to the successCB callback with a
+* properties object as a parameter. If there is an error obtaining the pattern, then the errorCB
+* callback is invoked.
+*
+* @param {String} currencyCode
+* @param {Function} successCB
+* @param {Function} errorCB
+*
+* @return    Object.pattern {String}: The currency pattern for formatting and parsing currency values.
+*                                    The patterns follow Unicode Technical Standard #35
+*                                    http://unicode.org/reports/tr35/tr35-4.html
+*            Object.code {String}: The ISO 4217 currency code for the pattern.
+*            Object.fraction {Number}: The number of fractional digits to use when parsing and
+*                                    formatting currency.
+*            Object.rounding {Number}: The rounding increment to use when parsing and formatting.
+*            Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
+*            Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
+*
+* @error GlobalizationError.FORMATTING_ERROR
+*
+* Example
+*    globalization.getCurrencyPattern('EUR',
+*                function (currency) {alert('Pattern:' + currency.pattern + '\n');}
+*                function () {});
+*/
+getCurrencyPattern:function(currencyCode, successCB, failureCB) {
+    argscheck.checkArgs('sfF', 'Globalization.getCurrencyPattern', arguments);
+    exec(successCB, failureCB, "Globalization", "getCurrencyPattern", [{"currencyCode": currencyCode}]);
+}
+
+};
+
+module.exports = globalization;
+
+});
+
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
+// file: lib/ios/plugin/inappbrowser/symbols.js
+define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
+// file: lib/ios/plugin/ios/Contact.js
+define("cordova/plugin/ios/Contact", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError');
+
+/**
+ * Provides iOS Contact.display API.
+ */
+module.exports = {
+    display : function(errorCB, options) {
+        /*
+         *    Display a contact using the iOS Contact Picker UI
+         *    NOT part of W3C spec so no official documentation
+         *
+         *    @param errorCB error callback
+         *    @param options object
+         *    allowsEditing: boolean AS STRING
+         *        "true" to allow editing the contact
+         *        "false" (default) display contact
+         */
+
+        if (this.id === null) {
+            if (typeof errorCB === "function") {
+                var errorObj = new ContactError(ContactError.UNKNOWN_ERROR);
+                errorCB(errorObj);
+            }
+        }
+        else {
+            exec(null, errorCB, "Contacts","displayContact", [this.id, options]);
+        }
+    }
+};
+
+});
+
+// file: lib/ios/plugin/ios/Entry.js
+define("cordova/plugin/ios/Entry", function(require, exports, module) {
+
+module.exports = {
+    toURL:function() {
+        // TODO: refactor path in a cross-platform way so we can eliminate
+        // these kinds of platform-specific hacks.
+        return "file://localhost" + this.fullPath;
+    },
+    toURI: function() {
+        console.log("DEPRECATED: Update your code to use 'toURL'");
+        return "file://localhost" + this.fullPath;
+    }
+};
+
+});
+
+// file: lib/ios/plugin/ios/contacts.js
+define("cordova/plugin/ios/contacts", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * Provides iOS enhanced contacts API.
+ */
+module.exports = {
+    newContactUI : function(successCallback) {
+        /*
+         *    Create a contact using the iOS Contact Picker UI
+         *    NOT part of W3C spec so no official documentation
+         *
+         * returns:  the id of the created contact as param to successCallback
+         */
+        exec(successCallback, null, "Contacts","newContact", []);
+    },
+    chooseContact : function(successCallback, options) {
+        /*
+         *    Select a contact using the iOS Contact Picker UI
+         *    NOT part of W3C spec so no official documentation
+         *
+         *    @param errorCB error callback
+         *    @param options object
+         *    allowsEditing: boolean AS STRING
+         *        "true" to allow editing the contact
+         *        "false" (default) display contact
+         *      fields: array of fields to return in contact object (see ContactOptions.fields)
+         *
+         *    @returns
+         *        id of contact selected
+         *        ContactObject
+         *            if no fields provided contact contains just id information
+         *            if fields provided contact object contains information for the specified fields
+         *
+         */
+         var win = function(result) {
+             var fullContact = require('cordova/plugin/contacts').create(result);
+            successCallback(fullContact.id, fullContact);
+       };
+        exec(win, null, "Contacts","chooseContact", [options]);
+    }
+};
+
+});
+
+// file: lib/ios/plugin/ios/contacts/symbols.js
+define("cordova/plugin/ios/contacts/symbols", function(require, exports, module) {
+
+require('cordova/plugin/contacts/symbols');
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/ios/contacts', 'navigator.contacts');
+modulemapper.merges('cordova/plugin/ios/Contact', 'Contact');
+
+});
+
+// file: lib/ios/plugin/ios/geolocation/symbols.js
+define("cordova/plugin/ios/geolocation/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/geolocation', 'navigator.geolocation');
+
+});
+
+// file: lib/ios/plugin/ios/logger/plugininit.js
+define("cordova/plugin/ios/logger/plugininit", function(require, exports, module) {
+
+// use the native logger
+var logger = require("cordova/plugin/logger");
+logger.useConsole(true);
+
+});
+
+// file: lib/ios/plugin/ios/logger/symbols.js
+define("cordova/plugin/ios/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'console');
+
+});
+
+// file: lib/ios/plugin/ios/notification.js
+define("cordova/plugin/ios/notification", function(require, exports, module) {
+
+var Media = require('cordova/plugin/Media');
+
+module.exports = {
+    beep:function(count) {
+        (new Media('beep.wav')).play();
+    }
+};
+
+});
+
+// file: lib/common/plugin/logger.js
+define("cordova/plugin/logger", function(require, exports, module) {
+
+//------------------------------------------------------------------------------
+// The logger module exports the following properties/functions:
+//
+// LOG                          - constant for the level LOG
+// ERROR                        - constant for the level ERROR
+// WARN                         - constant for the level WARN
+// INFO                         - constant for the level INFO
+// DEBUG                        - constant for the level DEBUG
+// logLevel()                   - returns current log level
+// logLevel(value)              - sets and returns a new log level
+// useConsole()                 - returns whether logger is using console
+// useConsole(value)            - sets and returns whether logger is using console
+// log(message,...)             - logs a message at level LOG
+// error(message,...)           - logs a message at level ERROR
+// warn(message,...)            - logs a message at level WARN
+// info(message,...)            - logs a message at level INFO
+// debug(message,...)           - logs a message at level DEBUG
+// logLevel(level,message,...)  - logs a message specified level
+//
+//------------------------------------------------------------------------------
+
+var logger = exports;
+
+var exec    = require('cordova/exec');
+var utils   = require('cordova/utils');
+
+var UseConsole   = true;
+var UseLogger    = true;
+var Queued       = [];
+var DeviceReady  = false;
+var CurrentLevel;
+
+var originalConsole = console;
+
+/**
+ * Logging levels
+ */
+
+var Levels = [
+    "LOG",
+    "ERROR",
+    "WARN",
+    "INFO",
+    "DEBUG"
+];
+
+/*
+ * add the logging levels to the logger object and
+ * to a separate levelsMap object for testing
+ */
+
+var LevelsMap = {};
+for (var i=0; i<Levels.length; i++) {
+    var level = Levels[i];
+    LevelsMap[level] = i;
+    logger[level]    = level;
+}
+
+CurrentLevel = LevelsMap.WARN;
+
+/**
+ * Getter/Setter for the logging level
+ *
+ * Returns the current logging level.
+ *
+ * When a value is passed, sets the logging level to that value.
+ * The values should be one of the following constants:
+ *    logger.LOG
+ *    logger.ERROR
+ *    logger.WARN
+ *    logger.INFO
+ *    logger.DEBUG
+ *
+ * The value used determines which messages get printed.  The logging
+ * values above are in order, and only messages logged at the logging
+ * level or above will actually be displayed to the user.  E.g., the
+ * default level is WARN, so only messages logged with LOG, ERROR, or
+ * WARN will be displayed; INFO and DEBUG messages will be ignored.
+ */
+logger.level = function (value) {
+    if (arguments.length) {
+        if (LevelsMap[value] === null) {
+            throw new Error("invalid logging level: " + value);
+        }
+        CurrentLevel = LevelsMap[value];
+    }
+
+    return Levels[CurrentLevel];
+};
+
+/**
+ * Getter/Setter for the useConsole functionality
+ *
+ * When useConsole is true, the logger will log via the
+ * browser 'console' object.
+ */
+logger.useConsole = function (value) {
+    if (arguments.length) UseConsole = !!value;
+
+    if (UseConsole) {
+        if (typeof console == "undefined") {
+            throw new Error("global console object is not defined");
+        }
+
+        if (typeof console.log != "function") {
+            throw new Error("global console object does not have a log function");
+        }
+
+        if (typeof console.useLogger == "function") {
+            if (console.useLogger()) {
+                throw new Error("console and logger are too intertwingly");
+            }
+        }
+    }
+
+    return UseConsole;
+};
+
+/**
+ * Getter/Setter for the useLogger functionality
+ *
+ * When useLogger is true, the logger will log via the
+ * native Logger plugin.
+ */
+logger.useLogger = function (value) {
+    // Enforce boolean
+    if (arguments.length) UseLogger = !!value;
+    return UseLogger;
+};
+
+/**
+ * Logs a message at the LOG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.log   = function(message) { logWithArgs("LOG",   arguments); };
+
+/**
+ * Logs a message at the ERROR level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.error = function(message) { logWithArgs("ERROR", arguments); };
+
+/**
+ * Logs a message at the WARN level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.warn  = function(message) { logWithArgs("WARN",  arguments); };
+
+/**
+ * Logs a message at the INFO level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.info  = function(message) { logWithArgs("INFO",  arguments); };
+
+/**
+ * Logs a message at the DEBUG level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.debug = function(message) { logWithArgs("DEBUG", arguments); };
+
+// log at the specified level with args
+function logWithArgs(level, args) {
+    args = [level].concat([].slice.call(args));
+    logger.logLevel.apply(logger, args);
+}
+
+/**
+ * Logs a message at the specified level.
+ *
+ * Parameters passed after message are used applied to
+ * the message with utils.format()
+ */
+logger.logLevel = function(level /* , ... */) {
+    // format the message with the parameters
+    var formatArgs = [].slice.call(arguments, 1);
+    var message    = logger.format.apply(logger.format, formatArgs);
+
+    if (LevelsMap[level] === null) {
+        throw new Error("invalid logging level: " + level);
+    }
+
+    if (LevelsMap[level] > CurrentLevel) return;
+
+    // queue the message if not yet at deviceready
+    if (!DeviceReady && !UseConsole) {
+        Queued.push([level, message]);
+        return;
+    }
+
+    // Log using the native logger if that is enabled
+    if (UseLogger) {
+        exec(null, null, "Logger", "logLevel", [level, message]);
+    }
+
+    // Log using the console if that is enabled
+    if (UseConsole) {
+        // make sure console is not using logger
+        if (console.__usingCordovaLogger) {
+            throw new Error("console and logger are too intertwingly");
+        }
+
+        // log to the console
+        switch (level) {
+            case logger.LOG:   originalConsole.log(message); break;
+            case logger.ERROR: originalConsole.log("ERROR: " + message); break;
+            case logger.WARN:  originalConsole.log("WARN: "  + message); break;
+            case logger.INFO:  originalConsole.log("INFO: "  + message); break;
+            case logger.DEBUG: originalConsole.log("DEBUG: " + message); break;
+        }
+    }
+};
+
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+    if (formatString === null || formatString === undefined) return [""];
+    if (arguments.length == 1) return [formatString.toString()];
+
+    if (typeof formatString != "string")
+        formatString = formatString.toString();
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest    = formatString;
+    var result  = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg   = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] == '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+    try {
+        switch(formatChar) {
+            case 'j':
+            case 'o': return JSON.stringify(object);
+            case 'c': return '';
+        }
+    }
+    catch (e) {
+        return "error JSON.stringify()ing argument: " + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
+// when deviceready fires, log queued messages
+logger.__onDeviceReady = function() {
+    if (DeviceReady) return;
+
+    DeviceReady = true;
+
+    for (var i=0; i<Queued.length; i++) {
+        var messageArgs = Queued[i];
+        logger.logLevel(messageArgs[0], messageArgs[1]);
+    }
+
+    Queued = null;
+};
+
+// add a deviceready event to log queued messages
+document.addEventListener("deviceready", logger.__onDeviceReady, false);
+
+});
+
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/ios/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.clobbers('cordova/plugin/MediaError', 'MediaError');
+
+});
+
+// file: lib/common/plugin/network.js
+define("cordova/plugin/network", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    cordova = require('cordova'),
+    channel = require('cordova/channel'),
+    utils = require('cordova/utils');
+
+// Link the onLine property with the Cordova-supplied network info.
+// This works because we clobber the naviagtor object with our own
+// object in bootstrap.js.
+if (typeof navigator != 'undefined') {
+    utils.defineGetter(navigator, 'onLine', function() {
+        return this.connection.type != 'none';
+    });
+}
+
+function NetworkConnection() {
+    this.type = 'unknown';
+}
+
+/**
+ * Get connection info
+ *
+ * @param {Function} successCallback The function to call when the Connection data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the Connection data. (OPTIONAL)
+ */
+NetworkConnection.prototype.getInfo = function(successCallback, errorCallback) {
+    exec(successCallback, errorCallback, "NetworkStatus", "getConnectionInfo", []);
+};
+
+var me = new NetworkConnection();
+var timerId = null;
+var timeout = 500;
+
+channel.onCordovaReady.subscribe(function() {
+    me.getInfo(function(info) {
+        me.type = info;
+        if (info === "none") {
+            // set a timer if still offline at the end of timer send the offline event
+            timerId = setTimeout(function(){
+                cordova.fireDocumentEvent("offline");
+                timerId = null;
+            }, timeout);
+        } else {
+            // If there is a current offline event pending clear it
+            if (timerId !== null) {
+                clearTimeout(timerId);
+                timerId = null;
+            }
+            cordova.fireDocumentEvent("online");
+        }
+
+        // should only fire this once
+        if (channel.onCordovaConnectionReady.state !== 2) {
+            channel.onCordovaConnectionReady.fire();
+        }
+    },
+    function (e) {
+        // If we can't get the network info we should still tell Cordova
+        // to fire the deviceready event.
+        if (channel.onCordovaConnectionReady.state !== 2) {
+            channel.onCordovaConnectionReady.fire();
+        }
+        console.log("Error initializing Network Connection: " + e);
+    });
+});
+
+module.exports = me;
+
+});
+
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
+// file: lib/common/plugin/notification.js
+define("cordova/plugin/notification", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var platform = require('cordova/platform');
+
+/**
+ * Provides access to notifications on the device.
+ */
+
+module.exports = {
+
+    /**
+     * Open a native alert dialog, with a customizable title and button text.
+     *
+     * @param {String} message              Message to print in the body of the alert
+     * @param {Function} completeCallback   The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the alert dialog (default: Alert)
+     * @param {String} buttonLabel          Label of the close button (default: OK)
+     */
+    alert: function(message, completeCallback, title, buttonLabel) {
+        var _title = (title || "Alert");
+        var _buttonLabel = (buttonLabel || "OK");
+        exec(completeCallback, null, "Notification", "alert", [message, _title, _buttonLabel]);
+    },
+
+    /**
+     * Open a native confirm dialog, with a customizable title and button text.
+     * The result that the user selects is returned to the result callback.
+     *
+     * @param {String} message              Message to print in the body of the alert
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the alert dialog (default: Confirm)
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
+     */
+    confirm: function(message, resultCallback, title, buttonLabels) {
+        var _title = (title || "Confirm");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Some platforms take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone" || platform.id == "blackberry10") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
+        exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
+    },
+
+    /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     * @param {String} defaultText          Textbox input value (default: "Default text")
+     */
+    prompt: function(message, resultCallback, title, buttonLabels, defaultText) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        var _defaultText = (defaultText || "Default text");
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels, _defaultText]);
+    },
+
+    /**
+     * Causes the device to vibrate.
+     *
+     * @param {Integer} mills       The number of milliseconds to vibrate for.
+     */
+    vibrate: function(mills) {
+        exec(null, null, "Notification", "vibrate", [mills]);
+    },
+
+    /**
+     * Causes the device to beep.
+     * On Android, the default notification ringtone is played "count" times.
+     *
+     * @param {Integer} count       The number of beeps.
+     */
+    beep: function(count) {
+        exec(null, null, "Notification", "beep", [count]);
+    }
+};
+
+});
+
+// file: lib/ios/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/notification', 'navigator.notification');
+modulemapper.merges('cordova/plugin/ios/notification', 'navigator.notification');
+
+});
+
+// file: lib/common/plugin/requestFileSystem.js
+define("cordova/plugin/requestFileSystem", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    FileError = require('cordova/plugin/FileError'),
+    FileSystem = require('cordova/plugin/FileSystem'),
+    exec = require('cordova/exec');
+
+/**
+ * Request a file system in which to store application data.
+ * @param type  local file system type
+ * @param size  indicates how much storage space, in bytes, the application expects to need
+ * @param successCallback  invoked with a FileSystem object
+ * @param errorCallback  invoked if error occurs retrieving file system
+ */
+var requestFileSystem = function(type, size, successCallback, errorCallback) {
+    argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
+    var fail = function(code) {
+        errorCallback && errorCallback(new FileError(code));
+    };
+
+    if (type < 0 || type > 3) {
+        fail(FileError.SYNTAX_ERR);
+    } else {
+        // if successful, return a FileSystem object
+        var success = function(file_system) {
+            if (file_system) {
+                if (successCallback) {
+                    // grab the name and root from the file system object
+                    var result = new FileSystem(file_system.name, file_system.root);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no FileSystem object returned
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+        exec(success, fail, "File", "requestFileSystem", [type, size]);
+    }
+};
+
+module.exports = requestFileSystem;
+
+});
+
+// file: lib/common/plugin/resolveLocalFileSystemURI.js
+define("cordova/plugin/resolveLocalFileSystemURI", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
+    FileEntry = require('cordova/plugin/FileEntry'),
+    FileError = require('cordova/plugin/FileError'),
+    exec = require('cordova/exec');
+
+/**
+ * Look up file system Entry referred to by local URI.
+ * @param {DOMString} uri  URI referring to a local file or directory
+ * @param successCallback  invoked with Entry object corresponding to URI
+ * @param errorCallback    invoked if error occurs retrieving file system entry
+ */
+module.exports = function(uri, successCallback, errorCallback) {
+    argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
+    // error callback
+    var fail = function(error) {
+        errorCallback && errorCallback(new FileError(error));
+    };
+    // sanity check for 'not:valid:filename'
+    if(!uri || uri.split(":").length > 2) {
+        setTimeout( function() {
+            fail(FileError.ENCODING_ERR);
+        },0);
+        return;
+    }
+    // if successful, return either a file or directory entry
+    var success = function(entry) {
+        var result;
+        if (entry) {
+            if (successCallback) {
+                // create appropriate Entry object
+                result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath) : new FileEntry(entry.name, entry.fullPath);
+                successCallback(result);
+            }
+        }
+        else {
+            // no Entry object returned
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    };
+
+    exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]);
+};
+
+});
+
+// file: lib/common/plugin/splashscreen.js
+define("cordova/plugin/splashscreen", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+var splashscreen = {
+    show:function() {
+        exec(null, null, "SplashScreen", "show", []);
+    },
+    hide:function() {
+        exec(null, null, "SplashScreen", "hide", []);
+    }
+};
+
+module.exports = splashscreen;
+
+});
+
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
+// file: lib/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function(a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] == item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function(a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index != -1) {
+        a.splice(index, 1);
+    }
+    return index != -1;
+};
+
+utils.typeName = function(val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = function(a) {
+    return utils.typeName(a) == 'Array';
+};
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function(d) {
+    return utils.typeName(d) == 'Date';
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function(obj) {
+    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if(utils.isArray(obj)){
+        retVal = [];
+        for(i = 0; i < obj.length; ++i){
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for(i in obj){
+        if(!(i in retVal) || retVal[i] != obj[i]) {
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function(context, func, params) {
+    if (typeof params == 'undefined') {
+        return function() {
+            return func.apply(context, arguments);
+        };
+    } else {
+        return function() {
+            return func.apply(context, params);
+        };
+    }
+};
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function() {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function() {
+    // proxy used to establish prototype chain
+    var F = function() {};
+    // extend Child from Parent
+    return function(Child, Parent) {
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function(msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+
+//------------------------------------------------------------------------------
+function UUIDcreatePart(length) {
+    var uuidpart = "";
+    for (var i=0; i<length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length == 1) {
+            uuidchar = "0" + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+
+});
+
+window.cordova = require('cordova');
+// file: lib/scripts/bootstrap.js
+
+(function (context) {
+    if (context._cordovaJsLoaded) {
+        throw new Error('cordova.js included multiple times.');
+    }
+    context._cordovaJsLoaded = true;
+
+    var channel = require('cordova/channel');
+    var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+    function logUnfiredChannels(arr) {
+        for (var i = 0; i < arr.length; ++i) {
+            if (arr[i].state != 2) {
+                console.log('Channel not fired: ' + arr[i].type);
+            }
+        }
+    }
+
+    window.setTimeout(function() {
+        if (channel.onDeviceReady.state != 2) {
+            console.log('deviceready has not fired after 5 seconds.');
+            logUnfiredChannels(platformInitChannelsArray);
+            logUnfiredChannels(channel.deviceReadyChannelsArray);
+        }
+    }, 5000);
+
+    // Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+    // We replace it so that properties that can't be clobbered can instead be overridden.
+    function replaceNavigator(origNavigator) {
+        var CordovaNavigator = function() {};
+        CordovaNavigator.prototype = origNavigator;
+        var newNavigator = new CordovaNavigator();
+        // This work-around really only applies to new APIs that are newer than Function.bind.
+        // Without it, APIs such as getGamepads() break.
+        if (CordovaNavigator.bind) {
+            for (var key in origNavigator) {
+                if (typeof origNavigator[key] == 'function') {
+                    newNavigator[key] = origNavigator[key].bind(origNavigator);
+                }
+            }
+        }
+        return newNavigator;
+    }
+    if (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
+    }
+
+    // _nativeReady is global variable that the native side can set
+    // to signify that the native code is ready. It is a global since
+    // it may be called before any cordova JS is ready.
+    if (window._nativeReady) {
+        channel.onNativeReady.fire();
+    }
+
+    /**
+     * Create all cordova objects once native side is ready.
+     */
+    channel.join(function() {
+        // Call the platform-specific initialization
+        require('cordova/platform').initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once page has fully loaded, all
+        // constructors have run and cordova info has been received from native
+        // side.
+        // This join call is deliberately made after platform.initialize() in
+        // order that plugins may manipulate channel.deviceReadyChannelsArray
+        // if necessary.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, platformInitChannelsArray);
+
+}(window));
+
+// file: lib/scripts/bootstrap-ios.js
+
+require('cordova/channel').onNativeReady.fire();
+
+// file: lib/scripts/plugin_loader.js
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json content.
+    // See plugman's plugin_loader.js for the details of this object.
+    // This function is only called if the really is a plugins array that isn't empty.
+    // Otherwise the XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules, path) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
+
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
+
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    context.cordova.require(module.id);
+                }
+            }
+
+            finishPluginLoading();
+        };
+
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(path + modules[i].file);
+        }
+    }
+
+    // Find the root of the app
+    var path = '';
+    var scripts = document.getElementsByTagName('script');
+    var term = 'cordova.js';
+    for (var n = scripts.length-1; n>-1; n--) {
+        var src = scripts[n].src;
+        if (src.indexOf(term) == (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length);
+            break;
+        }
+    }
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new XMLHttpRequest();
+    xhr.onload = function() {
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        var obj;
+        try {
+            obj = (this.status == 0 || this.status == 200) && this.responseText && JSON.parse(this.responseText);
+        } catch (err) {
+            // obj will be undefined.
+        }
+        if (Array.isArray(obj) && obj.length > 0) {
+            handlePluginsObject(obj, path);
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.onerror = function() {
+        finishPluginLoading();
+    };
+    var plugins_json = path + 'cordova_plugins.json';
+    try { // we commented we were going to try, so let us actually try and catch
+        xhr.open('GET', plugins_json, true); // Async
+        xhr.send();
+    } catch(err){
+        finishPluginLoading();
+    }
+}(window));
+
+
+})();var PhoneGap = cordova;
diff --git a/js/libs/phonegap/plugins/android/webintent.js b/js/libs/phonegap/plugins/android/webintent.js
new file mode 100644 (file)
index 0000000..da22b80
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * cordova Web Intent plugin
+ * Copyright (c) Boris Smus 2010
+ *
+ */
+var WebIntent = function() { 
+
+};
+
+WebIntent.ACTION_SEND = "android.intent.action.SEND";
+WebIntent.ACTION_VIEW= "android.intent.action.VIEW";
+WebIntent.EXTRA_TEXT = "android.intent.extra.TEXT";
+WebIntent.EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+WebIntent.EXTRA_STREAM = "android.intent.extra.STREAM";
+WebIntent.EXTRA_EMAIL = "android.intent.extra.EMAIL";
+
+WebIntent.prototype.startActivity = function(params, success, fail) {
+       return cordova.exec(function(args) {
+        success(args);
+    }, function(args) {
+        fail(args);
+    }, 'WebIntent', 'startActivity', [params]);
+};
+
+WebIntent.prototype.hasExtra = function(params, success, fail) {
+       return cordova.exec(function(args) {
+        success(args);
+    }, function(args) {
+        fail(args);
+    }, 'WebIntent', 'hasExtra', [params]);
+};
+
+WebIntent.prototype.getUri = function(success, fail) {
+       return cordova.exec(function(args) {
+        success(args);
+    }, function(args) {
+        fail(args);
+    }, 'WebIntent', 'getUri', []);
+};
+
+WebIntent.prototype.getExtra = function(params, success, fail) {
+       return cordova.exec(function(args) {
+        success(args);
+    }, function(args) {
+        fail(args);
+    }, 'WebIntent', 'getExtra', [params]);
+};
+
+
+WebIntent.prototype.onNewIntent = function(callback) {
+       return cordova.exec(function(args) {
+               callback(args);
+    }, function(args) {
+    }, 'WebIntent', 'onNewIntent', []);
+};
+
+WebIntent.prototype.sendBroadcast = function(params, success, fail) {
+    return cordova.exec(function(args) {
+        success(args);
+    }, function(args) {
+        fail(args);
+    }, 'WebIntent', 'sendBroadcast', [params]);
+};
+
+cordova.addConstructor(function() {
+       window.webintent = new WebIntent();
+       
+       // backwards compatibility      
+       window.plugins = window.plugins || {};
+       window.plugins.webintent = window.webintent;
+});
diff --git a/js/libs/phonegap/plugins/ios/ExternalFileUtil.js b/js/libs/phonegap/plugins/ios/ExternalFileUtil.js
new file mode 100644 (file)
index 0000000..308d1fd
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ THIS SOFTWARE IS PROVIDED BY ANDREW TRICE "AS IS" AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL ANDREW TRICE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+window.ExternalFileUtil = {
+       openWith: function(path, uti, success, fail, offset) {
+               return cordova.exec(success, fail, "ExternalFileUtil", "openWith", [path, uti, offset.left, offset.top]);
+       }
+};
diff --git a/js/main.js b/js/main.js
new file mode 100644 (file)
index 0000000..9721628
--- /dev/null
@@ -0,0 +1,289 @@
+var fluidbook;
+var desktopScale;
+var dektopScaleAmount;
+var INITED;
+var $_GET;
+var maskHashChange = false;
+var jsLibraries = [];
+var longpresstime = undefined;
+
+$(function() {
+       $_GET = parseGet();
+       INITED = false;
+
+       if (Modernizr.applicationcache) {
+               applicationCache.addEventListener('updateready', cacheUpdated, false);
+               applicationCache.addEventListener('downloading', function(e) {
+               }, false);
+               applicationCache.addEventListener('cached', function(e) {
+                       fluidbook.video.initCache();
+               }, false);
+               applicationCache.addEventListener('noupdate', function(e) {
+                       fluidbook.video.initCache();
+               }, false);
+               applicationCache.addEventListener('checking', function(e) {
+               }, false);
+               applicationCache.addEventListener('error', function(e) {
+               }, false);
+       }
+
+       if (DATAS.phonegap) {
+               document.addEventListener('deviceready', onDeviceReady, false);
+               document.addEventListener("resume", onAppResume, false);
+       } else {
+               init();
+       }
+});
+
+function onAppResume() {
+       if (!INITED) {
+               return;
+       }
+       fluidbook.hideLoader(1);
+}
+
+function onDeviceReady() {
+       init();
+}
+
+function loadJSLibrary(url, callback) {
+       if (!fluidbook.support.hasNetwork()) {
+               return;
+       }
+
+       if (jsLibraries.indexOf(url) > -1) {
+               if (callback != undefined) {
+                       callback();
+
+               }
+               return;
+       }
+       jsLibraries[jsLibraries.length] = url;
+
+       var script = document.createElement("script")
+       script.type = "text/javascript";
+
+       if (script.readyState) {  //IE
+               script.onreadystatechange = function() {
+                       if (script.readyState == "loaded" ||
+                                       script.readyState == "complete") {
+                               script.onreadystatechange = null;
+                               if (callback != undefined) {
+                                       callback();
+                               }
+                       }
+               };
+       } else {  //Others
+               script.onload = function() {
+                       if (callback != undefined) {
+                               callback();
+                       }
+               };
+       }
+
+       script.src = url;
+       document.getElementsByTagName("head")[0].appendChild(script);
+}
+
+function init() {
+       if (INITED == true) {
+               return;
+       }
+       INITED = true;
+
+       fluidbook = new Fluidbook(DATAS);
+       fluidbook.loadPlugins();
+       fluidbook.loader.preloadPages();
+
+       desktopScale = 1;
+       desktopScaleAmount = 1.5;
+
+       $("#main").css('display', 'block');
+       if ($_GET.s == '1') {
+               $('html').addClass('screenshot');
+       }
+
+       initEvents();
+}
+
+function initEvents() {
+       resize(true);
+
+       $(window).bind('hashchange', function() {
+               if (maskHashChange) {
+                       return;
+               }
+               fluidbook.stats.trackPageChange();
+               fluidbook.changeAddress();
+               return false;
+       });
+
+       $("#logo").click(clickLogo);
+
+       $(document).on('click', ".mview .back", function() {
+               if ($(this).hasClass('closeView')) {
+                       fluidbook.closeView(function() {
+                       }, false);
+                       if ($(this).attr('href') != '#') {
+                               maskHashChange = true;
+                               window.location = $(this).attr('href');
+                               setTimeout(function() {
+                                       maskHashChange = false;
+                               }, 200);
+
+                       }
+                       return false;
+               }
+               if ($(this).hasClass('one')) {
+                       fluidbook.closeView(function() {
+                       }, false);
+
+                       if ($(this).attr('href') != '#') {
+                               maskHashChange = true;
+                               window.location = $(this).attr('href');
+                               setTimeout(function() {
+                                       maskHashChange = false;
+                               }, 200);
+                       } else {
+                               maskHashChange = true;
+                               history.back();
+                               setTimeout(function() {
+                                       maskHashChange = false;
+                               }, 200);
+                       }
+                       return false;
+               }
+               if ($(this).attr('href') == '#') {
+                       window.location.hash = '/page/' + fluidbook.currentPage;
+                       return false;
+               }
+       });
+
+       $(document).on('click', '.share', function() {
+               var f = 'send' + ucfirst($(this).data('service'));
+               fluidbook[f]();
+       });
+
+       $(document).on('click', 'a', function() {
+               if (!DATAS.phonegap) {
+                       return true;
+               }
+               var target = $(this).attr('target');
+               if (target == '_blank' || target == '_system') {
+                       fluidbook.wopen($(this).attr('href'), $(this).attr('target'), 'location=no');
+                       return false;
+               }
+               return true;
+       });
+
+
+       setTimeout(function() {
+               resize();
+       }, 1000);
+
+       setInterval(function() {
+               fluidbook.pollZoom();
+       }, 250);
+
+       fluidbook.changeAddress();
+}
+
+function checkScroll() {
+       if (fluidbook.viewMode()) {
+               return;
+       }
+       if (window.innerWidth == 0) {
+               return;
+       }
+       var left = ($(window).width() / 2) - window.scrollX;
+       var right = window.innerWidth - left;
+
+       var reading = (left >= right) ? 'left' : 'right';
+       fluidbook.readingPage(reading);
+}
+
+function changeAddress(event) {
+       fluidbook.changeAddress(event);
+}
+
+function resize(init) {
+       if (init == undefined || init == null) {
+               init = false;
+       }
+       fluidbook.resize.resize(init);
+}
+
+function goNextPage(e) {
+       var y = e.offsetY == undefined ? e.originalEvent.layerY : e.offsetY;
+       if (y < 65) {
+               if (fluidbook.pad.enabled) {
+                       fluidbook.goNextChapter();
+               } else {
+                       fluidbook.goNextPage();
+               }
+       } else {
+               fluidbook.goLastPage();
+       }
+       return false;
+}
+
+function goPreviousPage(e) {
+       var y = e.offsetY == undefined ? e.originalEvent.layerY : e.offsetY;
+       if (y < 65) {
+               if (fluidbook.pad.enabled) {
+                       fluidbook.goPreviousChapter();
+               } else {
+                       fluidbook.goPreviousPage();
+               }
+
+       } else {
+               fluidbook.goFirstPage();
+       }
+       return false;
+}
+
+function clickLogo() {
+       fluidbook.clickLogo();
+       return false;
+}
+
+function preloadBackground(page, resolution) {
+       fluidbook.preloadBackground(page, resolution);
+}
+
+function setBackground(page, resolution) {
+       fluidbook.setBackground(page, resolution);
+}
+
+function searchHints() {
+       if ($("#q").val().length >= 3) {
+               fluidbook.getSearchHints($("#q").val());
+       } else {
+               try {
+                       fluidbook.hideSearchHints();
+               } catch (err) {
+
+               }
+       }
+}
+
+function cacheUpdated(e) {
+       applicationCache.swapCache();
+       if (window.confirm(fluidbook.l10n.__('An update of the publication is available. Do you want to load it ?'))) {
+               window.location.reload();
+       }
+}
+
+(function() {
+       var proxied = window.alert;
+       window.alert = function() {
+               if (navigator.notification) {
+                       navigator.notification.alert(arguments[0], function() {
+                       }, "Alert", "Ok");
+               } else {
+                       // do something here
+                       return proxied.apply(this, arguments);
+               }
+       };
+})();
+
diff --git a/js/tester.js b/js/tester.js
new file mode 100644 (file)
index 0000000..4b30b9c
--- /dev/null
@@ -0,0 +1,31 @@
+$(function(){
+       $(window).bind('hashchange',function(){
+               changeAddress();
+       })
+       changeAddress();
+       
+})
+
+function changeAddress(){
+       var args=window.location.hash.split('/');
+       if(args.length==1 || args[1]==''){
+               setCurrentPage(1);
+       }else{
+               page=parseInt(args[1]);
+               setCurrentPage(page)
+       }
+}
+
+function setCurrentPage(page){
+       $.ajax({
+               url: 'data/contents/p'+page+'.html',
+               success: function(data) {
+                       $("#page").html(data);
+               },
+               error:function(){
+                       $("#page").html("");
+               }
+       });
+       
+       $(".background").css('backgroundImage','url(data/background/150/t'+page+'.jpg)');
+}
\ No newline at end of file
diff --git a/js/widget.js b/js/widget.js
new file mode 100644 (file)
index 0000000..206479b
--- /dev/null
@@ -0,0 +1,359 @@
+$(function() {\r
+       _GET = parseGet({\r
+               background: 'transparent',\r
+               target: '_blank',\r
+               link: '../index.html',\r
+               time: 4\r
+       });\r
+       _GET['time'] = Math.max(1.5, _GET['time']);\r
+\r
+       $("body").css('background-color', getColor(_GET['background']));\r
+\r
+       $(window).resize(function() {\r
+               resize();\r
+       });\r
+\r
+       var widget = $("#widget").fluidbookWidget(Math.max(0, DATAS.widgetStart), Math.min(DATAS.pages, DATAS.widgetEnd));\r
+       $(document).on('click', function() {\r
+               window.open(_GET['link'], _GET['target'], 'width=' + screen.width + ',height=' + screen.height + ',status=0,toolbar=0,menubar=0,scrollbars=1');\r
+       });\r
+});\r
+\r
+(function($) {\r
+       function FluidbookWidget(e, from, to) {\r
+               this.transition = 'none';\r
+               if (Modernizr.csstransforms) {\r
+                       this.transition = '2d';\r
+               }\r
+               if (Modernizr.csstransforms3d) {\r
+                       this.transition = '3d';\r
+               }\r
+\r
+               this.started = false;\r
+               this.e = e;\r
+               this.from = from;\r
+               if (this.from % 2 == 1) {\r
+                       this.from--;\r
+               }\r
+               this.to = to;\r
+               if (this.from % 2 == 0) {\r
+                       this.to++;\r
+               }\r
+               this.to = Math.min(DATAS.pages, this.to);\r
+               this.currentPage = 0;\r
+               this.dir = 1;\r
+\r
+               this.bookWidth;\r
+               this.bookHeight;\r
+               this.init();\r
+\r
+               this.transitionendevents = ['transitionend', 'mozTransitionEnd', 'webkitTransitionEnd', 'oTransitionEnd', 'msTransitionEnd'].join(' ');\r
+       }\r
+\r
+       FluidbookWidget.prototype = {\r
+               init: function() {\r
+                       this.e.append('<div id="currentDoublePage"></div>');\r
+\r
+                       // Init pages\r
+                       for (i = this.from; i <= this.to; i++) {\r
+                               var p = i;\r
+                               if (p % 2 == 1) {\r
+                                       p--;\r
+                               }\r
+                               var pclass = 'p';\r
+                               var shade = '';\r
+                               var side = 'left'\r
+                               if (i % 2 == 1) {\r
+                                       side = 'right';\r
+                               }\r
+                               if (i == 0) {\r
+                                       pclass += ' loaded';\r
+                               } else {\r
+\r
+                                       shade = '<div class="shade"><img src="images/shade' + side + '.png" /></div>';\r
+                               }\r
+\r
+                               pclass += ' ' + side;\r
+\r
+\r
+                               this.e.append('<div class="' + pclass + '" data-page="' + i + '">' + shade + '</div>');\r
+                       }\r
+\r
+                       this.preloadImages();\r
+               },\r
+               preloadImages: function() {\r
+                       var $this = this;\r
+                       var p = this.e.find('.p:not(.loaded)').first();\r
+                       if (p.length == 0) {\r
+                               this.endLoading();\r
+                               return;\r
+                       }\r
+                       var page = $(p).attr('data-page');\r
+                       var image = new Image();\r
+                       $(image).one('load error', function() {\r
+                               $(p).append(this);\r
+                               $(p).addClass('loaded');\r
+                               $this.preloadImages();\r
+                       });\r
+                       image.src = 'data/background/36/t' + page + '.jpg';\r
+                       if (image.complete) {\r
+                               $(p).append(image);\r
+                               $(p).addClass('loaded');\r
+                               this.preloadImages();\r
+                       }\r
+               },\r
+               endLoading: function() {\r
+                       if (this.started) {\r
+                               return;\r
+                       }\r
+                       this.started = true;\r
+                       this.e.find('.p').hide();\r
+\r
+\r
+                       var firstImage = $('.p>img').first().get(0);\r
+\r
+                       this.bookWidth = firstImage.width * 2;\r
+                       this.bookHeight = firstImage.height;\r
+\r
+\r
+\r
+                       $("#widget").css({\r
+                               width: this.bookWidth,\r
+                               minWidth: this.bookWidth,\r
+                               maxWidth: this.bookWidth,\r
+                               height: this.bookHeight,\r
+                               minHeight: this.bookHeight,\r
+                               maxHeight: this.bookHeight\r
+                       });\r
+\r
+                       $(".p .shade img").css({\r
+                               width: this.bookWidth / 6,\r
+                               height: this.bookHeight\r
+                       });\r
+\r
+                       $(".p .shade").css({\r
+                               width: this.bookWidth / 2,\r
+                               height: this.bookHeight\r
+                       })\r
+\r
+                       $(".p").css({\r
+                               width: this.bookWidth / 2,\r
+                               height: this.bookHeight\r
+                       })\r
+\r
+\r
+                       this.gotoPage(0, false);\r
+                       var $this = this;\r
+                       setInterval(function() {\r
+                               if ($this.animating) {\r
+                                       return;\r
+                               }\r
+                               $this.goNextPage();\r
+                       }, _GET['time'] * 1000);\r
+\r
+                       $("#container:hidden").fadeIn();\r
+                       this.resize();\r
+               },\r
+               gotoPage: function(page, transition) {\r
+                       this.resize();\r
+                       var $this = this;\r
+                       this.animating = true;\r
+                       var leftPage = $('.p[data-page=' + page + ']');\r
+                       var rightPage = $('.p[data-page=' + (page + 1) + ']');\r
+\r
+                       if (!transition || this.transition == 'none') {\r
+                               $("#nextDoublePage .p,#currentDoublePage .p").hide().appendTo(this.e);\r
+                               $("#currentDoublePage").append($(leftPage)).append($(rightPage));\r
+                               $(leftPage).show();\r
+                               $(rightPage).show();\r
+                               $(".p.right").css({\r
+                                       left: this.bookWidth / 2\r
+                               });\r
+                               $("#currentDoublePage,#nextDoublePage").css({\r
+                                       x: 0,\r
+                                       left: 0\r
+                               });\r
+\r
+                               $("#nextDoublePage").remove();\r
+                               this.animating = false;\r
+                       } else {\r
+                               if (this.transition == '2d') {\r
+                                       $("#widget").css('overflow', 'hidden');\r
+                                       this.e.append('<div id="nextDoublePage"></div>');\r
+                                       $(leftPage).show();\r
+                                       $(rightPage).show();\r
+                                       $("#nextDoublePage").append($(leftPage)).append($(rightPage));\r
+                                       $(".p.right").css({\r
+                                               left: this.bookWidth / 2\r
+                                       });\r
+\r
+                                       if (Modernizr.csstransitions) {\r
+                                               $("#nextDoublePage").css({\r
+                                                       x: this.bookWidth * this.dir\r
+                                               });\r
+                                               $("#currentDoublePage").transition({\r
+                                                       x: this.bookWidth * this.dir * -1\r
+                                               }, 1000);\r
+                                               $("#nextDoublePage").transition({\r
+                                                       x: 0\r
+                                               }, 1000, function() {\r
+                                                       $this.gotoPage(page, false)\r
+                                               });\r
+                                       } else {\r
+                                               $("#nextDoublePage").css({\r
+                                                       left: this.bookWidth * this.dir\r
+                                               });\r
+                                               $("#currentDoublePage").animate({\r
+                                                       left: this.bookWidth * this.dir * -1\r
+                                               }, 1000);\r
+                                               $("#nextDoublePage").animate({\r
+                                                       left: 0\r
+                                               }, 1000, function() {\r
+                                                       $this.gotoPage(page, false)\r
+                                               });\r
+                                       }\r
+                               }\r
+                               else if (this.transition == '3d') {\r
+                                       $("#widget").css('overflow', 'visible');\r
+                                       var nextFromClass;\r
+                                       if (this.dir == 1) {\r
+                                               nextFromClass = 'next';\r
+                                       } else {\r
+                                               nextFromClass = 'prev';\r
+                                       }\r
+\r
+\r
+                                       this.e.append('<div id="nextDoublePage" style="left:' + (this.bookWidth / 2) + 'px" class="' + nextFromClass + 'start _3d"></div>');\r
+\r
+                                       $("#currentDoublePage .p").hide().appendTo(this.e);\r
+                                       var leftTurn, rightTurn;\r
+                                       if (this.dir == 1) {\r
+                                               leftPage = $('.p[data-page=' + this.currentPage + ']');\r
+                                               rightPage = $('.p[data-page=' + (page + 1) + ']');\r
+                                               leftTurn = $('.p[data-page=' + page + ']');\r
+                                               rightTurn = $('.p[data-page=' + (this.currentPage + 1) + ']');\r
+                                       } else {\r
+                                               leftPage = $('.p[data-page=' + page + ']');\r
+                                               rightPage = $('.p[data-page=' + (this.currentPage + 1) + ']');\r
+                                               leftTurn = $('.p[data-page=' + this.currentPage + ']');\r
+                                               rightTurn = $('.p[data-page=' + (page + 1) + ']');\r
+                                       }\r
+\r
+                                       $(leftPage).show();\r
+                                       $(rightPage).show();\r
+                                       $(leftTurn).show();\r
+                                       $(rightTurn).show();\r
+\r
+                                       $("#currentDoublePage").append($(leftPage)).append($(rightPage));\r
+                                       if (this.dir == -1) {\r
+                                               $("#nextDoublePage").append($(leftTurn)).append($(rightTurn));\r
+                                       } else {\r
+                                               $("#nextDoublePage").append($(rightTurn)).append($(leftTurn));\r
+                                       }\r
+                                       $(".p.right").css({\r
+                                               left: this.bookWidth / 2\r
+                                       });\r
+\r
+                                       $("#nextDoublePage").addClass(nextFromClass + 'end');\r
+\r
+                                       $("#nextDoublePage").one(this.transitionendevents, function() {\r
+                                               $this.animating = false;\r
+                                               $this.gotoPage(page, false);\r
+                                       });\r
+                               }\r
+                       }\r
+\r
+                       this.currentPage = page;\r
+               },\r
+               goNextPage: function() {\r
+                       var p;\r
+                       if (this.dir == 1) {\r
+                               p = this.currentPage + 2;\r
+                               if (p > this.to) {\r
+                                       p -= 4;\r
+                                       this.dir = -1;\r
+                               }\r
+                       } else {\r
+                               p = this.currentPage - 2;\r
+                               if (p < this.from) {\r
+                                       p += 4;\r
+                                       this.dir = 1;\r
+                               }\r
+                       }\r
+\r
+                       this.gotoPage(p, true)\r
+\r
+               },\r
+               resize: function() {\r
+                       var w = $(window).width();\r
+                       var h = $(window).height();\r
+\r
+                       var s = Math.min((w * 0.95) / this.bookWidth, (h * 0.95) / this.bookHeight);\r
+\r
+                       var iw = this.bookWidth * s;\r
+                       var ih = this.bookHeight * s;\r
+\r
+                       var x = (w - iw) / 2;\r
+                       var y = (h - ih) / 2;\r
+\r
+                       $("body,#container").css({\r
+                               width: w,\r
+                               maxWidth: w,\r
+                               minWidth: w,\r
+                               height: h,\r
+                               maxHeight: h,\r
+                               minHeight: h\r
+                       });\r
+                       $("#nextDoublePage").css({\r
+                               width: this.bookWidth / 2,\r
+                               maxWidth: this.bookWidth / 2,\r
+                               minWidth: this.bookWidth / 2,\r
+                               height: this.bookHeight,\r
+                               maxHeight: this.bookHeight,\r
+                               minHeight: this.bookHeight,\r
+                               overflow: 'hidden'\r
+                       })\r
+\r
+                       this.e.css({\r
+                               transformOrigin: '0% 0%',\r
+                               x: x,\r
+                               y: y,\r
+                               scale: s\r
+                       });\r
+               }\r
+       };\r
+\r
+       jQuery.fn.fluidbookWidget = function(from, to) {\r
+               return this.each(function() {\r
+                       var $this = $(this);\r
+                       widget = new FluidbookWidget($this, from, to);\r
+               })\r
+       };\r
+})(jQuery);\r
+\r
+function parseGet(res) {\r
+       if (res == undefined) {\r
+               res = {};\r
+       }\r
+       var couples = window.location.search.substr(1).split('&');\r
+       var couple = new Array();\r
+       for (var i = 0; i < couples.length; i++) {\r
+               couple = couples[i].split('=');\r
+               res[couple[0]] = couple[1];\r
+       }\r
+       return res;\r
+}\r
+\r
+function getColor(color) {\r
+       if (color == 'transparent' || color.substr(0, 3) == 'rgb') {\r
+               return color;\r
+       }\r
+       if (color.length == 6) {\r
+               return '#' + color;\r
+       }\r
+       return color;\r
+}\r
+\r
+function resize() {\r
+       widget.resize();\r
+}
\ No newline at end of file
diff --git a/plugins/com/promotal/catalogue/plugin.css b/plugins/com/promotal/catalogue/plugin.css
new file mode 100644 (file)
index 0000000..c2b4a8e
--- /dev/null
@@ -0,0 +1,105 @@
+.distributors ul{\r
+       display:none;\r
+}\r
+\r
+.distributors li.prox ul{\r
+       display:block;\r
+}\r
+\r
+.content .map,\r
+.content .adresse{\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+       -webkit-box-sizing: border-box;\r
+       -ms-box-sizing: border-box;\r
+       -o-box-sizing: border-box;\r
+       width:50%;\r
+       height:400px;\r
+       padding:40px 40px 0 40px;\r
+}\r
+\r
+.content .map .details{\r
+       color:#000;\r
+       text-align: left;\r
+}\r
+\r
+.portrait .content .map,\r
+.portrait .content .adresse{\r
+       width:100%;\r
+}\r
+\r
+.content .map{\r
+       float:left;\r
+}\r
+\r
+.content .map>div{\r
+       height:100%;\r
+}\r
+\r
+.animate .content .map{\r
+       visibility:hidden;\r
+}\r
+\r
+.content .adresse{\r
+       float:left;\r
+       text-align: left;\r
+}\r
+\r
+.promotions a,a.button{\r
+       display:inline-block;\r
+       padding:8px 32px 8px 16px;\r
+       border-radius: 6px;\r
+       font-weight: bold;\r
+       margin:10px 0;\r
+       background-image: url("../../../../images/arrow-button.png");\r
+       background-repeat: no-repeat;\r
+       background-position: 100% 50%;\r
+       background-color:#00386c;\r
+}\r
+\r
+\r
+.promotions>div{\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+       -webkit-box-sizing: border-box;\r
+       -ms-box-sizing: border-box;\r
+       -o-box-sizing: border-box;\r
+       display: inline-block;\r
+       padding:40px;\r
+       text-align: left;\r
+       vertical-align: top;\r
+}\r
+.promotions .visuel{\r
+       width:45%;\r
+}\r
+\r
+.promotions .visuel img{\r
+       width:100%;\r
+       box-shadow: 2px 2px 4px rgba(0,0,0,0.3);\r
+       -moz-box-shadow: 2px 2px 4px rgba(0,0,0,0.3);\r
+       -webkit-box-shadow: 2px 2px 4px rgba(0,0,0,0.3);\r
+       -ms-box-shadow: 2px 2px 4px rgba(0,0,0,0.3);\r
+       -o-box-shadow: 2px 2px 4px rgba(0,0,0,0.3);\r
+}\r
+\r
+.promotions h4{\r
+       margin:0 40px;\r
+}\r
+\r
+.promotions .dotclear{\r
+       width:55%;\r
+}\r
+\r
+.promotions hr{\r
+       border:0;\r
+       border-bottom: 2px groove #a54581;\r
+}\r
+\r
+.promotions del{\r
+       font-size: 80%;\r
+       text-decoration: none;\r
+}\r
+\r
+.promotions p{\r
+       margin:15px 0;\r
+}
\ No newline at end of file
diff --git a/plugins/com/promotal/catalogue/plugin.js b/plugins/com/promotal/catalogue/plugin.js
new file mode 100644 (file)
index 0000000..3382d0a
--- /dev/null
@@ -0,0 +1,273 @@
+var gmaps = false;\r
+function com_promotal_catalogue() {\r
+       var locale = fluidbook.l10n.getActiveLang();\r
+\r
+       if (fluidbook.support.hasNetwork()) {\r
+               loadJSLibrary('https://maps.googleapis.com/maps/api/js?v=3&sensor=false&callback=initgmap');\r
+               gmaps = true;\r
+               $.ajax({\r
+                       crossDomain: true,\r
+                       url: 'http://promotal.fluidbook.com/application/distributeurs/' + locale,\r
+                       dataType: 'json',\r
+                       success: function(data) {\r
+                               fluidbook.cache.set('distributeurs_' + locale, data);\r
+                               if (typeof data == 'string') {\r
+                                       data = JSON.parse(data);\r
+                               }\r
+                               distributeurs = data;\r
+                               fluidbook.nav.addLink('nav-map', '#/distributors', 'map', 'find a distributor', 'help');\r
+                       },\r
+                       error: getDistributeursFromCache\r
+               });\r
+\r
+               $.ajax({\r
+                       crossDomain: true,\r
+                       url: 'http://promotal.fluidbook.com/application/promotions/' + locale,\r
+                       dataType: 'json',\r
+                       success: function(data) {\r
+                               fluidbook.cache.set('promotions_' + locale, data);\r
+                               promotions = data;\r
+                               if (promotions.length > 0) {\r
+                                       fluidbook.nav.addLink('nav-tag', '#/promotions', 'tag', 'promotions', 'help');\r
+                               }\r
+                       },\r
+                       error: getPromotionsFromCache\r
+               });\r
+\r
+       } else {\r
+               getDistributeursFromCache();\r
+               getPromotionsFromCache();\r
+       }\r
+}\r
+\r
+function getDistributeursFromCache() {\r
+\r
+       var locale = fluidbook.l10n.getActiveLang();\r
+       if (fluidbook.cache.isset('distributeurs_' + locale)) {\r
+               distributeurs = fluidbook.cache.get('distributeurs_' + locale);\r
+               fluidbook.nav.addLink('nav-map', '#/distributors', 'map', 'find a distributor', 'help');\r
+       }\r
+}\r
+\r
+function getPromotionsFromCache() {\r
+\r
+       var locale = fluidbook.l10n.getActiveLang();\r
+       if (fluidbook.cache.isset('promotions_' + locale)) {\r
+               promotions = fluidbook.cache.get('promotions_' + locale);\r
+               if (promotions.length > 0) {\r
+                       fluidbook.nav.addLink('nav-tag', '#/promotions', 'tag', 'promotions', 'help');\r
+               }\r
+       }\r
+}\r
+\r
+Fluidbook.prototype.openDistributors = function(id, p2, callback) {\r
+       var $this = this;\r
+       if (this.distributeursMenu == undefined) {\r
+               this.distributeursList = [];\r
+               this.distributeursMenu = '';\r
+               var i = 0;\r
+\r
+               html = '<ul class="chapters distributors">';\r
+               $.each(distributeurs, function(k0, r1) {\r
+                       html += '<li data-level="0"><a class="level0" href="#">' + k0 + '</a>';\r
+                       html += '<ul>';\r
+                       if (r1 != null) {\r
+                               $.each(r1, function(k1, r2) {\r
+                                       if (!isNaN(parseInt(k1))) {\r
+                                               html += '<li data-level="1"><a class="level1" href="#/distributors/' + $this.distributeursList.length + '">' + r2.nom + ' - ' + r2.ville + '</a></li>';\r
+                                               r2.id = $this.distributeursList.length;\r
+                                               $this.distributeursList.push(r2);\r
+                                       } else {\r
+                                               html += '<li data-level="1"><a class="level1" href="#">' + k1 + '</a>';\r
+                                               html += '<ul>';\r
+                                               $.each(r2, function(k2, r3) {\r
+                                                       html += '<li data-level="2"><a class="level2" href="#">' + k2 + '</a>';\r
+                                                       html += '<ul>';\r
+                                                       $.each(r3, function(k3, r4) {\r
+                                                               html += '<li data-level="2"><a class="level3" href="#/distributors/' + $this.distributeursList.length + '">' + r4.nom + ' - ' + r4.ville + '</a></li>';\r
+                                                               r4.id = $this.distributeursList.length;\r
+                                                               $this.distributeursList.push(r4);\r
+                                                       });\r
+                                                       html += '</ul>';\r
+                                                       html += '</li>';\r
+                                               });\r
+                                               html += '</ul>';\r
+                                               html += '</li>';\r
+                                       }\r
+                               });\r
+                       }\r
+                       html += '</ul>';\r
+                       html += '</li>';\r
+               });\r
+               html += '</ul>';\r
+               for (var i = 3; i >= 0; i--) {\r
+                       $(html).find('li[data-level=' + i + ']').each(function() {\r
+                               var siblings = $(this).nextUntil('li[data-level!=' + (i + 1) + ']', 'li[data-level=' + (i + 1) + ']');\r
+                               if (siblings.length > 0) {\r
+                                       $(this).append('<ul></ul>');\r
+                                       var nav = $(this).find('ul');\r
+                                       $(nav).append(siblings);\r
+                                       $(nav).hide();\r
+                               }\r
+                       });\r
+               }\r
+               html = $(html).get(0).outerHTML;\r
+               $(document).off('click', 'ul.chapters a');\r
+               $(document).on('click', 'ul.chapters a', function() {\r
+                       var li = $(this).parent();\r
+                       var subnav = $(li).children('ul');\r
+                       if ($(subnav).length) {\r
+                               if ($(subnav).is(':visible')) {\r
+                                       $(subnav).slideUp();\r
+                               } else {\r
+                                       $(subnav).slideDown();\r
+                               }\r
+\r
+                               return false;\r
+                       } else {\r
+                               return true;\r
+                       }\r
+               });\r
+               this.distributeursMenu = html;\r
+\r
+               if (Modernizr.geolocation) {\r
+                       navigator.geolocation.getCurrentPosition(function(position) {\r
+                               $this.distributorsGotPosition(position);\r
+                       }, function(code, message) {\r
+                               $this.distributorsGotPositionError(code, message);\r
+                       });\r
+               }\r
+       }\r
+\r
+       if (id == undefined) {\r
+               var view = '<div class="caption"><a href="#" class="back">&laquo; ' + this.l10n.__('back') + '</a><h2>' + this.l10n.__('find a distributor') + '</h2></div>';\r
+               view += '<div class="content">';\r
+               view += this.distributeursMenu;\r
+               view += '</div>';\r
+               $("#view").append('<div class="mview">' + view + '</div>');\r
+       } else {\r
+               var dist = this.distributeursList[id];\r
+               var q = dist.adresse.replace(/\n/g, ', ');\r
+               var view = '<div class="caption"><a href="#/distributors" class="back closeView">&laquo; ' + this.l10n.__('back') + '</a><h2>' + dist.nom + '</h2></div>';\r
+               view += '<div class="content">';\r
+               if (dist.pos != null && gmaps) {\r
+                       var rand = Math.round(Math.random() * 10000);\r
+\r
+                       var mapStyles = [{featureType: "poi", elementType: "labels", stylers: [{visibility: "off"}]}];\r
+\r
+                       var mapOptions = {\r
+                               zoom: 12,\r
+                               center: new google.maps.LatLng(dist.pos.lat, dist.pos.lng),\r
+                               mapTypeId: google.maps.MapTypeId.ROADMAP,\r
+                               styles: mapStyles,\r
+                               mapTypeControlOptions: {\r
+                                       mapTypeIds: []\r
+                               }\r
+\r
+                       };\r
+                       view += '<div class="map"><div class="gmap" id="map_' + rand + '"></div></div>';\r
+               }\r
+               var details = '<div class="details"><h3>' + dist.nom + '</h3>' + dist.adresse.replace(/\n/g, '<br />') + '</div>';\r
+               var tel = '';\r
+               if (dist.telephone != '') {\r
+                       tel = this.l10n.__('tel:') + ' <a href="tel:' + dist.telephone + '">' + dist.telephone + '</a>' + '<br />';\r
+               }\r
+               view += '<div class="adresse">' + details + tel + '<div><a class="button" href="mailto:?subject=' + dist.nom + '&body=' + encodeURIComponent(dist.nom + "\n" + dist.adresse + "\n\n" + this.l10n.__('tel:') + ' ' + dist.telephone) + '">' + this.l10n.__('Send details by email') + '</a></div></div>';\r
+               view += '</div>';\r
+               $("#view").append('<div class="mview hori">' + view + '</div>');\r
+\r
+               if (dist.pos != null && gmaps) {\r
+                       var map = new google.maps.Map(document.getElementById('map_' + rand),\r
+                                       mapOptions);\r
+\r
+\r
+\r
+                       var marker = new google.maps.Marker({\r
+                               position: new google.maps.LatLng(dist.pos.lat, dist.pos.lng),\r
+                               map: map,\r
+                               infos: new google.maps.InfoWindow({\r
+                                       content: details\r
+                               })\r
+                       });\r
+\r
+                       setTimeout(function() {\r
+                               google.maps.event.trigger(map, 'resize');\r
+                               map.setCenter(mapOptions.center);\r
+                               marker.infos.open(map, marker);\r
+                       }, 250);\r
+\r
+                       google.maps.event.addListener(marker, 'click', function() {\r
+                               this.infos.open(map, this);\r
+                       });\r
+               }\r
+       }\r
+\r
+       if (callback != undefined) {\r
+               callback();\r
+       }\r
+};\r
+Fluidbook.prototype.openPromotions = function(p1, p2, callback) {\r
+       var view = '<div class="caption"><a href="#" class="back">&laquo; ' + this.l10n.__('back') + '</a><h2>' + this.l10n.__('promotions') + '</h2></div>';\r
+       view += '<div class="content promotions">';\r
+       view += promotions.join('<hr />');\r
+       view += '</div>';\r
+\r
+\r
+\r
+       $("#view").append('<div class="mview">' + view + '</div>');\r
+       $("#view .mview:last a").attr('target', '_blank');\r
+\r
+       if (callback != undefined) {\r
+               callback();\r
+       }\r
+};\r
+\r
+Fluidbook.prototype.distributorsGotPosition = function(position) {\r
+       var list = [];\r
+       $.each(this.distributeursList, function(k, v) {\r
+               if (v.pos == null) {\r
+                       return;\r
+               }\r
+               v.distance = haversine({latitude: v.pos.lat, longitude: v.pos.lng}, position.coords);\r
+               list.push(v);\r
+       });\r
+       list.sort(function(a, b) {\r
+               return a.distance - b.distance;\r
+       });\r
+       var proxList = list.slice(0, 15);\r
+\r
+       var prox = '<li data-level="0" class="prox"><a class="level0" href="#">' + this.l10n.__('next to me') + '</a>';\r
+       prox += '<ul>';\r
+       $.each(proxList, function(k, v) {\r
+               prox += '<li data-level="1"><a class="level1" href="#/distributors/' + v.id + '">' + v.nom + ' - ' + v.ville + '</a></li>';\r
+       });\r
+       prox += '</ul>';\r
+       prox += '</li>';\r
+       $(".mview .content .distributors").prepend(prox);\r
+       this.distributeursMenu = $(".mview .content").html();\r
+       $(".mview .content .distributors>li>ul:first").hide().slideDown();\r
+};\r
+Fluidbook.prototype.distributorsGotPositionError = function(code, message) {\r
+\r
+};\r
+\r
+function haversine(p1, p2) {\r
+       var R = 6371\r
+       var dLat = rad(p2.latitude - p1.latitude)\r
+       var dLong = rad(p2.longitude - p1.longitude)\r
+\r
+       var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +\r
+                       Math.cos(rad(p1.latitude)) * Math.cos(rad(p2.latitude)) * Math.sin(dLong / 2) * Math.sin(dLong / 2)\r
+       var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))\r
+       var d = R * c\r
+\r
+       return Math.round(d);\r
+}\r
+\r
+function rad(x) {\r
+       return x * Math.PI / 180\r
+}\r
+\r
+function initgmap() {\r
+\r
+}\r
diff --git a/style/fluidbook.css b/style/fluidbook.css
new file mode 100644 (file)
index 0000000..7362369
--- /dev/null
@@ -0,0 +1,1323 @@
+/* Screenshot */\r
+.screenshot .mview{\r
+       overflow-y: hidden;\r
+}\r
+\r
+/* Incompatible */\r
+.no-csstransforms #device{\r
+       display:none;\r
+}\r
+.csstransforms #message{\r
+       display:none;\r
+}\r
+\r
+/* Disable print div*/\r
+#printpages{\r
+       display:none;\r
+}\r
+\r
+/* Global settings */\r
+a,input[type=text],input[type=password],input[type=file],textarea{outline:none;-webkit-appearance:none;}\r
+a{text-decoration:none;color:inherit;}\r
+*{\r
+       padding:0;\r
+       margin:0;\r
+\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+       -webkit-box-sizing: border-box;\r
+       -ms-box-sizing: border-box;\r
+       -o-box-sizing: border-box;\r
+\r
+       -webkit-tap-highlight-color:rgba(0,0,0,0);\r
+       -ms-touch-action:double-tap-zoom pinch-zoom; \r
+       -ms-scroll-chaining:chained;\r
+\r
+       -webkit-font-smoothing:antialiased;\r
+}\r
+\r
+img{\r
+       border:0;\r
+       box-sizing:content-box;\r
+       -moz-box-sizing: content-box;\r
+       -webkit-box-sizing: content-box;\r
+       -ms-box-sizing: content-box;\r
+       -o-box-sizing: content-box;\r
+}\r
+\r
+b,strong,h1,h2,h3,h4,h5,h6{\r
+       font-weight: 600;\r
+}\r
+\r
+.pan,.pan *{\r
+       -ms-touch-action:auto;\r
+}\r
+\r
+\r
+html{\r
+       user-select:text;\r
+       -moz-user-select:text;\r
+       -webkit-user-select:text;\r
+       -o-user-select:text;\r
+       -ms-user-select:text;\r
+\r
+}\r
+\r
+body {\r
+    -webkit-touch-callout: none !important;\r
+}\r
+\r
+\r
+body,input{\r
+       font-family: Ubuntu, Arial, Helvetica, sans-serif;\r
+}\r
+\r
+body.loading *{\r
+       cursor:progress !important;\r
+}\r
+\r
+body{\r
+       overflow-y: hidden;\r
+       overflow-x: hidden;\r
+}\r
+\r
+#main{\r
+       position:absolute;\r
+       display:none;\r
+       overflow:hidden;\r
+       visibility: hidden;\r
+}\r
+\r
+#hiddencontents{\r
+       display:none;\r
+}\r
+\r
+/* Background */\r
+#background{\r
+       position: absolute;\r
+    left: 0;\r
+    top: 0;\r
+    width: 100%;\r
+       height: 100%;\r
+       z-index:0;\r
+}\r
+\r
+#background .links{\r
+       position:absolute;\r
+}\r
+\r
+/* Orientation */\r
+.portrait .shade, .portrait .page.right{display:none;}\r
+.portrait .hideOnPortrait{display:none;}\r
+\r
+/* Desktop devices */\r
+\r
+.desktop #links{\r
+       cursor:url(../images/cur-zoom-in.png), -moz-zoom-in;\r
+}\r
+.desktop.zoomed #links{\r
+       cursor:url(../images/cur-zoom-out.png), -moz-zoom-out;\r
+}\r
+\r
+#links .link{\r
+       cursor:auto;\r
+}\r
+\r
+/* Coquillette */\r
+#coquillette{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       z-index: 1000;\r
+}\r
+\r
+/* Pages */\r
+.background,.texts{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       overflow: visible;\r
+}      \r
+\r
+.background{\r
+       background-repeat:no-repeat;\r
+}\r
+\r
+.background img{\r
+       width:100%;\r
+       height:100%;\r
+}\r
+\r
+.texts{\r
+}\r
+\r
+.texts img,.texts object{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+\r
+/* Espaces forcés */\r
+\r
+.page{\r
+       overflow: hidden;\r
+       position:absolute;\r
+       top:0px;\r
+       background-color:#fff;\r
+}\r
+\r
+.page .shade{\r
+       position:absolute;\r
+       top:0px;\r
+}\r
+\r
+\r
+.page.right .shade{\r
+       left:0px;\r
+}\r
+\r
+.page.left .shade{\r
+       right:0px;\r
+}\r
+\r
+.background,.texts, .l, .g, .s{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+.texts .g {\r
+    line-height: 1;\r
+}\r
+\r
+.g,.gs,.l{\r
+       white-space: nowrap;\r
+}\r
+.texts .gs{\r
+       display:inline-block;\r
+}\r
+\r
+.o{\r
+       font-style: oblique;\r
+}\r
+\r
+\r
+.doublePage,#shadow,#pages{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       overflow:hidden;\r
+}\r
+#pages{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+\r
+}\r
+\r
+/* Nav */\r
+#nav #locales{\r
+       display: inline-block;\r
+       width:22px;\r
+       height:17px;\r
+       border-radius: 3px;\r
+       background-position:50% 50%;\r
+       background-repeat:no-repeat;\r
+       margin:11px 2px 10px 22px;\r
+}\r
+\r
+.localesList li a{\r
+       padding:10px 20px !important;\r
+}\r
+\r
+.localesList li a img{\r
+       vertical-align: middle;\r
+       margin:-2px 20px 0 0;\r
+}\r
+\r
+/* Fluidbook */\r
+#fluidbook{\r
+       position:absolute;\r
+       z-index: 11;\r
+}\r
+\r
+#cache{\r
+       display:none;\r
+}\r
+\r
+#pagesnumbers{\r
+       font-size:12px;\r
+       padding: 0;\r
+       position: absolute;\r
+       white-space: nowrap;\r
+       margin:5px 0 0 0;\r
+}\r
+\r
+#pagesnumbers div{\r
+       text-align: center;\r
+       display:inline-block;\r
+}\r
+\r
+.portrait #pagesnumbers .right{\r
+       display:none;\r
+}\r
+\r
+/* Interface */\r
+#interface{\r
+       position:static;\r
+}\r
+\r
+#next,#previous{\r
+       background:#f00;\r
+       width: 40px;\r
+       height:100px;\r
+       position:absolute;\r
+       top:310px;\r
+       display:block;\r
+       opacity:1;\r
+       z-index:21;\r
+}\r
+\r
+#next,#previous,#down,#splash{\r
+       transition: opacity 1s ease-in-out;\r
+       -moz-transition: opacity 1s ease-in-out;\r
+       -webkit-transition: opacity 1s ease-in-out;\r
+       -o-transition: opacity 1s ease-in-out;\r
+       -ms-transition: opacity 1s ease-in-out;\r
+}\r
+\r
+#next.hidden.help,#previous.hidden.help{\r
+       transition: none;\r
+       -moz-transition: none;\r
+       -webkit-transition: none;\r
+       -o-transition: none;\r
+       -ms-transition: none;\r
+       opacity:1;\r
+\r
+}\r
+\r
+#next.hidden,#previous.hidden{\r
+       opacity:0;\r
+       cursor:default;\r
+}\r
+\r
+#next{\r
+       right:0px;\r
+       border-top-left-radius:7px;\r
+       border-bottom-left-radius:7px;\r
+}\r
+\r
+#previous{\r
+       left:0px;\r
+       border-top-right-radius:7px;\r
+       border-bottom-right-radius:7px;\r
+}\r
+\r
+/* Header */\r
+header{position:relative;}\r
+#nav>a{\r
+       margin:0 0 0 20px;\r
+       vertical-align: top;\r
+}\r
+#nav>a>img{\r
+       padding: 10px 2px 0px 2px;\r
+       vertical-align: top;\r
+}\r
+\r
+#nav{\r
+       float:left;\r
+       position:relative;\r
+       z-index:12;\r
+       white-space: nowrap;\r
+}\r
+\r
+#afterSearch{\r
+       display:inline-block;\r
+       position:relative;\r
+       vertical-align: top;\r
+       left:30px;\r
+}\r
+\r
+#afterSearch .c{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       z-index: 9;\r
+       display: block;\r
+}\r
+\r
+#afterSearch .links{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       z-index:10;\r
+}\r
+\r
+#search{\r
+       position:relative;\r
+       display:inline-block;\r
+       margin:8px 0 0 30px;\r
+       z-index: 2;\r
+       vertical-align: top;\r
+}\r
+#search img{\r
+       vertical-align: middle;\r
+}\r
+#search input{\r
+       padding:5px;\r
+       border-radius:5px;\r
+       border: 0;\r
+       height:22px;\r
+       width:150px;\r
+\r
+}\r
+\r
+.hint{\r
+       padding:5px;\r
+       height:22px;\r
+       width:140px;\r
+       margin:2px;\r
+       background-color:#fff;\r
+       color:#000;\r
+       display:block;\r
+       font-size:12px;\r
+}\r
+.hint:hover{\r
+       background-color:#000;\r
+       color:#fff;\r
+}\r
+\r
+#searchHints{\r
+       background:#fff;\r
+       border-radius:5px;\r
+       width:150px;\r
+       padding:5px;\r
+       display:none;\r
+}\r
+\r
+#logo{\r
+       position:absolute;\r
+       top:0px;\r
+       right:0px;\r
+       background-repeat: no-repeat;\r
+       z-index: 10;\r
+}\r
+.portrait #logo{\r
+       display:none;\r
+}\r
+\r
+/* Credits */\r
+footer{\r
+       font-family: Silkscreen,Arial,Helvetica,sans-serif;\r
+       font-size:8px;\r
+       text-transform: uppercase;\r
+       position: absolute;\r
+       bottom:0px;\r
+       right:0px;\r
+       z-index: 20;\r
+}\r
+footer a{\r
+       text-decoration: none;\r
+       margin:0 4px 4px 0;\r
+}\r
+\r
+/* Fluidbook zooming */\r
+\r
+footer,header,#interface{\r
+       -moz-transition: opacity 400ms ease-in;\r
+       -webkit-transition: opacity 400ms ease-in;\r
+       -o-transition: opacity 400ms ease-in;\r
+       -ms-transition: opacity 400ms ease-in;\r
+       transition: opacity 400ms ease-in;\r
+}\r
+\r
+footer.hidden,header.hidden,#interface.hidden{\r
+       opacity:0;\r
+       z-index:0;\r
+}\r
+\r
+#fluidbook{\r
+       -moz-transition: -moz-transform 1s ease-out,transform 1s ease-out;\r
+       -webkit-transition:-webkit-transform 1s ease-out,transform 1s ease-out;\r
+       -o-transition: -o-transform 1s ease-out,transform 1s ease-out;\r
+       -ms-transition: -ms-transform 1s ease-out,transform 1s ease-out;\r
+       transition: transform 1s ease-out;\r
+}\r
+\r
+#fluidbook.animate{\r
+       -moz-transition: all 1s ease-out;\r
+       -webkit-transition: all 1s ease-out;\r
+       -ms-transition: all 1s ease-out;\r
+       -o-transition: all 1s ease-out;\r
+       transition: all 1s ease-out;\r
+}\r
+\r
+/* Links */\r
+#links{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       z-index:4;\r
+       background-color: rgba(0,0,0,0.001);\r
+}\r
+\r
+.link{\r
+       position: absolute;\r
+       cursor:auto;\r
+       z-index: 2;\r
+}\r
+\r
+.link.multimedia{\r
+       z-index:1;\r
+}\r
+\r
+.link.contentLink{\r
+       z-index:0;\r
+}\r
+\r
+.link a{\r
+       width:100%;\r
+       height:100%;\r
+       display:block;\r
+       border-radius:5px;\r
+       background-color:rgba(0,0,0,0.001);\r
+}\r
+\r
+.link a.displayArea.animating{\r
+       -moz-transition: opacity 1s ease-in;\r
+       -webkit-transition: opacity 1s ease-in;\r
+       -o-transition: opacity 1s ease-in;\r
+       -ms-transition: opacity 1s ease-in;\r
+       transition: opacity 1s ease-in;\r
+}\r
+\r
+#links .nonlinkarea{\r
+       display:none;\r
+}\r
+\r
+.pad #links .nonlinkarea{\r
+       width:100%;\r
+       height:100%;\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       display: block;\r
+}\r
+\r
+/* Bookmarks */\r
+.bookmark.left{\r
+       background-image: url("../data/images/bookmark-left-off.svg");\r
+}\r
+\r
+.bookmark.right,\r
+.portrait #fluidbook .bookmark.left{\r
+       background-image: url("../data/images/bookmark-right-off.svg");\r
+}\r
+\r
+.bookmark.left[data-enabled]{\r
+       background-image: url("../data/images/bookmark-left-on.svg");\r
+}\r
+\r
+.bookmark.right[data-enabled],\r
+.portrait #fluidbook .bookmark.left[data-enabled]{\r
+       background-image: url("../data/images/bookmark-right-on.svg");\r
+}\r
+\r
+.no-svg .bookmark.left{\r
+       background-image: url("../data/images/bookmark-left-off.png");\r
+}\r
+\r
+.no-svg .bookmark.right,\r
+.no-svg .portrait #fluidbook .bookmark.left{\r
+       background-image: url("../data/images/bookmark-right-off.png");\r
+}\r
+\r
+.no-svg .bookmark.left[data-enabled]{\r
+       background-image: url("../data/images/bookmark-left-on.png");\r
+}\r
+\r
+.no-svg .bookmark.right[data-enabled],\r
+.no-svg .portrait #fluidbook .bookmark.left[data-enabled]{\r
+       background-image: url("../data/images/bookmark-right-on.png");\r
+}\r
+\r
+.bookmark.animating{\r
+       -moz-transition: opacity 1s ease-in;\r
+       -webkit-transition: opacity 1s ease-in;\r
+       -o-transition: opacity 1s ease-in;\r
+       -ms-transition: opacity 1s ease-in;\r
+       transition: opacity 1s ease-in;\r
+}\r
+\r
+.bookmark{\r
+       background-repeat: no-repeat;\r
+       background-size:cover;\r
+       position:absolute;\r
+       top:0px;\r
+       opacity: 0;\r
+       display: block;\r
+       cursor:pointer;\r
+}\r
+\r
+.bookmark[data-enabled],.bookmark:hover{\r
+       opacity: 1 !important;\r
+       -moz-transition: none;\r
+       -webkit-transition: none;\r
+       -o-transition: none;\r
+       -ms-transition: none;\r
+       transition: none;\r
+}\r
+\r
+#indexView .bookmark{\r
+       width:35px;\r
+       height:35px;\r
+}\r
+\r
+.landscape .bookmark.left{\r
+       left:0px;\r
+}\r
+\r
+.bookmark.right{\r
+       right:0px;\r
+}\r
+\r
+/* View */\r
+\r
+.mview{\r
+       position:absolute;\r
+       z-index:22;\r
+       display:none;\r
+       overflow-x: hidden;\r
+    overflow-y: auto;\r
+       -webkit-overflow-scrolling: touch;\r
+       text-shadow: 0px -1px 0px rgba(0,0,0,0.15);\r
+       background-repeat: no-repeat;\r
+       background-size: 100% 100%;\r
+}\r
+\r
+.mview.animate{\r
+       -moz-transition: -moz-transform 600ms ease-out,transform 600ms ease-out;\r
+       -webkit-transition:-webkit-transform 600ms ease-out;\r
+       -o-transition: -o-transform 600ms ease-out,transform 600ms ease-out;\r
+       -ms-transition: -ms-transform 600ms ease-out,transform 600ms ease-out;\r
+       transition: transform 600ms ease-out;\r
+}\r
+\r
+.mview .caption{\r
+       padding:9px 12px;\r
+       height:44px;\r
+       position:absolute;\r
+       z-index: 1;\r
+}\r
+\r
+.mview .caption h2{\r
+       font-size:20px;\r
+       line-height: 22px;\r
+       text-align: center;\r
+       font-weight: 500;\r
+       margin:0 auto;\r
+       overflow: hidden;\r
+       text-overflow: ellipsis;\r
+    white-space: nowrap;\r
+}\r
+\r
+.mview .caption .fonctions{\r
+       position:absolute;\r
+       top:9px;\r
+       right:12px;\r
+}\r
+\r
+.mview .caption .fonctions a{\r
+       float:right;\r
+       margin:0 0 0 10px;\r
+}\r
+\r
+.mview .caption a{\r
+       height:27px;\r
+       font-weight: 600;\r
+       font-size:14px;\r
+       line-height: 25px;\r
+       display: block;\r
+\r
+       box-shadow:inset 1px 1px 0px rgba(255,255,255,0.3);\r
+       -moz-box-shadow:inset 1px 1px 0px rgba(255,255,255,0.3);\r
+       -webkit-box-shadow:inset 1px 1px 0px rgba(255,255,255,0.3);\r
+       -ms-box-shadow:inset 1px 1px 0px rgba(255,255,255,0.3);\r
+       -o-box-shadow:inset 1px 1px 0px rgba(255,255,255,0.3);\r
+\r
+       background-repeat: no-repeat;\r
+       background-position:10px 4px;\r
+\r
+       border-radius:5px;\r
+}\r
+\r
+.mview .caption a.back{\r
+       position:absolute;\r
+       top:9px;\r
+       left:12px;\r
+\r
+       background-image:url("../data/images/interface-back-arrow.svg");\r
+       background-size:auto 17px;\r
+       padding:0 13px 0 27px;\r
+}\r
+\r
+.mview .caption a.send{\r
+       background-image:url("../data/images/share-email.svg");\r
+}\r
+\r
+.mview .caption a.print{\r
+       background-image:url("../data/images/interface-print.svg");\r
+}\r
+\r
+.mview .caption a{\r
+       padding:0 13px 0 33px;\r
+       background-size:auto 17px;\r
+}\r
+\r
+.portrait .mview .caption a.miniOnPortrait {\r
+       background-position: 50% 50%;\r
+       padding:0 15px;\r
+}\r
+\r
+\r
+.mview .content{\r
+       text-align: center;\r
+       position:absolute;\r
+       top:44px;\r
+}\r
+\r
+#indexView{\r
+       margin:auto;\r
+}\r
+\r
+#indexView .doubleThumb,#indexView .padding{\r
+       display:inline-block;\r
+       margin:10px 10px 40px 10px;\r
+       position:relative;\r
+       width:200px;\r
+       cursor:pointer;\r
+       text-align: center;\r
+}\r
+\r
+#indexView.bookmarkView .doubleThumb{\r
+       width:100px;\r
+\r
+}\r
+\r
+#indexView.bookmarkView .doubleThumb.left{\r
+       margin-right:10px;\r
+}\r
+\r
+#indexView.bookmarkView{\r
+       text-align: left;\r
+}\r
+\r
+\r
+#indexView .padding{\r
+       height:1px;\r
+}\r
+\r
+\r
+#indexView .doubleThumb .overlay{\r
+       background-color:rgba(0,0,0,0.5);\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       width:200px;\r
+       z-index:4;\r
+}\r
+\r
+#indexView .doubleThumb.simple .overlay{\r
+       width:100px;\r
+}\r
+\r
+\r
+#indexView .doubleThumb .hits{\r
+       position:relative;\r
+       display:inline;\r
+       top:30px;\r
+       z-index:5;\r
+       font-size:12px;\r
+}\r
+\r
+#indexView .doubleThumb .hits.yes{\r
+       padding:5px;\r
+       border-radius:5px;\r
+}\r
+#indexView .thumb{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       font-size:12px;\r
+}\r
+\r
+#indexView .thumb img{\r
+       background:#fff;\r
+}\r
+\r
+#indexView .thumb .number{\r
+       text-align:center;\r
+       display:block;\r
+       font-family: Arial,Helvetica,sans-serif;\r
+       margin: 1px 0 0 0;\r
+       max-width: 100px;\r
+}\r
+\r
+#indexView .thumb.right{\r
+       left:100px;\r
+}\r
+\r
+#indexView .doubleThumb.simple{\r
+       width:100px;\r
+}\r
+\r
+#indexView .doubleThumb.simple.right{\r
+       margin-left:110px;\r
+}\r
+#indexView .doubleThumb.left{\r
+       margin-right:110px;\r
+}\r
+\r
+\r
+#indexView .right .thumb.right{\r
+       left:0px;\r
+}\r
+\r
+/* Search */\r
+.highlight0{\r
+       background-color:#00ff00;\r
+}\r
+.highlight1{\r
+       background-color:#ffff00;\r
+}\r
+.highlight2{\r
+       background-color:#00ffff;\r
+}\r
+.highlight3{\r
+       background-color:#ff00ff;\r
+}\r
+.highlight4{\r
+       background-color:#ff0000;\r
+}\r
+\r
+/* Share */\r
+\r
+ul.chapters.shareList a.level0 img{\r
+       height:25px;\r
+       margin:2px 10px 0 0;\r
+       position:relative;\r
+       top:3px;\r
+}\r
+\r
+/* Help */\r
+#helpView{\r
+       background-color: rgba(0,0,0,0.7);\r
+       position:absolute;\r
+       z-index:20;\r
+       display:none;\r
+       color:#ffffff;\r
+       overflow:hidden;\r
+}\r
+\r
+#helpView .illustration{\r
+       text-align:center;\r
+       font-size:20px;\r
+}\r
+\r
+#helpView .illustration p{\r
+       position:static;\r
+}\r
+\r
+#helpView #icons{\r
+       position:absolute;\r
+       top:0px;\r
+       font-size:16px;\r
+}\r
+\r
+#helpView .icon{\r
+       position:absolute;\r
+       top:0px;\r
+       display:inline-block;\r
+       border-left: 1px solid #ffffff;\r
+       text-align: left;\r
+       width:400px;\r
+       padding-left:5px;\r
+}\r
+\r
+#helpView .interface hr{\r
+       width:30px;\r
+       height:0px;\r
+       border:0;\r
+       border-top:1px solid #ffffff;\r
+       display:inline-block;\r
+       margin: 0 10px;\r
+       vertical-align: middle;\r
+}\r
+\r
+#helpView .down{\r
+       position:absolute;\r
+       right:62px;\r
+       bottom:20px;\r
+}\r
+\r
+#helpView .down hr{\r
+       width:30px;\r
+       height:0px;\r
+       border:0;\r
+       border-top:1px solid #ffffff;\r
+       display:inline-block;\r
+       margin: 0 10px;\r
+       vertical-align: middle;\r
+}\r
+\r
+#helpView .interface .next,\r
+#helpView .interface .last{\r
+       text-align: right;\r
+       right:40px;\r
+       top:340px;\r
+}\r
+\r
+#helpView .interface .first,\r
+#helpView .interface .previous{\r
+       left:40px;\r
+       top:340px;\r
+}\r
+\r
+#helpView .interface .first,\r
+#helpView .interface .last{\r
+       margin-top:43px;\r
+}\r
+\r
+#helpView .interface .next,\r
+#helpView .interface .previous{\r
+       margin-top:-5px;\r
+}\r
+\r
+\r
+#helpView .interface div{\r
+       position:absolute;\r
+}\r
+\r
+.portrait #helpView .interface{\r
+       display:none;\r
+}\r
+\r
+.pad.portrait #helpView .interface{\r
+       display:block;\r
+}\r
+\r
+.pad #helpView .illustration{\r
+       display:none;\r
+}\r
+\r
+/* Archives */\r
+#archivesview{\r
+       position:relative;\r
+       overflow: hidden;\r
+       top:44px;\r
+}\r
+\r
+#archivesview img{\r
+       width:100%;\r
+}\r
+\r
+#archivesview .links{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+\r
+/* Videos */\r
+.mview .videoContainer{\r
+       box-sizing: border-box;\r
+       -moz-box-sizing: border-box;\r
+       -webkit-box-sizing: border-box;\r
+       -ms-box-sizing: border-box;\r
+       -o-box-sizing: border-box;\r
+       padding:20px;\r
+       width:100%;\r
+       height:100%;\r
+}\r
+\r
+.mview .videoContainer video,\r
+.mview .videoContainer object,.webvideo{\r
+       position:static;\r
+       width: 100%;\r
+       height:auto;\r
+       display: block;\r
+}\r
+.videoContainer{\r
+       position:relative;\r
+}\r
+\r
+/* Chapters */\r
+ul.chapters a{\r
+       display:block;\r
+       text-align: left;\r
+       padding:10px 20px 10px 20px;\r
+}\r
+\r
+ul.chapters a.level-1{\r
+       font-size:200%;\r
+       font-family: Ubuntu;\r
+       font-weight: 600;\r
+       text-align: center;\r
+}\r
+\r
+ul.chapters a.level-1 .right{\r
+       display:none;\r
+}\r
+\r
+ul.chapters a.level0,ul.chapters a.level1,ul.chapters a.level2,ul.chapters a.level3{\r
+       border-top: 1px solid rgba(255,255,255,0.3);\r
+\r
+}\r
+\r
+ul.chapters a.level0{\r
+       font-size:150%;\r
+       font-family: Ubuntu;\r
+       font-weight: 500;\r
+}\r
+\r
+ul.chapters a.level1{\r
+       padding:10px 20px 10px 50px;\r
+       font-size:120%;\r
+}\r
+\r
+ul.chapters a.level2{\r
+       padding:10px 20px 10px 80px;\r
+       font-size: 100%;\r
+}\r
+\r
+ul.chapters a.level3{\r
+       padding:10px 20px 10px 110px;\r
+       font-size:80%;\r
+}\r
+\r
+ul.chapters, ul.chapters ul{\r
+       list-style: none;\r
+}\r
+\r
+ul.chapters a .right{\r
+       float:right;\r
+}\r
+\r
+ul.chapters a .right .puce{\r
+       width:25px;\r
+       height:25px;\r
+\r
+       border-radius: 5px;\r
+       -moz-border-radius: 5px;\r
+       -webkit-border-radius: 5px;\r
+       -ms-border-radius: 5px;\r
+       -o-border-radius: 5px;\r
+\r
+       box-shadow: 2px 2px 4px rgba(0,0,0,0.25);\r
+       -moz-box-shadow: 2px 2px 4px rgba(0,0,0,0.25);\r
+       -webkit-box-shadow: 2px 2px 4px rgba(0,0,0,0.25);\r
+       -ms-box-shadow: 2px 2px 4px rgba(0,0,0,0.25);\r
+       -o-box-shadow: 2px 2px 4px rgba(0,0,0,0.25);\r
+\r
+\r
+       background-image: url("../images/chapters-arrow.png");\r
+       background-repeat: no-repeat;\r
+}\r
+\r
+ul.chapters a.level0 .right .puce{\r
+       margin:2px 0 0 0;\r
+}\r
+\r
+ul.chapters a.level2 .right .puce{\r
+       margin:-2px 0 0 0;\r
+}\r
+\r
+ul.chapters a>nav{\r
+       display:none;\r
+}\r
+\r
+/* ipad mag */\r
+.pad #pagesnumbers,\r
+.pad footer\r
+{\r
+       display:none;\r
+}\r
+\r
+.pad #interface,\r
+.pad header{\r
+       opacity: 0;\r
+       visibility: hidden;\r
+       z-index: 21;\r
+}\r
+\r
+.pad #interface{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       width:100%;\r
+}\r
+\r
+#down{\r
+       display:none;\r
+}\r
+\r
+.pad #down{\r
+       display:block;\r
+       width:40px;\r
+       height:40px;\r
+       border-radius:5px;\r
+       background-image: url("../data/images/interface-down.svg");\r
+       background-repeat: no-repeat;\r
+       padding:8px 8px 8px 8px;\r
+       position:absolute;\r
+       bottom:10px;\r
+       right:10px;\r
+       background-size: 24px 24px;\r
+       background-position: 50% 50%;\r
+       z-index: 22;\r
+       opacity:0;\r
+       background-color:rgba(0,0,0,0.6);\r
+\r
+       -moz-transition: all .15s ease-out;\r
+       -webkit-transition:all .15s ease-out;\r
+       -o-transition: all .15s ease-out;\r
+       -ms-transition: all .15s ease-out;\r
+       transition: all .15s ease-out;\r
+\r
+       -moz-transform-origin: 50% 20px;\r
+       -webkit-transform-origin: 50% 20px;\r
+       -ms-transform-origin: 50% 20px;\r
+       -o-transform-origin: 50% 20px;\r
+       transform-origin: 50% 20px;\r
+\r
+       -moz-transform: rotate(0deg);\r
+       -webkit-transform: rotate(0deg);\r
+       -ms-transform: rotate(0deg);\r
+       -o-transform: rotate(0deg);\r
+       transform: rotate(0deg);\r
+}\r
+\r
+#down.right{\r
+       -moz-transform:  rotate(-90deg);\r
+       -webkit-transform: rotate(-90deg);\r
+       -ms-transform: rotate(-90deg);\r
+       -o-transform: rotate(-90deg);\r
+       transform: rotate(-90deg);\r
+}\r
+\r
+/*  Transitions */\r
+\r
+/* 2D */\r
+.doublePage._2d.sliding{\r
+       -moz-transition:none;\r
+       -webkit-transition:none;\r
+       -o-transition: none;\r
+       -ms-transition: none;\r
+       transition: none;\r
+}\r
+\r
+/* 3D */\r
+#pages._3dtransition{\r
+       -moz-perspective:5000px;\r
+       -webkit-perspective:5000px;\r
+       -o-perspective:5000px;\r
+       -ms-perspective:5000px;\r
+       perspective: 5000px;\r
+\r
+       -moz-perspective-origin:50% 75%;\r
+       -webkit-perspective-origin:50% 75%;\r
+       -ms-perspective-origin:50% 75%;\r
+       -o-perspective-origin:50% 75%;\r
+       perspective-origin: 50% 75%;\r
+\r
+       overflow: visible !important;\r
+}\r
+\r
+.doublePage._3d{\r
+       overflow: visible;\r
+       z-index:100;\r
+\r
+       -moz-transform-style:preserve-3d;\r
+       -webkit-transform-style:preserve-3d;\r
+       -o-transform-style:preserve-3d;\r
+       -ms-transform-style:preserve-3d;\r
+       transform-style: preserve-3d;\r
+}\r
+\r
+._3d .page{\r
+       -moz-backface-visibility:hidden;\r
+       -webkit-backface-visibility:hidden;\r
+       -o-backface-visibility:hidden;\r
+       -ms-backface-visibility:hidden;\r
+       backface-visibility: hidden;\r
+\r
+       left:0px !important;\r
+}\r
+\r
+.doublePage._3d .right{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,0deg);\r
+       -o-transform:  rotate3d(0,1,0,0deg);\r
+       -ms-transform:  rotate3d(0,1,0,0deg);\r
+       transform:  rotate3d(0,1,0,0deg);\r
+       -moz-transform:  rotateY(0deg) translate3d(0,0,0);\r
+}\r
+\r
+.doublePage._3d .left{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+}\r
+\r
+.doublePage._3d.nextstart{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,360deg);\r
+       -o-transform:  rotate3d(0,1,0,360deg);\r
+       -ms-transform:  rotate3d(0,1,0,360deg);\r
+       transform:  rotate3d(0,1,0,360deg);\r
+       -moz-transform:  rotateY(360deg) translate3d(0,0,0);\r
+\r
+       -moz-transform-origin: 0 0;\r
+       -webkit-transform-origin: 0 0;\r
+       -o-transform-origin: 0 0;\r
+       -ms-transform-origin: 0 0;\r
+       transform-origin: 0 0;\r
+}\r
+\r
+.doublePage._3d.nextend{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+}\r
+\r
+.doublePage._3d.prevstart{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+\r
+       -moz-transform-origin: 0 0;\r
+       -webkit-transform-origin: 0 0;\r
+       -o-transform-origin: 0 0;\r
+       -ms-transform-origin: 0 0;\r
+       transform-origin: 0 0;\r
+}\r
+\r
+.doublePage._3d.prevend{\r
+\r
+       -webkit-transform:  rotate3d(0,1,0,360deg);\r
+       -o-transform:  rotate3d(0,1,0,360deg);\r
+       -ms-transform:  rotate3d(0,1,0,360deg);\r
+       transform:  rotate3d(0,1,0,360deg);\r
+       -moz-transform:  rotateY(360deg) translate3d(0,0,0);\r
+}\r
+\r
+a.button{\r
+       display:inline-block;\r
+       padding:8px 32px 8px 16px;\r
+       border-radius: 6px;\r
+       font-weight: 600;\r
+       margin:10px 0;\r
+       background-image: url("../images/arrow-button.png");\r
+       background-repeat: no-repeat;\r
+       background-position: 100% 50%;\r
+}\r
+\r
+\r
+#fontsLoader{\r
+       position:absolute;\r
+       bottom:0px;\r
+       right: 0px;\r
+       width:0;\r
+       height:0px;\r
+       overflow:hidden; \r
+}\r
+\r
+/*  Splash screen */\r
+#splash{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+       z-index: 30;\r
+       opacity:0;\r
+}\r
+\r
+#splash .logo{\r
+       position:absolute;\r
+}\r
+\r
+\r
+\r
+@media all and (orientation: portrait) {  \r
+       #ol{display:none;}\r
+       @-ms-viewport { width: 640px; }\r
+}  \r
+\r
+@media all and (orientation: landscape) {  \r
+       #op{display:none;}\r
+       @-ms-viewport { width: 1024px; }\r
+}  \r
+\r
+/* Webfonts*/\r
+@font-face {\r
+    font-family: 'Silkscreen';\r
+    src: url('fonts/slkscr-webfont.woff') format('woff'),\r
+               url('fonts/slkscr-webfont.ttf') format('truetype');\r
+    font-weight: normal;\r
+    font-style: normal;\r
+\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-R-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-R-webfont.ttf') format('truetype');\r
+    font-weight: 400;\r
+    font-style: normal;\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-RI-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-RI-webfont.ttf') format('truetype');\r
+    font-weight: 400;\r
+    font-style: italic;\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-L-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-L-webfont.ttf') format('truetype');\r
+    font-weight:300;\r
+    font-style: normal;\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-LI-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-LI-webfont.ttf') format('truetype');\r
+    font-weight: 300;\r
+    font-style: italic;\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-M-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-M-webfont.ttf') format('truetype');\r
+    font-weight: 600;\r
+    font-style: normal;\r
+}\r
+\r
+@font-face {\r
+    font-family: 'Ubuntu';\r
+    src: url('fonts/Ubuntu-MI-webfont.woff') format('woff'),\r
+               url('fonts/Ubuntu-MI-webfont.ttf') format('truetype');\r
+    font-weight: 600;\r
+    font-style: italic;\r
+}\r
diff --git a/style/fonts/Ubuntu-B-webfont.ttf b/style/fonts/Ubuntu-B-webfont.ttf
new file mode 100644 (file)
index 0000000..c81f83a
Binary files /dev/null and b/style/fonts/Ubuntu-B-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-B-webfont.woff b/style/fonts/Ubuntu-B-webfont.woff
new file mode 100644 (file)
index 0000000..d275286
Binary files /dev/null and b/style/fonts/Ubuntu-B-webfont.woff differ
diff --git a/style/fonts/Ubuntu-BI-webfont.ttf b/style/fonts/Ubuntu-BI-webfont.ttf
new file mode 100644 (file)
index 0000000..4b4217a
Binary files /dev/null and b/style/fonts/Ubuntu-BI-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-BI-webfont.woff b/style/fonts/Ubuntu-BI-webfont.woff
new file mode 100644 (file)
index 0000000..171b64f
Binary files /dev/null and b/style/fonts/Ubuntu-BI-webfont.woff differ
diff --git a/style/fonts/Ubuntu-L-webfont.ttf b/style/fonts/Ubuntu-L-webfont.ttf
new file mode 100644 (file)
index 0000000..186e5a2
Binary files /dev/null and b/style/fonts/Ubuntu-L-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-L-webfont.woff b/style/fonts/Ubuntu-L-webfont.woff
new file mode 100644 (file)
index 0000000..7c2af3b
Binary files /dev/null and b/style/fonts/Ubuntu-L-webfont.woff differ
diff --git a/style/fonts/Ubuntu-LI-webfont.ttf b/style/fonts/Ubuntu-LI-webfont.ttf
new file mode 100644 (file)
index 0000000..177e956
Binary files /dev/null and b/style/fonts/Ubuntu-LI-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-LI-webfont.woff b/style/fonts/Ubuntu-LI-webfont.woff
new file mode 100644 (file)
index 0000000..70ee056
Binary files /dev/null and b/style/fonts/Ubuntu-LI-webfont.woff differ
diff --git a/style/fonts/Ubuntu-M-webfont.ttf b/style/fonts/Ubuntu-M-webfont.ttf
new file mode 100644 (file)
index 0000000..5c4967c
Binary files /dev/null and b/style/fonts/Ubuntu-M-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-M-webfont.woff b/style/fonts/Ubuntu-M-webfont.woff
new file mode 100644 (file)
index 0000000..72ce7ad
Binary files /dev/null and b/style/fonts/Ubuntu-M-webfont.woff differ
diff --git a/style/fonts/Ubuntu-MI-webfont.ttf b/style/fonts/Ubuntu-MI-webfont.ttf
new file mode 100644 (file)
index 0000000..2dab3b7
Binary files /dev/null and b/style/fonts/Ubuntu-MI-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-MI-webfont.woff b/style/fonts/Ubuntu-MI-webfont.woff
new file mode 100644 (file)
index 0000000..c1f6294
Binary files /dev/null and b/style/fonts/Ubuntu-MI-webfont.woff differ
diff --git a/style/fonts/Ubuntu-R-webfont.ttf b/style/fonts/Ubuntu-R-webfont.ttf
new file mode 100644 (file)
index 0000000..147d98e
Binary files /dev/null and b/style/fonts/Ubuntu-R-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-R-webfont.woff b/style/fonts/Ubuntu-R-webfont.woff
new file mode 100644 (file)
index 0000000..cb3dc6f
Binary files /dev/null and b/style/fonts/Ubuntu-R-webfont.woff differ
diff --git a/style/fonts/Ubuntu-RI-webfont.ttf b/style/fonts/Ubuntu-RI-webfont.ttf
new file mode 100644 (file)
index 0000000..92e05d8
Binary files /dev/null and b/style/fonts/Ubuntu-RI-webfont.ttf differ
diff --git a/style/fonts/Ubuntu-RI-webfont.woff b/style/fonts/Ubuntu-RI-webfont.woff
new file mode 100644 (file)
index 0000000..4f09e67
Binary files /dev/null and b/style/fonts/Ubuntu-RI-webfont.woff differ
diff --git a/style/fonts/slkscr-webfont.ttf b/style/fonts/slkscr-webfont.ttf
new file mode 100644 (file)
index 0000000..1f4550d
Binary files /dev/null and b/style/fonts/slkscr-webfont.ttf differ
diff --git a/style/fonts/slkscr-webfont.woff b/style/fonts/slkscr-webfont.woff
new file mode 100644 (file)
index 0000000..6f18403
Binary files /dev/null and b/style/fonts/slkscr-webfont.woff differ
diff --git a/style/widget.css b/style/widget.css
new file mode 100644 (file)
index 0000000..4105d7e
--- /dev/null
@@ -0,0 +1,161 @@
+*{margin:0;padding:0}\r
+\r
+body{\r
+       overflow: hidden;\r
+       cursor:pointer;\r
+}\r
+\r
+#container{\r
+       overflow:hidden;\r
+       display:none;\r
+}\r
+\r
+#widget{\r
+       position:absolute;\r
+       top:0px; \r
+       left:0px;\r
+}\r
\r
+.p{\r
+       display:none;\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+\r
+.p>img{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+\r
+.p .shade img{\r
+       position: absolute;\r
+       top:0px;\r
+}\r
+\r
+.p.left .shade img{\r
+       right:0px;\r
+}\r
+\r
+.p.right .shade img{\r
+       left:0px;\r
+}\r
+\r
+.shade img{\r
+       display:block;\r
+       position:relative;\r
+       z-index:4;\r
+}\r
+\r
+#currentDoublePage,#nextDoublePage{\r
+       position:absolute;\r
+       top:0px;\r
+       left:0px;\r
+}\r
+\r
+#nextDoublePage{\r
+       z-index:3;\r
+}\r
+\r
+#widget{\r
+       perspective: 5000px;\r
+       -moz-perspective:5000px;\r
+       -webkit-perspective:5000px;\r
+       -o-perspective:5000px;\r
+       -ms-perspective:5000px;\r
+\r
+\r
+       perspective-origin: 50% 75%;\r
+       -moz-perspective-origin:50% 75%;\r
+       -webkit-perspective-origin:50% 75%;\r
+       -ms-perspective-origin:50% 75%;\r
+       -o-perspective-origin:50% 75%;\r
+}\r
+\r
+#nextDoublePage._3d{\r
+       overflow: visible;\r
+       z-index:100;\r
+\r
+       transition: all 1s ease-out;\r
+       -moz-transition: all 1s ease-out;\r
+       -webkit-transition: all 1s ease-out;\r
+       -o-transition: all 1s ease-out;\r
+       -ms-transition: all 1s ease-out;\r
+\r
+       transform-style: preserve-3d;\r
+       -moz-transform-style:preserve-3d;\r
+       -webkit-transform-style:preserve-3d;\r
+       -o-transform-style:preserve-3d;\r
+       -ms-transform-style:preserve-3d;\r
+}\r
+\r
+#nextDoublePage._3d .p{\r
+       backface-visibility: hidden;\r
+       -moz-backface-visibility:hidden;\r
+       -webkit-backface-visibility:hidden;\r
+       -o-backface-visibility:hidden;\r
+       -ms-backface-visibility:hidden; \r
+\r
+       left:0px !important;\r
+}\r
+\r
+#nextDoublePage._3d .right{\r
+       transform:  rotate3d(0,1,0,0deg);\r
+       -moz-transform:  rotateY(0deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,0deg);\r
+       -o-transform:  rotate3d(0,1,0,0deg);\r
+       -ms-transform:  rotate3d(0,1,0,0deg);\r
+}\r
+\r
+#nextDoublePage._3d .left{\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+}\r
+\r
+#nextDoublePage._3d.nextstart{\r
+       transform:  rotate3d(0,1,0,360deg);\r
+       -moz-transform:  rotateY(360deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,360deg);\r
+       -o-transform:  rotate3d(0,1,0,360deg);\r
+       -ms-transform:  rotate3d(0,1,0,360deg);\r
+\r
+       transform-origin: 0 0;\r
+       -moz-transform-origin: 0 0;\r
+       -webkit-transform-origin: 0 0;\r
+       -o-transform-origin: 0 0;\r
+       -ms-transform-origin: 0 0;\r
+}\r
+\r
+#nextDoublePage._3d.nextend{\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+}\r
+\r
+#nextDoublePage._3d.prevstart{\r
+       transform:  rotate3d(0,1,0,180deg);\r
+       -moz-transform:  rotateY(180deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,180deg);\r
+       -o-transform:  rotate3d(0,1,0,180deg);\r
+       -ms-transform:  rotate3d(0,1,0,180deg);\r
+\r
+       transform-origin: 0 0;\r
+       -moz-transform-origin: 0 0;\r
+       -webkit-transform-origin: 0 0;\r
+       -o-transform-origin: 0 0;\r
+       -ms-transform-origin: 0 0;\r
+}\r
+\r
+#nextDoublePage._3d.prevend{\r
+       transform:  rotate3d(0,1,0,360deg);\r
+       -moz-transform:  rotateY(360deg) translate3d(0,0,0);\r
+       -webkit-transform:  rotate3d(0,1,0,360deg);\r
+       -o-transform:  rotate3d(0,1,0,360deg);\r
+       -ms-transform:  rotate3d(0,1,0,360deg);\r
+}
\ No newline at end of file
diff --git a/swf/_src/Fluidbook Video Player.as3proj b/swf/_src/Fluidbook Video Player.as3proj
new file mode 100644 (file)
index 0000000..397537b
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<project version="2">\r
+  <!-- Output SWF options -->\r
+  <output>\r
+    <movie outputType="Application" />\r
+    <movie input="" />\r
+    <movie path="..\..\..\cubeExtranet\swf\video.swf" />\r
+    <movie fps="30" />\r
+    <movie width="800" />\r
+    <movie height="600" />\r
+    <movie version="10" />\r
+    <movie minorVersion="0" />\r
+    <movie platform="Flash Player" />\r
+    <movie background="#FFFFFF" />\r
+  </output>\r
+  <!-- Other classes to be compiled into your SWF -->\r
+  <classpaths>\r
+    <class path="." />\r
+  </classpaths>\r
+  <!-- Build options -->\r
+  <build>\r
+    <option accessible="False" />\r
+    <option allowSourcePathOverlap="False" />\r
+    <option benchmark="False" />\r
+    <option es="False" />\r
+    <option locale="" />\r
+    <option loadConfig="" />\r
+    <option optimize="True" />\r
+    <option omitTraces="True" />\r
+    <option showActionScriptWarnings="True" />\r
+    <option showBindingWarnings="True" />\r
+    <option showInvalidCSS="True" />\r
+    <option showDeprecationWarnings="True" />\r
+    <option showUnusedTypeSelectorWarnings="True" />\r
+    <option strict="True" />\r
+    <option useNetwork="True" />\r
+    <option useResourceBundleMetadata="True" />\r
+    <option warnings="True" />\r
+    <option verboseStackTraces="False" />\r
+    <option linkReport="" />\r
+    <option loadExterns="" />\r
+    <option staticLinkRSL="True" />\r
+    <option additional="" />\r
+    <option compilerConstants="" />\r
+    <option minorVersion="" />\r
+  </build>\r
+  <!-- SWC Include Libraries -->\r
+  <includeLibraries>\r
+    <!-- example: <element path="..." /> -->\r
+  </includeLibraries>\r
+  <!-- SWC Libraries -->\r
+  <libraryPaths>\r
+    <element path="lib\fluidbook3dLibrary.swc" />\r
+  </libraryPaths>\r
+  <!-- External Libraries -->\r
+  <externalLibraryPaths>\r
+    <!-- example: <element path="..." /> -->\r
+  </externalLibraryPaths>\r
+  <!-- Runtime Shared Libraries -->\r
+  <rslPaths>\r
+    <!-- example: <element path="..." /> -->\r
+  </rslPaths>\r
+  <!-- Intrinsic Libraries -->\r
+  <intrinsics>\r
+    <!-- example: <element path="..." /> -->\r
+  </intrinsics>\r
+  <!-- Assets to embed into the output SWF -->\r
+  <library>\r
+    <!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->\r
+  </library>\r
+  <!-- Class files to compile (other referenced classes will automatically be included) -->\r
+  <compileTargets>\r
+    <compile path="com\fluidbook\video\Main.as" />\r
+  </compileTargets>\r
+  <!-- Paths to exclude from the Project Explorer tree -->\r
+  <hiddenPaths>\r
+    <!-- example: <hidden path="..." /> -->\r
+  </hiddenPaths>\r
+  <!-- Executed before build -->\r
+  <preBuildCommand />\r
+  <!-- Executed after build -->\r
+  <postBuildCommand alwaysRun="False" />\r
+  <!-- Other project options -->\r
+  <options>\r
+    <option showHiddenPaths="False" />\r
+    <option testMovie="Default" />\r
+  </options>\r
+  <!-- Plugin storage -->\r
+  <storage />\r
+</project>
\ No newline at end of file
diff --git a/web.config b/web.config
new file mode 100644 (file)
index 0000000..4289910
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<configuration>
+       <system.webServer>
+               <staticContent>
+      <!-- Remove extension from mapping if exists -->
+                       <remove fileExtension=".ogm"/>
+                       <remove fileExtension=".ogv"/>
+                       <remove fileExtension=".ogg"/>
+                       <remove fileExtension=".mp4"/>
+                       <remove fileExtension=".webm"/>
+                       <remove fileExtension=".svg"/>
+                       <remove fileExtension=".svgz"/>
+                       <remove fileExtension=".json"/>
+                       <remove fileExtension=".woff"/>
+                       <remove fileExtension=".eot"/>
+                       <remove fileExtension=".otf"/>
+                       <remove fileExtension=".ttf"/>
+                       <remove fileExtension=".appcache" />
+      <!-- Add extensions for HTML5 contents -->
+                       <mimeMap fileExtension=".ogm" mimeType="video/ogg"/>
+                       <mimeMap fileExtension=".ogv" mimeType="video/ogg"/>
+                       <mimeMap fileExtension=".ogg" mimeType="video/ogg"/>
+                       <mimeMap fileExtension=".mp4" mimeType="video/mp4"/>
+                       <mimeMap fileExtension=".webm" mimeType="video/webm"/>
+                       <mimeMap fileExtension=".svg" mimeType="image/svg+xml"/>
+                       <mimeMap fileExtension=".svgz" mimeType="image/svg+xml"/>
+                       <mimeMap fileExtension=".json" mimeType="application/json"/>
+                       <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject"/>
+                       <mimeMap fileExtension=".otf" mimeType="application/octet-stream"/>
+                       <mimeMap fileExtension=".ttf" mimeType="application/octet-stream"/>
+                       <mimeMap fileExtension=".woff" mimeType="application/x-font-woff"/>
+                       <mimeMap fileExtension=".appcache" mimeType="text/cache-manifest"/>
+               </staticContent>
+       </system.webServer>
+</configuration>
diff --git a/widget.html b/widget.html
new file mode 100644 (file)
index 0000000..6fb318c
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>\r
+<html>\r
+       <head>\r
+               <title><!-- $titre --></title>\r
+               <meta charset="utf-8">\r
+               <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=IE8">\r
+               <!-- $style -->\r
+               <!-- $script -->\r
+       </head>\r
+       <body>\r
+               <div id="container">\r
+                       <div id="widget">\r
+\r
+                       </div>\r
+               </div>\r
+       </body>\r
+</html>
\ No newline at end of file