--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/static/iconolab/js/dist/bundle.js Tue May 31 17:46:32 2016 +0200
@@ -0,0 +1,18317 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var cutout = __webpack_require__(1);
+
+ /* expose jQuery */
+ var test = __webpack_require__(4);
+
+ var api = {
+ initCutoutComponent: function (config) {
+ return cutout.init(config);
+ },
+ testComponent: function () {}
+ };
+
+ module.exports = api;
+
+ iconolab = api;
+
+ console.log(test);
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+ var Snap = __webpack_require__(2);
+
+ /* custom plugin */
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var elproto = Element.prototype;
+
+ elproto.toBack = function () {
+ this.prependTo(this.paper);
+ };
+
+ elproto.toFront = function () {
+ this.appendTo(this.paper);
+ };
+ });
+
+ var paper;
+ var pointData = [];
+ var startPoint = null;
+ var drawing_path = null;
+ var PATH_COLOR = "#ff00ff";
+ var SELECTED_COLOR = "#ffff00";
+ var FIRST_NODE_COLOR = "#FF0000";
+ var HANDLE_SIZE = 6;
+ var isDragged = false;
+ var enablePoint = true;
+ var pathIsClosed = false;
+ var ENABLE_NEW_NODE = true;
+
+ var getId = (function () {
+ var cpt = 0;
+ var defautPrefix = "item_";
+ return function (prefix) {
+ prefix = (typeof prefix === 'string') ? prefix : defautPrefix;
+ cpt = cpt + 1;
+ return prefix + cpt;
+ }
+ }());
+
+ var pathToPoint = function (path) {
+ if (typeof path === "string") { return false; }
+ };
+
+ //transform point to path
+ var updatePath = function (paper, updateCallback) {
+ var path = "M";
+
+ if (pointData.length <= 1) {
+ return;
+ }
+
+ /*if (pathIsClosed) {
+ pointData.pop();
+ }*/
+
+ path += pointData[0].x + ',' + pointData[0].y;
+
+ for (var i=0; i < pointData.length; i++) {
+ if (i == 0) continue;
+
+ var pointInfos = pointData[i];
+ lPath = "L" + pointInfos.x + "," + pointInfos.y;
+ path += " " + lPath;
+ }
+
+ path += (pathIsClosed) ? " Z": "";
+
+ console.log("stra", updateCallback);
+
+ if (typeof updateCallback === 'function' && pathIsClosed) {
+ updateCallback();
+ }
+
+ /* remove prev path */
+ if (drawing_path) {
+ drawing_path.remove();
+ }
+
+ drawing_path = paper.path(path);
+
+ drawing_path.attr({
+ stroke: "red",
+ opacity: 0.6
+ });
+
+ /* bring all handler to front */
+ pointData.map(function (point) {
+ if (point.handler) {
+ point.handler.toFront();
+ }
+ });
+
+ console.log("radical...", path);
+ console.log({isDragged: isDragged, enablePoint: enablePoint, pathIsClosed: pathIsClosed});
+ };
+
+ onClosePath = function () {
+ ENABLE_NEW_NODE = false;
+ /* Group path an handler - add remove_btn */
+ };
+
+ onClickOnHandler = function (point, p, e) {
+ //close path
+ console.log("new click handler ...");
+ if (point.isFirst && pointData.length > 2) {
+ pathIsClosed = true;
+ }
+ };
+
+ var updatePointPosition = function (newPoint, x, y) {
+ var index = pointData.indexOf(newPoint);
+ if (index !== -1) {
+ pointData[index].x = x;
+ pointData[index].y = y;
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ var clearPreviousPath = function () {
+ drawing_path.remove();
+ };
+
+ var onMoveHandler = function (dx, dy, posX, posY, e) {
+ console.log("in onMoveHandler...");
+ isDragged = true;
+ /* update point then update the view */
+ var transformValue = this.data('origTransform') + (this.data('origTransform') ? "T" : "t") + [dx, dy];
+ this.attr({ transform: transformValue});
+ var boxSize = this.getBBox();
+
+ var wasUpdated = updatePointPosition(this.data('point'), boxSize.x + (HANDLE_SIZE / 2) , boxSize.y + (HANDLE_SIZE / 2));
+
+ if (wasUpdated) {
+ updatePath(this.paper);
+ }
+ }
+
+ var bindHandlerEvent = function (point, p) {
+ point.handler.click(onClickOnHandler.bind(this, point, p));
+ /* -- handler -- */
+ point.handler.hover(function () {
+ point.handler.attr({fill: 'yellow'});
+ }, function () {
+ var fillColor = point.isFirst ? FIRST_NODE_COLOR : "";
+ point.handler.attr({fill: fillColor});
+ });
+
+ point.handler.drag(onMoveHandler, function () {
+ this.data('origTransform', this.transform().local );
+ }, function () {
+ if (!isDragged) { return true; }
+ isDragged = false;
+ enablePoint = false;
+ });
+ }
+
+ var createPointHandler = function (p, point) {
+
+ var handleX = point.x - HANDLE_SIZE/2;
+ var handleY = point.y - HANDLE_SIZE/2;
+
+ handler = p.rect(handleX, handleY, HANDLE_SIZE, HANDLE_SIZE);
+
+ point.handler = handler;
+ point.handler.data('point', point);
+ if (pointData.length === 0) {
+ point.isFirst = true;
+ }
+
+ bindHandlerEvent(point, p);
+ point.handler.attr({
+ fill: (pointData.length === 0) ? FIRST_NODE_COLOR : "",
+ opacity: 0.9,
+ stroke: PATH_COLOR
+ });
+
+ return point;
+ }
+
+ var setPath = function () {
+
+ }
+
+ //create paper
+ var createPoint = function (paper, x, y, pointData) {
+
+ console.log("... Inside createPoint ... ");
+ var point = {x:x, y:y, id: getId()};
+
+ /**/
+ if (pathIsClosed) {
+ updatePath(paper, onClosePath);
+ return;
+ }
+
+ if (!enablePoint) {
+ enablePoint = true;
+ return false;
+ }
+
+ point = createPointHandler(paper, point);
+ pointData.push(point);
+ updatePath(paper);
+ };
+
+
+ module.exports = {
+
+ init: function(config) {
+
+ /* strange ... */
+ var mainImage = jQuery(config.imageId).find('img').eq(0);
+ var cutCanvas = jQuery(config.imageId).find('.cut-canvas').eq(0);
+ var path = jQuery(config.imageId).find('.image-path').eq(0);
+
+ if (path.length) {
+ jQuery(cutCanvas).append(path);
+ }
+
+ cutCanvas.css({
+ position: 'absolute',
+ top: '0px',
+ left: '0px',
+ width: mainImage.width(),
+ height: mainImage.height()
+ });
+
+ paper = new Snap(cutCanvas.get(0));
+ /* show path, init the drawing module*/
+ paper.click( function(e) {
+ if (!ENABLE_NEW_NODE) { return true; }
+ createPoint(paper, e.offsetX, e.offsetY, pointData);
+ });
+ },
+ };
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_LOCAL_MODULE_0__;/*** IMPORTS FROM imports-loader ***/
+ (function() {
+ var fix = module.exports=0;
+
+ // Snap.svg 0.4.0
+ //
+ // Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ //
+ // build: 2015-04-07
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ // ┌────────────────────────────────────────────────────────────┐ \\
+ // │ Eve 0.4.2 - JavaScript Events Library │ \\
+ // ├────────────────────────────────────────────────────────────┤ \\
+ // │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
+ // └────────────────────────────────────────────────────────────┘ \\
+
+ (function (glob) {
+ var version = "0.4.2",
+ has = "hasOwnProperty",
+ separator = /[\.\/]/,
+ comaseparator = /\s*,\s*/,
+ wildcard = "*",
+ fun = function () {},
+ numsort = function (a, b) {
+ return a - b;
+ },
+ current_event,
+ stop,
+ events = {n: {}},
+ firstDefined = function () {
+ for (var i = 0, ii = this.length; i < ii; i++) {
+ if (typeof this[i] != "undefined") {
+ return this[i];
+ }
+ }
+ },
+ lastDefined = function () {
+ var i = this.length;
+ while (--i) {
+ if (typeof this[i] != "undefined") {
+ return this[i];
+ }
+ }
+ },
+ /*\
+ * eve
+ [ method ]
+
+ * Fires event with given `name`, given scope and other parameters.
+
+ > Arguments
+
+ - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
+ - scope (object) context for the event handlers
+ - varargs (...) the rest of arguments will be sent to event handlers
+
+ = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value.
+ \*/
+ eve = function (name, scope) {
+ name = String(name);
+ var e = events,
+ oldstop = stop,
+ args = Array.prototype.slice.call(arguments, 2),
+ listeners = eve.listeners(name),
+ z = 0,
+ f = false,
+ l,
+ indexed = [],
+ queue = {},
+ out = [],
+ ce = current_event,
+ errors = [];
+ out.firstDefined = firstDefined;
+ out.lastDefined = lastDefined;
+ current_event = name;
+ stop = 0;
+ for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
+ indexed.push(listeners[i].zIndex);
+ if (listeners[i].zIndex < 0) {
+ queue[listeners[i].zIndex] = listeners[i];
+ }
+ }
+ indexed.sort(numsort);
+ while (indexed[z] < 0) {
+ l = queue[indexed[z++]];
+ out.push(l.apply(scope, args));
+ if (stop) {
+ stop = oldstop;
+ return out;
+ }
+ }
+ for (i = 0; i < ii; i++) {
+ l = listeners[i];
+ if ("zIndex" in l) {
+ if (l.zIndex == indexed[z]) {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ do {
+ z++;
+ l = queue[indexed[z]];
+ l && out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ } while (l)
+ } else {
+ queue[l.zIndex] = l;
+ }
+ } else {
+ out.push(l.apply(scope, args));
+ if (stop) {
+ break;
+ }
+ }
+ }
+ stop = oldstop;
+ current_event = ce;
+ return out;
+ };
+ // Undocumented. Debug only.
+ eve._events = events;
+ /*\
+ * eve.listeners
+ [ method ]
+
+ * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
+
+ > Arguments
+
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated
+
+ = (array) array of event handlers
+ \*/
+ eve.listeners = function (name) {
+ var names = name.split(separator),
+ e = events,
+ item,
+ items,
+ k,
+ i,
+ ii,
+ j,
+ jj,
+ nes,
+ es = [e],
+ out = [];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ nes = [];
+ for (j = 0, jj = es.length; j < jj; j++) {
+ e = es[j].n;
+ items = [e[names[i]], e[wildcard]];
+ k = 2;
+ while (k--) {
+ item = items[k];
+ if (item) {
+ nes.push(item);
+ out = out.concat(item.f || []);
+ }
+ }
+ }
+ es = nes;
+ }
+ return out;
+ };
+
+ /*\
+ * eve.on
+ [ method ]
+ **
+ * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
+ | eve.on("*.under.*", f);
+ | eve("mouse.under.floor"); // triggers f
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
+ > Example:
+ | eve.on("mouse", eatIt)(2);
+ | eve.on("mouse", scream);
+ | eve.on("mouse", catchIt)(1);
+ * This will ensure that `catchIt` function will be called before `eatIt`.
+ *
+ * If you want to put your handler before non-indexed handlers, specify a negative value.
+ * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
+ \*/
+ eve.on = function (name, f) {
+ name = String(name);
+ if (typeof f != "function") {
+ return function () {};
+ }
+ var names = name.split(comaseparator);
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ (function (name) {
+ var names = name.split(separator),
+ e = events,
+ exist;
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ e = e.n;
+ e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
+ }
+ e.f = e.f || [];
+ for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
+ exist = true;
+ break;
+ }
+ !exist && e.f.push(f);
+ }(names[i]));
+ }
+ return function (zIndex) {
+ if (+zIndex == +zIndex) {
+ f.zIndex = +zIndex;
+ }
+ };
+ };
+ /*\
+ * eve.f
+ [ method ]
+ **
+ * Returns function that will fire given event with optional arguments.
+ * Arguments that will be passed to the result function will be also
+ * concated to the list of final arguments.
+ | el.onclick = eve.f("click", 1, 2);
+ | eve.on("click", function (a, b, c) {
+ | console.log(a, b, c); // 1, 2, [event object]
+ | });
+ > Arguments
+ - event (string) event name
+ - varargs (…) and any other arguments
+ = (function) possible event handler function
+ \*/
+ eve.f = function (event) {
+ var attrs = [].slice.call(arguments, 1);
+ return function () {
+ eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
+ };
+ };
+ /*\
+ * eve.stop
+ [ method ]
+ **
+ * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
+ \*/
+ eve.stop = function () {
+ stop = 1;
+ };
+ /*\
+ * eve.nt
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ > Arguments
+ **
+ - subname (string) #optional subname of the event
+ **
+ = (string) name of the event, if `subname` is not specified
+ * or
+ = (boolean) `true`, if current event’s name contains `subname`
+ \*/
+ eve.nt = function (subname) {
+ if (subname) {
+ return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
+ }
+ return current_event;
+ };
+ /*\
+ * eve.nts
+ [ method ]
+ **
+ * Could be used inside event handler to figure out actual name of the event.
+ **
+ **
+ = (array) names of the event
+ \*/
+ eve.nts = function () {
+ return current_event.split(separator);
+ };
+ /*\
+ * eve.off
+ [ method ]
+ **
+ * Removes given function from the list of event listeners assigned to given name.
+ * If no arguments specified all the events will be cleared.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ \*/
+ /*\
+ * eve.unbind
+ [ method ]
+ **
+ * See @eve.off
+ \*/
+ eve.off = eve.unbind = function (name, f) {
+ if (!name) {
+ eve._events = events = {n: {}};
+ return;
+ }
+ var names = name.split(comaseparator);
+ if (names.length > 1) {
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ eve.off(names[i], f);
+ }
+ return;
+ }
+ names = name.split(separator);
+ var e,
+ key,
+ splice,
+ i, ii, j, jj,
+ cur = [events];
+ for (i = 0, ii = names.length; i < ii; i++) {
+ for (j = 0; j < cur.length; j += splice.length - 2) {
+ splice = [j, 1];
+ e = cur[j].n;
+ if (names[i] != wildcard) {
+ if (e[names[i]]) {
+ splice.push(e[names[i]]);
+ }
+ } else {
+ for (key in e) if (e[has](key)) {
+ splice.push(e[key]);
+ }
+ }
+ cur.splice.apply(cur, splice);
+ }
+ }
+ for (i = 0, ii = cur.length; i < ii; i++) {
+ e = cur[i];
+ while (e.n) {
+ if (f) {
+ if (e.f) {
+ for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
+ e.f.splice(j, 1);
+ break;
+ }
+ !e.f.length && delete e.f;
+ }
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ var funcs = e.n[key].f;
+ for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
+ funcs.splice(j, 1);
+ break;
+ }
+ !funcs.length && delete e.n[key].f;
+ }
+ } else {
+ delete e.f;
+ for (key in e.n) if (e.n[has](key) && e.n[key].f) {
+ delete e.n[key].f;
+ }
+ }
+ e = e.n;
+ }
+ }
+ };
+ /*\
+ * eve.once
+ [ method ]
+ **
+ * Binds given event handler with a given name to only run once then unbind itself.
+ | eve.once("login", f);
+ | eve("login"); // triggers f
+ | eve("login"); // no listeners
+ * Use @eve to trigger the listener.
+ **
+ > Arguments
+ **
+ - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
+ - f (function) event handler function
+ **
+ = (function) same return function as @eve.on
+ \*/
+ eve.once = function (name, f) {
+ var f2 = function () {
+ eve.unbind(name, f2);
+ return f.apply(this, arguments);
+ };
+ return eve.on(name, f2);
+ };
+ /*\
+ * eve.version
+ [ property (string) ]
+ **
+ * Current version of the library.
+ \*/
+ eve.version = version;
+ eve.toString = function () {
+ return "You are running Eve " + version;
+ };
+ (typeof module != "undefined" && module.exports) ? (module.exports = eve) : ( true ? (!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_LOCAL_MODULE_0__ = (function() { return eve; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)))) : (glob.eve = eve));
+ })(this);
+
+ (function (glob, factory) {
+ // AMD support
+ if (true) {
+ // Define as an anonymous module
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__WEBPACK_LOCAL_MODULE_0__], __WEBPACK_AMD_DEFINE_RESULT__ = function (eve) {
+ return factory(glob, eve);
+ }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+ } else if (typeof exports != 'undefined') {
+ // Next for Node.js or CommonJS
+ var eve = require('eve');
+ module.exports = factory(glob, eve);
+ } else {
+ // Browser globals (glob is window)
+ // Snap adds itself to window
+ factory(glob, glob.eve);
+ }
+ }(window || this, function (window, eve) {
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ var mina = (function (eve) {
+ var animations = {},
+ requestAnimFrame = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function (callback) {
+ setTimeout(callback, 16);
+ },
+ isArray = Array.isArray || function (a) {
+ return a instanceof Array ||
+ Object.prototype.toString.call(a) == "[object Array]";
+ },
+ idgen = 0,
+ idprefix = "M" + (+new Date).toString(36),
+ ID = function () {
+ return idprefix + (idgen++).toString(36);
+ },
+ diff = function (a, b, A, B) {
+ if (isArray(a)) {
+ res = [];
+ for (var i = 0, ii = a.length; i < ii; i++) {
+ res[i] = diff(a[i], b, A[i], B);
+ }
+ return res;
+ }
+ var dif = (A - a) / (B - b);
+ return function (bb) {
+ return a + dif * (bb - b);
+ };
+ },
+ timer = Date.now || function () {
+ return +new Date;
+ },
+ sta = function (val) {
+ var a = this;
+ if (val == null) {
+ return a.s;
+ }
+ var ds = a.s - val;
+ a.b += a.dur * ds;
+ a.B += a.dur * ds;
+ a.s = val;
+ },
+ speed = function (val) {
+ var a = this;
+ if (val == null) {
+ return a.spd;
+ }
+ a.spd = val;
+ },
+ duration = function (val) {
+ var a = this;
+ if (val == null) {
+ return a.dur;
+ }
+ a.s = a.s * val / a.dur;
+ a.dur = val;
+ },
+ stopit = function () {
+ var a = this;
+ delete animations[a.id];
+ a.update();
+ eve("mina.stop." + a.id, a);
+ },
+ pause = function () {
+ var a = this;
+ if (a.pdif) {
+ return;
+ }
+ delete animations[a.id];
+ a.update();
+ a.pdif = a.get() - a.b;
+ },
+ resume = function () {
+ var a = this;
+ if (!a.pdif) {
+ return;
+ }
+ a.b = a.get() - a.pdif;
+ delete a.pdif;
+ animations[a.id] = a;
+ },
+ update = function () {
+ var a = this,
+ res;
+ if (isArray(a.start)) {
+ res = [];
+ for (var j = 0, jj = a.start.length; j < jj; j++) {
+ res[j] = +a.start[j] +
+ (a.end[j] - a.start[j]) * a.easing(a.s);
+ }
+ } else {
+ res = +a.start + (a.end - a.start) * a.easing(a.s);
+ }
+ a.set(res);
+ },
+ frame = function () {
+ var len = 0;
+ for (var i in animations) if (animations.hasOwnProperty(i)) {
+ var a = animations[i],
+ b = a.get(),
+ res;
+ len++;
+ a.s = (b - a.b) / (a.dur / a.spd);
+ if (a.s >= 1) {
+ delete animations[i];
+ a.s = 1;
+ len--;
+ (function (a) {
+ setTimeout(function () {
+ eve("mina.finish." + a.id, a);
+ });
+ }(a));
+ }
+ a.update();
+ }
+ len && requestAnimFrame(frame);
+ },
+ /*\
+ * mina
+ [ method ]
+ **
+ * Generic animation of numbers
+ **
+ - a (number) start _slave_ number
+ - A (number) end _slave_ number
+ - b (number) start _master_ number (start time in general case)
+ - B (number) end _master_ number (end time in gereal case)
+ - get (function) getter of _master_ number (see @mina.time)
+ - set (function) setter of _slave_ number
+ - easing (function) #optional easing function, default is @mina.linear
+ = (object) animation descriptor
+ o {
+ o id (string) animation id,
+ o start (number) start _slave_ number,
+ o end (number) end _slave_ number,
+ o b (number) start _master_ number,
+ o s (number) animation status (0..1),
+ o dur (number) animation duration,
+ o spd (number) animation speed,
+ o get (function) getter of _master_ number (see @mina.time),
+ o set (function) setter of _slave_ number,
+ o easing (function) easing function, default is @mina.linear,
+ o status (function) status getter/setter,
+ o speed (function) speed getter/setter,
+ o duration (function) duration getter/setter,
+ o stop (function) animation stopper
+ o pause (function) pauses the animation
+ o resume (function) resumes the animation
+ o update (function) calles setter with the right value of the animation
+ o }
+ \*/
+ mina = function (a, A, b, B, get, set, easing) {
+ var anim = {
+ id: ID(),
+ start: a,
+ end: A,
+ b: b,
+ s: 0,
+ dur: B - b,
+ spd: 1,
+ get: get,
+ set: set,
+ easing: easing || mina.linear,
+ status: sta,
+ speed: speed,
+ duration: duration,
+ stop: stopit,
+ pause: pause,
+ resume: resume,
+ update: update
+ };
+ animations[anim.id] = anim;
+ var len = 0, i;
+ for (i in animations) if (animations.hasOwnProperty(i)) {
+ len++;
+ if (len == 2) {
+ break;
+ }
+ }
+ len == 1 && requestAnimFrame(frame);
+ return anim;
+ };
+ /*\
+ * mina.time
+ [ method ]
+ **
+ * Returns the current time. Equivalent to:
+ | function () {
+ | return (new Date).getTime();
+ | }
+ \*/
+ mina.time = timer;
+ /*\
+ * mina.getById
+ [ method ]
+ **
+ * Returns an animation by its id
+ - id (string) animation's id
+ = (object) See @mina
+ \*/
+ mina.getById = function (id) {
+ return animations[id] || null;
+ };
+
+ /*\
+ * mina.linear
+ [ method ]
+ **
+ * Default linear easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.linear = function (n) {
+ return n;
+ };
+ /*\
+ * mina.easeout
+ [ method ]
+ **
+ * Easeout easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.easeout = function (n) {
+ return Math.pow(n, 1.7);
+ };
+ /*\
+ * mina.easein
+ [ method ]
+ **
+ * Easein easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.easein = function (n) {
+ return Math.pow(n, .48);
+ };
+ /*\
+ * mina.easeinout
+ [ method ]
+ **
+ * Easeinout easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.easeinout = function (n) {
+ if (n == 1) {
+ return 1;
+ }
+ if (n == 0) {
+ return 0;
+ }
+ var q = .48 - n / 1.04,
+ Q = Math.sqrt(.1734 + q * q),
+ x = Q - q,
+ X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1),
+ y = -Q - q,
+ Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1),
+ t = X + Y + .5;
+ return (1 - t) * 3 * t * t + t * t * t;
+ };
+ /*\
+ * mina.backin
+ [ method ]
+ **
+ * Backin easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.backin = function (n) {
+ if (n == 1) {
+ return 1;
+ }
+ var s = 1.70158;
+ return n * n * ((s + 1) * n - s);
+ };
+ /*\
+ * mina.backout
+ [ method ]
+ **
+ * Backout easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.backout = function (n) {
+ if (n == 0) {
+ return 0;
+ }
+ n = n - 1;
+ var s = 1.70158;
+ return n * n * ((s + 1) * n + s) + 1;
+ };
+ /*\
+ * mina.elastic
+ [ method ]
+ **
+ * Elastic easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.elastic = function (n) {
+ if (n == !!n) {
+ return n;
+ }
+ return Math.pow(2, -10 * n) * Math.sin((n - .075) *
+ (2 * Math.PI) / .3) + 1;
+ };
+ /*\
+ * mina.bounce
+ [ method ]
+ **
+ * Bounce easing
+ - n (number) input 0..1
+ = (number) output 0..1
+ \*/
+ mina.bounce = function (n) {
+ var s = 7.5625,
+ p = 2.75,
+ l;
+ if (n < (1 / p)) {
+ l = s * n * n;
+ } else {
+ if (n < (2 / p)) {
+ n -= (1.5 / p);
+ l = s * n * n + .75;
+ } else {
+ if (n < (2.5 / p)) {
+ n -= (2.25 / p);
+ l = s * n * n + .9375;
+ } else {
+ n -= (2.625 / p);
+ l = s * n * n + .984375;
+ }
+ }
+ }
+ return l;
+ };
+ window.mina = mina;
+ return mina;
+ })(typeof eve == "undefined" ? function () {} : eve);
+ // Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+
+ var Snap = (function(root) {
+ Snap.version = "0.4.0";
+ /*\
+ * Snap
+ [ method ]
+ **
+ * Creates a drawing surface or wraps existing SVG element.
+ **
+ - width (number|string) width of surface
+ - height (number|string) height of surface
+ * or
+ - DOM (SVGElement) element to be wrapped into Snap structure
+ * or
+ - array (array) array of elements (will return set of elements)
+ * or
+ - query (string) CSS query selector
+ = (object) @Element
+ \*/
+ function Snap(w, h) {
+ if (w) {
+ if (w.nodeType) {
+ return wrap(w);
+ }
+ if (is(w, "array") && Snap.set) {
+ return Snap.set.apply(Snap, w);
+ }
+ if (w instanceof Element) {
+ return w;
+ }
+ if (h == null) {
+ w = glob.doc.querySelector(String(w));
+ return wrap(w);
+ }
+ }
+ w = w == null ? "100%" : w;
+ h = h == null ? "100%" : h;
+ return new Paper(w, h);
+ }
+ Snap.toString = function () {
+ return "Snap v" + this.version;
+ };
+ Snap._ = {};
+ var glob = {
+ win: root.window,
+ doc: root.window.document
+ };
+ Snap._.glob = glob;
+ var has = "hasOwnProperty",
+ Str = String,
+ toFloat = parseFloat,
+ toInt = parseInt,
+ math = Math,
+ mmax = math.max,
+ mmin = math.min,
+ abs = math.abs,
+ pow = math.pow,
+ PI = math.PI,
+ round = math.round,
+ E = "",
+ S = " ",
+ objectToString = Object.prototype.toString,
+ ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
+ colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,
+ bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
+ reURLValue = /^url\(#?([^)]+)\)$/,
+ separator = Snap._.separator = /[,\s]+/,
+ whitespace = /[\s]/g,
+ commaSpaces = /[\s]*,[\s]*/,
+ hsrg = {hs: 1, rg: 1},
+ pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
+ tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig,
+ pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig,
+ idgen = 0,
+ idprefix = "S" + (+new Date).toString(36),
+ ID = function (el) {
+ return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36);
+ },
+ xlink = "http://www.w3.org/1999/xlink",
+ xmlns = "http://www.w3.org/2000/svg",
+ hub = {},
+ URL = Snap.url = function (url) {
+ return "url('#" + url + "')";
+ };
+
+ function $(el, attr) {
+ if (attr) {
+ if (el == "#text") {
+ el = glob.doc.createTextNode(attr.text || attr["#text"] || "");
+ }
+ if (el == "#comment") {
+ el = glob.doc.createComment(attr.text || attr["#text"] || "");
+ }
+ if (typeof el == "string") {
+ el = $(el);
+ }
+ if (typeof attr == "string") {
+ if (el.nodeType == 1) {
+ if (attr.substring(0, 6) == "xlink:") {
+ return el.getAttributeNS(xlink, attr.substring(6));
+ }
+ if (attr.substring(0, 4) == "xml:") {
+ return el.getAttributeNS(xmlns, attr.substring(4));
+ }
+ return el.getAttribute(attr);
+ } else if (attr == "text") {
+ return el.nodeValue;
+ } else {
+ return null;
+ }
+ }
+ if (el.nodeType == 1) {
+ for (var key in attr) if (attr[has](key)) {
+ var val = Str(attr[key]);
+ if (val) {
+ if (key.substring(0, 6) == "xlink:") {
+ el.setAttributeNS(xlink, key.substring(6), val);
+ } else if (key.substring(0, 4) == "xml:") {
+ el.setAttributeNS(xmlns, key.substring(4), val);
+ } else {
+ el.setAttribute(key, val);
+ }
+ } else {
+ el.removeAttribute(key);
+ }
+ }
+ } else if ("text" in attr) {
+ el.nodeValue = attr.text;
+ }
+ } else {
+ el = glob.doc.createElementNS(xmlns, el);
+ }
+ return el;
+ }
+ Snap._.$ = $;
+ Snap._.id = ID;
+ function getAttrs(el) {
+ var attrs = el.attributes,
+ name,
+ out = {};
+ for (var i = 0; i < attrs.length; i++) {
+ if (attrs[i].namespaceURI == xlink) {
+ name = "xlink:";
+ } else {
+ name = "";
+ }
+ name += attrs[i].name;
+ out[name] = attrs[i].textContent;
+ }
+ return out;
+ }
+ function is(o, type) {
+ type = Str.prototype.toLowerCase.call(type);
+ if (type == "finite") {
+ return isFinite(o);
+ }
+ if (type == "array" &&
+ (o instanceof Array || Array.isArray && Array.isArray(o))) {
+ return true;
+ }
+ return (type == "null" && o === null) ||
+ (type == typeof o && o !== null) ||
+ (type == "object" && o === Object(o)) ||
+ objectToString.call(o).slice(8, -1).toLowerCase() == type;
+ }
+ /*\
+ * Snap.format
+ [ method ]
+ **
+ * Replaces construction of type `{<name>}` to the corresponding argument
+ **
+ - token (string) string to format
+ - json (object) object which properties are used as a replacement
+ = (string) formatted string
+ > Usage
+ | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z"
+ | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
+ | x: 10,
+ | y: 20,
+ | dim: {
+ | width: 40,
+ | height: 50,
+ | "negative width": -40
+ | }
+ | }));
+ \*/
+ Snap.format = (function () {
+ var tokenRegex = /\{([^\}]+)\}/g,
+ objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
+ replacer = function (all, key, obj) {
+ var res = obj;
+ key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
+ name = name || quotedName;
+ if (res) {
+ if (name in res) {
+ res = res[name];
+ }
+ typeof res == "function" && isFunc && (res = res());
+ }
+ });
+ res = (res == null || res == obj ? all : res) + "";
+ return res;
+ };
+ return function (str, obj) {
+ return Str(str).replace(tokenRegex, function (all, key) {
+ return replacer(all, key, obj);
+ });
+ };
+ })();
+ function clone(obj) {
+ if (typeof obj == "function" || Object(obj) !== obj) {
+ return obj;
+ }
+ var res = new obj.constructor;
+ for (var key in obj) if (obj[has](key)) {
+ res[key] = clone(obj[key]);
+ }
+ return res;
+ }
+ Snap._.clone = clone;
+ function repush(array, item) {
+ for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
+ return array.push(array.splice(i, 1)[0]);
+ }
+ }
+ function cacher(f, scope, postprocessor) {
+ function newf() {
+ var arg = Array.prototype.slice.call(arguments, 0),
+ args = arg.join("\u2400"),
+ cache = newf.cache = newf.cache || {},
+ count = newf.count = newf.count || [];
+ if (cache[has](args)) {
+ repush(count, args);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ count.length >= 1e3 && delete cache[count.shift()];
+ count.push(args);
+ cache[args] = f.apply(scope, arg);
+ return postprocessor ? postprocessor(cache[args]) : cache[args];
+ }
+ return newf;
+ }
+ Snap._.cacher = cacher;
+ function angle(x1, y1, x2, y2, x3, y3) {
+ if (x3 == null) {
+ var x = x1 - x2,
+ y = y1 - y2;
+ if (!x && !y) {
+ return 0;
+ }
+ return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
+ } else {
+ return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3);
+ }
+ }
+ function rad(deg) {
+ return deg % 360 * PI / 180;
+ }
+ function deg(rad) {
+ return rad * 180 / PI % 360;
+ }
+ function x_y() {
+ return this.x + S + this.y;
+ }
+ function x_y_w_h() {
+ return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
+ }
+
+ /*\
+ * Snap.rad
+ [ method ]
+ **
+ * Transform angle to radians
+ - deg (number) angle in degrees
+ = (number) angle in radians
+ \*/
+ Snap.rad = rad;
+ /*\
+ * Snap.deg
+ [ method ]
+ **
+ * Transform angle to degrees
+ - rad (number) angle in radians
+ = (number) angle in degrees
+ \*/
+ Snap.deg = deg;
+ /*\
+ * Snap.sin
+ [ method ]
+ **
+ * Equivalent to `Math.sin()` only works with degrees, not radians.
+ - angle (number) angle in degrees
+ = (number) sin
+ \*/
+ Snap.sin = function (angle) {
+ return math.sin(Snap.rad(angle));
+ };
+ /*\
+ * Snap.tan
+ [ method ]
+ **
+ * Equivalent to `Math.tan()` only works with degrees, not radians.
+ - angle (number) angle in degrees
+ = (number) tan
+ \*/
+ Snap.tan = function (angle) {
+ return math.tan(Snap.rad(angle));
+ };
+ /*\
+ * Snap.cos
+ [ method ]
+ **
+ * Equivalent to `Math.cos()` only works with degrees, not radians.
+ - angle (number) angle in degrees
+ = (number) cos
+ \*/
+ Snap.cos = function (angle) {
+ return math.cos(Snap.rad(angle));
+ };
+ /*\
+ * Snap.asin
+ [ method ]
+ **
+ * Equivalent to `Math.asin()` only works with degrees, not radians.
+ - num (number) value
+ = (number) asin in degrees
+ \*/
+ Snap.asin = function (num) {
+ return Snap.deg(math.asin(num));
+ };
+ /*\
+ * Snap.acos
+ [ method ]
+ **
+ * Equivalent to `Math.acos()` only works with degrees, not radians.
+ - num (number) value
+ = (number) acos in degrees
+ \*/
+ Snap.acos = function (num) {
+ return Snap.deg(math.acos(num));
+ };
+ /*\
+ * Snap.atan
+ [ method ]
+ **
+ * Equivalent to `Math.atan()` only works with degrees, not radians.
+ - num (number) value
+ = (number) atan in degrees
+ \*/
+ Snap.atan = function (num) {
+ return Snap.deg(math.atan(num));
+ };
+ /*\
+ * Snap.atan2
+ [ method ]
+ **
+ * Equivalent to `Math.atan2()` only works with degrees, not radians.
+ - num (number) value
+ = (number) atan2 in degrees
+ \*/
+ Snap.atan2 = function (num) {
+ return Snap.deg(math.atan2(num));
+ };
+ /*\
+ * Snap.angle
+ [ method ]
+ **
+ * Returns an angle between two or three points
+ > Parameters
+ - x1 (number) x coord of first point
+ - y1 (number) y coord of first point
+ - x2 (number) x coord of second point
+ - y2 (number) y coord of second point
+ - x3 (number) #optional x coord of third point
+ - y3 (number) #optional y coord of third point
+ = (number) angle in degrees
+ \*/
+ Snap.angle = angle;
+ /*\
+ * Snap.len
+ [ method ]
+ **
+ * Returns distance between two points
+ > Parameters
+ - x1 (number) x coord of first point
+ - y1 (number) y coord of first point
+ - x2 (number) x coord of second point
+ - y2 (number) y coord of second point
+ = (number) distance
+ \*/
+ Snap.len = function (x1, y1, x2, y2) {
+ return Math.sqrt(Snap.len2(x1, y1, x2, y2));
+ };
+ /*\
+ * Snap.len2
+ [ method ]
+ **
+ * Returns squared distance between two points
+ > Parameters
+ - x1 (number) x coord of first point
+ - y1 (number) y coord of first point
+ - x2 (number) x coord of second point
+ - y2 (number) y coord of second point
+ = (number) distance
+ \*/
+ Snap.len2 = function (x1, y1, x2, y2) {
+ return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
+ };
+ /*\
+ * Snap.closestPoint
+ [ method ]
+ **
+ * Returns closest point to a given one on a given path.
+ > Parameters
+ - path (Element) path element
+ - x (number) x coord of a point
+ - y (number) y coord of a point
+ = (object) in format
+ {
+ x (number) x coord of the point on the path
+ y (number) y coord of the point on the path
+ length (number) length of the path to the point
+ distance (number) distance from the given point to the path
+ }
+ \*/
+ // Copied from http://bl.ocks.org/mbostock/8027637
+ Snap.closestPoint = function (path, x, y) {
+ function distance2(p) {
+ var dx = p.x - x,
+ dy = p.y - y;
+ return dx * dx + dy * dy;
+ }
+ var pathNode = path.node,
+ pathLength = pathNode.getTotalLength(),
+ precision = pathLength / pathNode.pathSegList.numberOfItems * .125,
+ best,
+ bestLength,
+ bestDistance = Infinity;
+
+ // linear scan for coarse approximation
+ for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
+ if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
+ best = scan, bestLength = scanLength, bestDistance = scanDistance;
+ }
+ }
+
+ // binary search for precise estimate
+ precision *= .5;
+ while (precision > .5) {
+ var before,
+ after,
+ beforeLength,
+ afterLength,
+ beforeDistance,
+ afterDistance;
+ if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
+ best = before, bestLength = beforeLength, bestDistance = beforeDistance;
+ } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
+ best = after, bestLength = afterLength, bestDistance = afterDistance;
+ } else {
+ precision *= .5;
+ }
+ }
+
+ best = {
+ x: best.x,
+ y: best.y,
+ length: bestLength,
+ distance: Math.sqrt(bestDistance)
+ };
+ return best;
+ }
+ /*\
+ * Snap.is
+ [ method ]
+ **
+ * Handy replacement for the `typeof` operator
+ - o (…) any object or primitive
+ - type (string) name of the type, e.g., `string`, `function`, `number`, etc.
+ = (boolean) `true` if given value is of given type
+ \*/
+ Snap.is = is;
+ /*\
+ * Snap.snapTo
+ [ method ]
+ **
+ * Snaps given value to given grid
+ - values (array|number) given array of values or step of the grid
+ - value (number) value to adjust
+ - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`.
+ = (number) adjusted value
+ \*/
+ Snap.snapTo = function (values, value, tolerance) {
+ tolerance = is(tolerance, "finite") ? tolerance : 10;
+ if (is(values, "array")) {
+ var i = values.length;
+ while (i--) if (abs(values[i] - value) <= tolerance) {
+ return values[i];
+ }
+ } else {
+ values = +values;
+ var rem = value % values;
+ if (rem < tolerance) {
+ return value - rem;
+ }
+ if (rem > values - tolerance) {
+ return value - rem + values;
+ }
+ }
+ return value;
+ };
+ // Colour
+ /*\
+ * Snap.getRGB
+ [ method ]
+ **
+ * Parses color string as RGB object
+ - color (string) color string in one of the following formats:
+ # <ul>
+ # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li>
+ # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li>
+ # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li>
+ # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li>
+ # <li>rgba(•••, •••, •••, •••) — also with opacity</li>
+ # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li>
+ # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li>
+ # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li>
+ # <li>hsba(•••, •••, •••, •••) — also with opacity</li>
+ # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
+ # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li>
+ # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li>
+ # <li>hsla(•••, •••, •••, •••) — also with opacity</li>
+ # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
+ # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li>
+ # </ul>
+ * Note that `%` can be used any time: `rgb(20%, 255, 50%)`.
+ = (object) RGB object in the following format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) true if string can't be parsed
+ o }
+ \*/
+ Snap.getRGB = cacher(function (colour) {
+ if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
+ return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
+ }
+ if (colour == "none") {
+ return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString};
+ }
+ !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
+ if (!colour) {
+ return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
+ }
+ var res,
+ red,
+ green,
+ blue,
+ opacity,
+ t,
+ values,
+ rgb = colour.match(colourRegExp);
+ if (rgb) {
+ if (rgb[2]) {
+ blue = toInt(rgb[2].substring(5), 16);
+ green = toInt(rgb[2].substring(3, 5), 16);
+ red = toInt(rgb[2].substring(1, 3), 16);
+ }
+ if (rgb[3]) {
+ blue = toInt((t = rgb[3].charAt(3)) + t, 16);
+ green = toInt((t = rgb[3].charAt(2)) + t, 16);
+ red = toInt((t = rgb[3].charAt(1)) + t, 16);
+ }
+ if (rgb[4]) {
+ values = rgb[4].split(commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red *= 2.55);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green *= 2.55);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue *= 2.55);
+ rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ }
+ if (rgb[5]) {
+ values = rgb[5].split(commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red /= 100);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green /= 100);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue /= 100);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return Snap.hsb2rgb(red, green, blue, opacity);
+ }
+ if (rgb[6]) {
+ values = rgb[6].split(commaSpaces);
+ red = toFloat(values[0]);
+ values[0].slice(-1) == "%" && (red /= 100);
+ green = toFloat(values[1]);
+ values[1].slice(-1) == "%" && (green /= 100);
+ blue = toFloat(values[2]);
+ values[2].slice(-1) == "%" && (blue /= 100);
+ (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
+ rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
+ values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
+ return Snap.hsl2rgb(red, green, blue, opacity);
+ }
+ red = mmin(math.round(red), 255);
+ green = mmin(math.round(green), 255);
+ blue = mmin(math.round(blue), 255);
+ opacity = mmin(mmax(opacity, 0), 1);
+ rgb = {r: red, g: green, b: blue, toString: rgbtoString};
+ rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
+ rgb.opacity = is(opacity, "finite") ? opacity : 1;
+ return rgb;
+ }
+ return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
+ }, Snap);
+ /*\
+ * Snap.hsb
+ [ method ]
+ **
+ * Converts HSB values to a hex representation of the color
+ - h (number) hue
+ - s (number) saturation
+ - b (number) value or brightness
+ = (string) hex representation of the color
+ \*/
+ Snap.hsb = cacher(function (h, s, b) {
+ return Snap.hsb2rgb(h, s, b).hex;
+ });
+ /*\
+ * Snap.hsl
+ [ method ]
+ **
+ * Converts HSL values to a hex representation of the color
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (string) hex representation of the color
+ \*/
+ Snap.hsl = cacher(function (h, s, l) {
+ return Snap.hsl2rgb(h, s, l).hex;
+ });
+ /*\
+ * Snap.rgb
+ [ method ]
+ **
+ * Converts RGB values to a hex representation of the color
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (string) hex representation of the color
+ \*/
+ Snap.rgb = cacher(function (r, g, b, o) {
+ if (is(o, "finite")) {
+ var round = math.round;
+ return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")";
+ }
+ return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
+ });
+ var toHex = function (color) {
+ var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0],
+ red = "rgb(255, 0, 0)";
+ toHex = cacher(function (color) {
+ if (color.toLowerCase() == "red") {
+ return red;
+ }
+ i.style.color = red;
+ i.style.color = color;
+ var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
+ return out == red ? null : out;
+ });
+ return toHex(color);
+ },
+ hsbtoString = function () {
+ return "hsb(" + [this.h, this.s, this.b] + ")";
+ },
+ hsltoString = function () {
+ return "hsl(" + [this.h, this.s, this.l] + ")";
+ },
+ rgbtoString = function () {
+ return this.opacity == 1 || this.opacity == null ?
+ this.hex :
+ "rgba(" + [this.r, this.g, this.b, this.opacity] + ")";
+ },
+ prepareRGB = function (r, g, b) {
+ if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) {
+ b = r.b;
+ g = r.g;
+ r = r.r;
+ }
+ if (g == null && is(r, string)) {
+ var clr = Snap.getRGB(r);
+ r = clr.r;
+ g = clr.g;
+ b = clr.b;
+ }
+ if (r > 1 || g > 1 || b > 1) {
+ r /= 255;
+ g /= 255;
+ b /= 255;
+ }
+
+ return [r, g, b];
+ },
+ packageRGB = function (r, g, b, o) {
+ r = math.round(r * 255);
+ g = math.round(g * 255);
+ b = math.round(b * 255);
+ var rgb = {
+ r: r,
+ g: g,
+ b: b,
+ opacity: is(o, "finite") ? o : 1,
+ hex: Snap.rgb(r, g, b),
+ toString: rgbtoString
+ };
+ is(o, "finite") && (rgb.opacity = o);
+ return rgb;
+ };
+ /*\
+ * Snap.color
+ [ method ]
+ **
+ * Parses the color string and returns an object featuring the color's component values
+ - clr (string) color string in one of the supported formats (see @Snap.getRGB)
+ = (object) Combined RGB/HSB object in the following format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••,
+ o error (boolean) `true` if string can't be parsed,
+ o h (number) hue,
+ o s (number) saturation,
+ o v (number) value (brightness),
+ o l (number) lightness
+ o }
+ \*/
+ Snap.color = function (clr) {
+ var rgb;
+ if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
+ rgb = Snap.hsb2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.opacity = 1;
+ clr.hex = rgb.hex;
+ } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
+ rgb = Snap.hsl2rgb(clr);
+ clr.r = rgb.r;
+ clr.g = rgb.g;
+ clr.b = rgb.b;
+ clr.opacity = 1;
+ clr.hex = rgb.hex;
+ } else {
+ if (is(clr, "string")) {
+ clr = Snap.getRGB(clr);
+ }
+ if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) {
+ rgb = Snap.rgb2hsl(clr);
+ clr.h = rgb.h;
+ clr.s = rgb.s;
+ clr.l = rgb.l;
+ rgb = Snap.rgb2hsb(clr);
+ clr.v = rgb.b;
+ } else {
+ clr = {hex: "none"};
+ clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
+ clr.error = 1;
+ }
+ }
+ clr.toString = rgbtoString;
+ return clr;
+ };
+ /*\
+ * Snap.hsb2rgb
+ [ method ]
+ **
+ * Converts HSB values to an RGB object
+ - h (number) hue
+ - s (number) saturation
+ - v (number) value or brightness
+ = (object) RGB object in the following format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ Snap.hsb2rgb = function (h, s, v, o) {
+ if (is(h, "object") && "h" in h && "s" in h && "b" in h) {
+ v = h.b;
+ s = h.s;
+ o = h.o;
+ h = h.h;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = v * s;
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = v - C;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+ /*\
+ * Snap.hsl2rgb
+ [ method ]
+ **
+ * Converts HSL values to an RGB object
+ - h (number) hue
+ - s (number) saturation
+ - l (number) luminosity
+ = (object) RGB object in the following format:
+ o {
+ o r (number) red,
+ o g (number) green,
+ o b (number) blue,
+ o hex (string) color in HTML/CSS format: #••••••
+ o }
+ \*/
+ Snap.hsl2rgb = function (h, s, l, o) {
+ if (is(h, "object") && "h" in h && "s" in h && "l" in h) {
+ l = h.l;
+ s = h.s;
+ h = h.h;
+ }
+ if (h > 1 || s > 1 || l > 1) {
+ h /= 360;
+ s /= 100;
+ l /= 100;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = 2 * s * (l < .5 ? l : 1 - l);
+ X = C * (1 - abs(h % 2 - 1));
+ R = G = B = l - C / 2;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return packageRGB(R, G, B, o);
+ };
+ /*\
+ * Snap.rgb2hsb
+ [ method ]
+ **
+ * Converts RGB values to an HSB object
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSB object in the following format:
+ o {
+ o h (number) hue,
+ o s (number) saturation,
+ o b (number) brightness
+ o }
+ \*/
+ Snap.rgb2hsb = function (r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, V, C;
+ V = mmax(r, g, b);
+ C = V - mmin(r, g, b);
+ H = (C == 0 ? null :
+ V == r ? (g - b) / C :
+ V == g ? (b - r) / C + 2 :
+ (r - g) / C + 4
+ );
+ H = ((H + 360) % 6) * 60 / 360;
+ S = C == 0 ? 0 : C / V;
+ return {h: H, s: S, b: V, toString: hsbtoString};
+ };
+ /*\
+ * Snap.rgb2hsl
+ [ method ]
+ **
+ * Converts RGB values to an HSL object
+ - r (number) red
+ - g (number) green
+ - b (number) blue
+ = (object) HSL object in the following format:
+ o {
+ o h (number) hue,
+ o s (number) saturation,
+ o l (number) luminosity
+ o }
+ \*/
+ Snap.rgb2hsl = function (r, g, b) {
+ b = prepareRGB(r, g, b);
+ r = b[0];
+ g = b[1];
+ b = b[2];
+
+ var H, S, L, M, m, C;
+ M = mmax(r, g, b);
+ m = mmin(r, g, b);
+ C = M - m;
+ H = (C == 0 ? null :
+ M == r ? (g - b) / C :
+ M == g ? (b - r) / C + 2 :
+ (r - g) / C + 4);
+ H = ((H + 360) % 6) * 60 / 360;
+ L = (M + m) / 2;
+ S = (C == 0 ? 0 :
+ L < .5 ? C / (2 * L) :
+ C / (2 - 2 * L));
+ return {h: H, s: S, l: L, toString: hsltoString};
+ };
+
+ // Transformations
+ /*\
+ * Snap.parsePathString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given path string into an array of arrays of path segments
+ - pathString (string|array) path string or array of segments (in the last case it is returned straight away)
+ = (array) array of segments
+ \*/
+ Snap.parsePathString = function (pathString) {
+ if (!pathString) {
+ return null;
+ }
+ var pth = Snap.path(pathString);
+ if (pth.arr) {
+ return Snap.path.clone(pth.arr);
+ }
+
+ var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
+ data = [];
+ if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption
+ data = Snap.path.clone(pathString);
+ }
+ if (!data.length) {
+ Str(pathString).replace(pathCommand, function (a, b, c) {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(pathValues, function (a, b) {
+ b && params.push(+b);
+ });
+ if (name == "m" && params.length > 2) {
+ data.push([b].concat(params.splice(0, 2)));
+ name = "l";
+ b = b == "m" ? "l" : "L";
+ }
+ if (name == "o" && params.length == 1) {
+ data.push([b, params[0]]);
+ }
+ if (name == "r") {
+ data.push([b].concat(params));
+ } else while (params.length >= paramCounts[name]) {
+ data.push([b].concat(params.splice(0, paramCounts[name])));
+ if (!paramCounts[name]) {
+ break;
+ }
+ }
+ });
+ }
+ data.toString = Snap.path.toString;
+ pth.arr = Snap.path.clone(data);
+ return data;
+ };
+ /*\
+ * Snap.parseTransformString
+ [ method ]
+ **
+ * Utility method
+ **
+ * Parses given transform string into an array of transformations
+ - TString (string|array) transform string or array of transformations (in the last case it is returned straight away)
+ = (array) array of transformations
+ \*/
+ var parseTransformString = Snap.parseTransformString = function (TString) {
+ if (!TString) {
+ return null;
+ }
+ var paramCounts = {r: 3, s: 4, t: 2, m: 6},
+ data = [];
+ if (is(TString, "array") && is(TString[0], "array")) { // rough assumption
+ data = Snap.path.clone(TString);
+ }
+ if (!data.length) {
+ Str(TString).replace(tCommand, function (a, b, c) {
+ var params = [],
+ name = b.toLowerCase();
+ c.replace(pathValues, function (a, b) {
+ b && params.push(+b);
+ });
+ data.push([b].concat(params));
+ });
+ }
+ data.toString = Snap.path.toString;
+ return data;
+ };
+ function svgTransform2string(tstr) {
+ var res = [];
+ tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) {
+ params = params.split(/\s*,\s*|\s+/);
+ if (name == "rotate" && params.length == 1) {
+ params.push(0, 0);
+ }
+ if (name == "scale") {
+ if (params.length > 2) {
+ params = params.slice(0, 2);
+ } else if (params.length == 2) {
+ params.push(0, 0);
+ }
+ if (params.length == 1) {
+ params.push(params[0], 0, 0);
+ }
+ }
+ if (name == "skewX") {
+ res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]);
+ } else if (name == "skewY") {
+ res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]);
+ } else {
+ res.push([name.charAt(0)].concat(params));
+ }
+ return all;
+ });
+ return res;
+ }
+ Snap._.svgTransform2string = svgTransform2string;
+ Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i;
+ function transform2matrix(tstr, bbox) {
+ var tdata = parseTransformString(tstr),
+ m = new Snap.Matrix;
+ if (tdata) {
+ for (var i = 0, ii = tdata.length; i < ii; i++) {
+ var t = tdata[i],
+ tlen = t.length,
+ command = Str(t[0]).toLowerCase(),
+ absolute = t[0] != command,
+ inver = absolute ? m.invert() : 0,
+ x1,
+ y1,
+ x2,
+ y2,
+ bb;
+ if (command == "t" && tlen == 2){
+ m.translate(t[1], 0);
+ } else if (command == "t" && tlen == 3) {
+ if (absolute) {
+ x1 = inver.x(0, 0);
+ y1 = inver.y(0, 0);
+ x2 = inver.x(t[1], t[2]);
+ y2 = inver.y(t[1], t[2]);
+ m.translate(x2 - x1, y2 - y1);
+ } else {
+ m.translate(t[1], t[2]);
+ }
+ } else if (command == "r") {
+ if (tlen == 2) {
+ bb = bb || bbox;
+ m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ } else if (tlen == 4) {
+ if (absolute) {
+ x2 = inver.x(t[2], t[3]);
+ y2 = inver.y(t[2], t[3]);
+ m.rotate(t[1], x2, y2);
+ } else {
+ m.rotate(t[1], t[2], t[3]);
+ }
+ }
+ } else if (command == "s") {
+ if (tlen == 2 || tlen == 3) {
+ bb = bb || bbox;
+ m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
+ } else if (tlen == 4) {
+ if (absolute) {
+ x2 = inver.x(t[2], t[3]);
+ y2 = inver.y(t[2], t[3]);
+ m.scale(t[1], t[1], x2, y2);
+ } else {
+ m.scale(t[1], t[1], t[2], t[3]);
+ }
+ } else if (tlen == 5) {
+ if (absolute) {
+ x2 = inver.x(t[3], t[4]);
+ y2 = inver.y(t[3], t[4]);
+ m.scale(t[1], t[2], x2, y2);
+ } else {
+ m.scale(t[1], t[2], t[3], t[4]);
+ }
+ }
+ } else if (command == "m" && tlen == 7) {
+ m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
+ }
+ }
+ }
+ return m;
+ }
+ Snap._.transform2matrix = transform2matrix;
+ Snap._unit2px = unit2px;
+ var contains = glob.doc.contains || glob.doc.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 = b.parentNode;
+ if (b == a) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ function getSomeDefs(el) {
+ var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) ||
+ (el.node.parentNode && wrap(el.node.parentNode)) ||
+ Snap.select("svg") ||
+ Snap(0, 0),
+ pdefs = p.select("defs"),
+ defs = pdefs == null ? false : pdefs.node;
+ if (!defs) {
+ defs = make("defs", p.node).node;
+ }
+ return defs;
+ }
+ function getSomeSVG(el) {
+ return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg");
+ }
+ Snap._.getSomeDefs = getSomeDefs;
+ Snap._.getSomeSVG = getSomeSVG;
+ function unit2px(el, name, value) {
+ var svg = getSomeSVG(el).node,
+ out = {},
+ mgr = svg.querySelector(".svg---mgr");
+ if (!mgr) {
+ mgr = $("rect");
+ $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"});
+ svg.appendChild(mgr);
+ }
+ function getW(val) {
+ if (val == null) {
+ return E;
+ }
+ if (val == +val) {
+ return val;
+ }
+ $(mgr, {width: val});
+ try {
+ return mgr.getBBox().width;
+ } catch (e) {
+ return 0;
+ }
+ }
+ function getH(val) {
+ if (val == null) {
+ return E;
+ }
+ if (val == +val) {
+ return val;
+ }
+ $(mgr, {height: val});
+ try {
+ return mgr.getBBox().height;
+ } catch (e) {
+ return 0;
+ }
+ }
+ function set(nam, f) {
+ if (name == null) {
+ out[nam] = f(el.attr(nam) || 0);
+ } else if (nam == name) {
+ out = f(value == null ? el.attr(nam) || 0 : value);
+ }
+ }
+ switch (el.type) {
+ case "rect":
+ set("rx", getW);
+ set("ry", getH);
+ case "image":
+ set("width", getW);
+ set("height", getH);
+ case "text":
+ set("x", getW);
+ set("y", getH);
+ break;
+ case "circle":
+ set("cx", getW);
+ set("cy", getH);
+ set("r", getW);
+ break;
+ case "ellipse":
+ set("cx", getW);
+ set("cy", getH);
+ set("rx", getW);
+ set("ry", getH);
+ break;
+ case "line":
+ set("x1", getW);
+ set("x2", getW);
+ set("y1", getH);
+ set("y2", getH);
+ break;
+ case "marker":
+ set("refX", getW);
+ set("markerWidth", getW);
+ set("refY", getH);
+ set("markerHeight", getH);
+ break;
+ case "radialGradient":
+ set("fx", getW);
+ set("fy", getH);
+ break;
+ case "tspan":
+ set("dx", getW);
+ set("dy", getH);
+ break;
+ default:
+ set(name, getW);
+ }
+ svg.removeChild(mgr);
+ return out;
+ }
+ /*\
+ * Snap.select
+ [ method ]
+ **
+ * Wraps a DOM element specified by CSS selector as @Element
+ - query (string) CSS selector of the element
+ = (Element) the current element
+ \*/
+ Snap.select = function (query) {
+ query = Str(query).replace(/([^\\]):/g, "$1\\:");
+ return wrap(glob.doc.querySelector(query));
+ };
+ /*\
+ * Snap.selectAll
+ [ method ]
+ **
+ * Wraps DOM elements specified by CSS selector as set or array of @Element
+ - query (string) CSS selector of the element
+ = (Element) the current element
+ \*/
+ Snap.selectAll = function (query) {
+ var nodelist = glob.doc.querySelectorAll(query),
+ set = (Snap.set || Array)();
+ for (var i = 0; i < nodelist.length; i++) {
+ set.push(wrap(nodelist[i]));
+ }
+ return set;
+ };
+
+ function add2group(list) {
+ if (!is(list, "array")) {
+ list = Array.prototype.slice.call(arguments, 0);
+ }
+ var i = 0,
+ j = 0,
+ node = this.node;
+ while (this[i]) delete this[i++];
+ for (i = 0; i < list.length; i++) {
+ if (list[i].type == "set") {
+ list[i].forEach(function (el) {
+ node.appendChild(el.node);
+ });
+ } else {
+ node.appendChild(list[i].node);
+ }
+ }
+ var children = node.childNodes;
+ for (i = 0; i < children.length; i++) {
+ this[j++] = wrap(children[i]);
+ }
+ return this;
+ }
+ // Hub garbage collector every 10s
+ setInterval(function () {
+ for (var key in hub) if (hub[has](key)) {
+ var el = hub[key],
+ node = el.node;
+ if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) {
+ delete hub[key];
+ }
+ }
+ }, 1e4);
+ function Element(el) {
+ if (el.snap in hub) {
+ return hub[el.snap];
+ }
+ var svg;
+ try {
+ svg = el.ownerSVGElement;
+ } catch(e) {}
+ /*\
+ * Element.node
+ [ property (object) ]
+ **
+ * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
+ > Usage
+ | // draw a circle at coordinate 10,10 with radius of 10
+ | var c = paper.circle(10, 10, 10);
+ | c.node.onclick = function () {
+ | c.attr("fill", "red");
+ | };
+ \*/
+ this.node = el;
+ if (svg) {
+ this.paper = new Paper(svg);
+ }
+ /*\
+ * Element.type
+ [ property (string) ]
+ **
+ * SVG tag name of the given element.
+ \*/
+ this.type = el.tagName || el.nodeName;
+ var id = this.id = ID(this);
+ this.anims = {};
+ this._ = {
+ transform: []
+ };
+ el.snap = id;
+ hub[id] = this;
+ if (this.type == "g") {
+ this.add = add2group;
+ }
+ if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) {
+ for (var method in Paper.prototype) if (Paper.prototype[has](method)) {
+ this[method] = Paper.prototype[method];
+ }
+ }
+ }
+ /*\
+ * Element.attr
+ [ method ]
+ **
+ * Gets or sets given attributes of the element.
+ **
+ - params (object) contains key-value pairs of attributes you want to set
+ * or
+ - param (string) name of the attribute
+ = (Element) the current element
+ * or
+ = (string) value of attribute
+ > Usage
+ | el.attr({
+ | fill: "#fc0",
+ | stroke: "#000",
+ | strokeWidth: 2, // CamelCase...
+ | "fill-opacity": 0.5, // or dash-separated names
+ | width: "*=2" // prefixed values
+ | });
+ | console.log(el.attr("fill")); // #fc0
+ * Prefixed values in format `"+=10"` supported. All four operations
+ * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+`
+ * and `-`: `"+=2em"`.
+ \*/
+ Element.prototype.attr = function (params, value) {
+ var el = this,
+ node = el.node;
+ if (!params) {
+ if (node.nodeType != 1) {
+ return {
+ text: node.nodeValue
+ };
+ }
+ var attr = node.attributes,
+ out = {};
+ for (var i = 0, ii = attr.length; i < ii; i++) {
+ out[attr[i].nodeName] = attr[i].nodeValue;
+ }
+ return out;
+ }
+ if (is(params, "string")) {
+ if (arguments.length > 1) {
+ var json = {};
+ json[params] = value;
+ params = json;
+ } else {
+ return eve("snap.util.getattr." + params, el).firstDefined();
+ }
+ }
+ for (var att in params) {
+ if (params[has](att)) {
+ eve("snap.util.attr." + att, el, params[att]);
+ }
+ }
+ return el;
+ };
+ /*\
+ * Snap.parse
+ [ method ]
+ **
+ * Parses SVG fragment and converts it into a @Fragment
+ **
+ - svg (string) SVG string
+ = (Fragment) the @Fragment
+ \*/
+ Snap.parse = function (svg) {
+ var f = glob.doc.createDocumentFragment(),
+ full = true,
+ div = glob.doc.createElement("div");
+ svg = Str(svg);
+ if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) {
+ svg = "<svg>" + svg + "</svg>";
+ full = false;
+ }
+ div.innerHTML = svg;
+ svg = div.getElementsByTagName("svg")[0];
+ if (svg) {
+ if (full) {
+ f = svg;
+ } else {
+ while (svg.firstChild) {
+ f.appendChild(svg.firstChild);
+ }
+ }
+ }
+ return new Fragment(f);
+ };
+ function Fragment(frag) {
+ this.node = frag;
+ }
+ /*\
+ * Snap.fragment
+ [ method ]
+ **
+ * Creates a DOM fragment from a given list of elements or strings
+ **
+ - varargs (…) SVG string
+ = (Fragment) the @Fragment
+ \*/
+ Snap.fragment = function () {
+ var args = Array.prototype.slice.call(arguments, 0),
+ f = glob.doc.createDocumentFragment();
+ for (var i = 0, ii = args.length; i < ii; i++) {
+ var item = args[i];
+ if (item.node && item.node.nodeType) {
+ f.appendChild(item.node);
+ }
+ if (item.nodeType) {
+ f.appendChild(item);
+ }
+ if (typeof item == "string") {
+ f.appendChild(Snap.parse(item).node);
+ }
+ }
+ return new Fragment(f);
+ };
+
+ function make(name, parent) {
+ var res = $(name);
+ parent.appendChild(res);
+ var el = wrap(res);
+ return el;
+ }
+ function Paper(w, h) {
+ var res,
+ desc,
+ defs,
+ proto = Paper.prototype;
+ if (w && w.tagName == "svg") {
+ if (w.snap in hub) {
+ return hub[w.snap];
+ }
+ var doc = w.ownerDocument;
+ res = new Element(w);
+ desc = w.getElementsByTagName("desc")[0];
+ defs = w.getElementsByTagName("defs")[0];
+ if (!desc) {
+ desc = $("desc");
+ desc.appendChild(doc.createTextNode("Created with Snap"));
+ res.node.appendChild(desc);
+ }
+ if (!defs) {
+ defs = $("defs");
+ res.node.appendChild(defs);
+ }
+ res.defs = defs;
+ for (var key in proto) if (proto[has](key)) {
+ res[key] = proto[key];
+ }
+ res.paper = res.root = res;
+ } else {
+ res = make("svg", glob.doc.body);
+ $(res.node, {
+ height: h,
+ version: 1.1,
+ width: w,
+ xmlns: xmlns
+ });
+ }
+ return res;
+ }
+ function wrap(dom) {
+ if (!dom) {
+ return dom;
+ }
+ if (dom instanceof Element || dom instanceof Fragment) {
+ return dom;
+ }
+ if (dom.tagName && dom.tagName.toLowerCase() == "svg") {
+ return new Paper(dom);
+ }
+ if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") {
+ return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]);
+ }
+ return new Element(dom);
+ }
+
+ Snap._.make = make;
+ Snap._.wrap = wrap;
+ /*\
+ * Paper.el
+ [ method ]
+ **
+ * Creates an element on paper with a given name and no attributes
+ **
+ - name (string) tag name
+ - attr (object) attributes
+ = (Element) the current element
+ > Usage
+ | var c = paper.circle(10, 10, 10); // is the same as...
+ | var c = paper.el("circle").attr({
+ | cx: 10,
+ | cy: 10,
+ | r: 10
+ | });
+ | // and the same as
+ | var c = paper.el("circle", {
+ | cx: 10,
+ | cy: 10,
+ | r: 10
+ | });
+ \*/
+ Paper.prototype.el = function (name, attr) {
+ var el = make(name, this.node);
+ attr && el.attr(attr);
+ return el;
+ };
+ /*\
+ * Element.children
+ [ method ]
+ **
+ * Returns array of all the children of the element.
+ = (array) array of Elements
+ \*/
+ Element.prototype.children = function () {
+ var out = [],
+ ch = this.node.childNodes;
+ for (var i = 0, ii = ch.length; i < ii; i++) {
+ out[i] = Snap(ch[i]);
+ }
+ return out;
+ };
+ function jsonFiller(root, o) {
+ for (var i = 0, ii = root.length; i < ii; i++) {
+ var item = {
+ type: root[i].type,
+ attr: root[i].attr()
+ },
+ children = root[i].children();
+ o.push(item);
+ if (children.length) {
+ jsonFiller(children, item.childNodes = []);
+ }
+ }
+ }
+ /*\
+ * Element.toJSON
+ [ method ]
+ **
+ * Returns object representation of the given element and all its children.
+ = (object) in format
+ o {
+ o type (string) this.type,
+ o attr (object) attributes map,
+ o childNodes (array) optional array of children in the same format
+ o }
+ \*/
+ Element.prototype.toJSON = function () {
+ var out = [];
+ jsonFiller([this], out);
+ return out[0];
+ };
+ // default
+ eve.on("snap.util.getattr", function () {
+ var att = eve.nt();
+ att = att.substring(att.lastIndexOf(".") + 1);
+ var css = att.replace(/[A-Z]/g, function (letter) {
+ return "-" + letter.toLowerCase();
+ });
+ if (cssAttr[has](css)) {
+ return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css);
+ } else {
+ return $(this.node, att);
+ }
+ });
+ var cssAttr = {
+ "alignment-baseline": 0,
+ "baseline-shift": 0,
+ "clip": 0,
+ "clip-path": 0,
+ "clip-rule": 0,
+ "color": 0,
+ "color-interpolation": 0,
+ "color-interpolation-filters": 0,
+ "color-profile": 0,
+ "color-rendering": 0,
+ "cursor": 0,
+ "direction": 0,
+ "display": 0,
+ "dominant-baseline": 0,
+ "enable-background": 0,
+ "fill": 0,
+ "fill-opacity": 0,
+ "fill-rule": 0,
+ "filter": 0,
+ "flood-color": 0,
+ "flood-opacity": 0,
+ "font": 0,
+ "font-family": 0,
+ "font-size": 0,
+ "font-size-adjust": 0,
+ "font-stretch": 0,
+ "font-style": 0,
+ "font-variant": 0,
+ "font-weight": 0,
+ "glyph-orientation-horizontal": 0,
+ "glyph-orientation-vertical": 0,
+ "image-rendering": 0,
+ "kerning": 0,
+ "letter-spacing": 0,
+ "lighting-color": 0,
+ "marker": 0,
+ "marker-end": 0,
+ "marker-mid": 0,
+ "marker-start": 0,
+ "mask": 0,
+ "opacity": 0,
+ "overflow": 0,
+ "pointer-events": 0,
+ "shape-rendering": 0,
+ "stop-color": 0,
+ "stop-opacity": 0,
+ "stroke": 0,
+ "stroke-dasharray": 0,
+ "stroke-dashoffset": 0,
+ "stroke-linecap": 0,
+ "stroke-linejoin": 0,
+ "stroke-miterlimit": 0,
+ "stroke-opacity": 0,
+ "stroke-width": 0,
+ "text-anchor": 0,
+ "text-decoration": 0,
+ "text-rendering": 0,
+ "unicode-bidi": 0,
+ "visibility": 0,
+ "word-spacing": 0,
+ "writing-mode": 0
+ };
+
+ eve.on("snap.util.attr", function (value) {
+ var att = eve.nt(),
+ attr = {};
+ att = att.substring(att.lastIndexOf(".") + 1);
+ attr[att] = value;
+ var style = att.replace(/-(\w)/gi, function (all, letter) {
+ return letter.toUpperCase();
+ }),
+ css = att.replace(/[A-Z]/g, function (letter) {
+ return "-" + letter.toLowerCase();
+ });
+ if (cssAttr[has](css)) {
+ this.node.style[style] = value == null ? E : value;
+ } else {
+ $(this.node, attr);
+ }
+ });
+ (function (proto) {}(Paper.prototype));
+
+ // simple ajax
+ /*\
+ * Snap.ajax
+ [ method ]
+ **
+ * Simple implementation of Ajax
+ **
+ - url (string) URL
+ - postData (object|string) data for post request
+ - callback (function) callback
+ - scope (object) #optional scope of callback
+ * or
+ - url (string) URL
+ - callback (function) callback
+ - scope (object) #optional scope of callback
+ = (XMLHttpRequest) the XMLHttpRequest object, just in case
+ \*/
+ Snap.ajax = function (url, postData, callback, scope){
+ var req = new XMLHttpRequest,
+ id = ID();
+ if (req) {
+ if (is(postData, "function")) {
+ scope = callback;
+ callback = postData;
+ postData = null;
+ } else if (is(postData, "object")) {
+ var pd = [];
+ for (var key in postData) if (postData.hasOwnProperty(key)) {
+ pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key]));
+ }
+ postData = pd.join("&");
+ }
+ req.open((postData ? "POST" : "GET"), url, true);
+ if (postData) {
+ req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ }
+ if (callback) {
+ eve.once("snap.ajax." + id + ".0", callback);
+ eve.once("snap.ajax." + id + ".200", callback);
+ eve.once("snap.ajax." + id + ".304", callback);
+ }
+ req.onreadystatechange = function() {
+ if (req.readyState != 4) return;
+ eve("snap.ajax." + id + "." + req.status, scope, req);
+ };
+ if (req.readyState == 4) {
+ return req;
+ }
+ req.send(postData);
+ return req;
+ }
+ };
+ /*\
+ * Snap.load
+ [ method ]
+ **
+ * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX)
+ **
+ - url (string) URL
+ - callback (function) callback
+ - scope (object) #optional scope of callback
+ \*/
+ Snap.load = function (url, callback, scope) {
+ Snap.ajax(url, function (req) {
+ var f = Snap.parse(req.responseText);
+ scope ? callback.call(scope, f) : callback(f);
+ });
+ };
+ var getOffset = function (elem) {
+ var box = elem.getBoundingClientRect(),
+ doc = elem.ownerDocument,
+ body = doc.body,
+ docElem = doc.documentElement,
+ clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
+ left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
+ return {
+ y: top,
+ x: left
+ };
+ };
+ /*\
+ * Snap.getElementByPoint
+ [ method ]
+ **
+ * Returns you topmost element under given point.
+ **
+ = (object) Snap element object
+ - x (number) x coordinate from the top left corner of the window
+ - y (number) y coordinate from the top left corner of the window
+ > Usage
+ | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+ \*/
+ Snap.getElementByPoint = function (x, y) {
+ var paper = this,
+ svg = paper.canvas,
+ target = glob.doc.elementFromPoint(x, y);
+ if (glob.win.opera && target.tagName == "svg") {
+ var so = getOffset(target),
+ sr = target.createSVGRect();
+ sr.x = x - so.x;
+ sr.y = y - so.y;
+ sr.width = sr.height = 1;
+ var hits = target.getIntersectionList(sr, null);
+ if (hits.length) {
+ target = hits[hits.length - 1];
+ }
+ }
+ if (!target) {
+ return null;
+ }
+ return wrap(target);
+ };
+ /*\
+ * Snap.plugin
+ [ method ]
+ **
+ * Let you write plugins. You pass in a function with five arguments, like this:
+ | Snap.plugin(function (Snap, Element, Paper, global, Fragment) {
+ | Snap.newmethod = function () {};
+ | Element.prototype.newmethod = function () {};
+ | Paper.prototype.newmethod = function () {};
+ | });
+ * Inside the function you have access to all main objects (and their
+ * prototypes). This allow you to extend anything you want.
+ **
+ - f (function) your plugin body
+ \*/
+ Snap.plugin = function (f) {
+ f(Snap, Element, Paper, glob, Fragment);
+ };
+ glob.win.Snap = Snap;
+ return Snap;
+ }(window || this));
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var elproto = Element.prototype,
+ is = Snap.is,
+ Str = String,
+ unit2px = Snap._unit2px,
+ $ = Snap._.$,
+ make = Snap._.make,
+ getSomeDefs = Snap._.getSomeDefs,
+ has = "hasOwnProperty",
+ wrap = Snap._.wrap;
+ /*\
+ * Element.getBBox
+ [ method ]
+ **
+ * Returns the bounding box descriptor for the given element
+ **
+ = (object) bounding box descriptor:
+ o {
+ o cx: (number) x of the center,
+ o cy: (number) x of the center,
+ o h: (number) height,
+ o height: (number) height,
+ o path: (string) path command for the box,
+ o r0: (number) radius of a circle that fully encloses the box,
+ o r1: (number) radius of the smallest circle that can be enclosed,
+ o r2: (number) radius of the largest circle that can be enclosed,
+ o vb: (string) box as a viewbox command,
+ o w: (number) width,
+ o width: (number) width,
+ o x2: (number) x of the right side,
+ o x: (number) x of the left side,
+ o y2: (number) y of the bottom edge,
+ o y: (number) y of the top edge
+ o }
+ \*/
+ elproto.getBBox = function (isWithoutTransform) {
+ if (!Snap.Matrix || !Snap.path) {
+ return this.node.getBBox();
+ }
+ var el = this,
+ m = new Snap.Matrix;
+ if (el.removed) {
+ return Snap._.box();
+ }
+ while (el.type == "use") {
+ if (!isWithoutTransform) {
+ m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0));
+ }
+ if (el.original) {
+ el = el.original;
+ } else {
+ var href = el.attr("xlink:href");
+ el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1));
+ }
+ }
+ var _ = el._,
+ pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt;
+ try {
+ if (isWithoutTransform) {
+ _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox());
+ return Snap._.box(_.bboxwt);
+ } else {
+ el.realPath = pathfinder(el);
+ el.matrix = el.transform().localMatrix;
+ _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix)));
+ return Snap._.box(_.bbox);
+ }
+ } catch (e) {
+ // Firefox doesn’t give you bbox of hidden element
+ return Snap._.box();
+ }
+ };
+ var propString = function () {
+ return this.string;
+ };
+ function extractTransform(el, tstr) {
+ if (tstr == null) {
+ var doReturn = true;
+ if (el.type == "linearGradient" || el.type == "radialGradient") {
+ tstr = el.node.getAttribute("gradientTransform");
+ } else if (el.type == "pattern") {
+ tstr = el.node.getAttribute("patternTransform");
+ } else {
+ tstr = el.node.getAttribute("transform");
+ }
+ if (!tstr) {
+ return new Snap.Matrix;
+ }
+ tstr = Snap._.svgTransform2string(tstr);
+ } else {
+ if (!Snap._.rgTransform.test(tstr)) {
+ tstr = Snap._.svgTransform2string(tstr);
+ } else {
+ tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
+ }
+ if (is(tstr, "array")) {
+ tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
+ }
+ el._.transform = tstr;
+ }
+ var m = Snap._.transform2matrix(tstr, el.getBBox(1));
+ if (doReturn) {
+ return m;
+ } else {
+ el.matrix = m;
+ }
+ }
+ /*\
+ * Element.transform
+ [ method ]
+ **
+ * Gets or sets transformation of the element
+ **
+ - tstr (string) transform string in Snap or SVG format
+ = (Element) the current element
+ * or
+ = (object) transformation descriptor:
+ o {
+ o string (string) transform string,
+ o globalMatrix (Matrix) matrix of all transformations applied to element or its parents,
+ o localMatrix (Matrix) matrix of transformations applied only to the element,
+ o diffMatrix (Matrix) matrix of difference between global and local transformations,
+ o global (string) global transformation as string,
+ o local (string) local transformation as string,
+ o toString (function) returns `string` property
+ o }
+ \*/
+ elproto.transform = function (tstr) {
+ var _ = this._;
+ if (tstr == null) {
+ var papa = this,
+ global = new Snap.Matrix(this.node.getCTM()),
+ local = extractTransform(this),
+ ms = [local],
+ m = new Snap.Matrix,
+ i,
+ localString = local.toTransformString(),
+ string = Str(local) == Str(this.matrix) ?
+ Str(_.transform) : localString;
+ while (papa.type != "svg" && (papa = papa.parent())) {
+ ms.push(extractTransform(papa));
+ }
+ i = ms.length;
+ while (i--) {
+ m.add(ms[i]);
+ }
+ return {
+ string: string,
+ globalMatrix: global,
+ totalMatrix: m,
+ localMatrix: local,
+ diffMatrix: global.clone().add(local.invert()),
+ global: global.toTransformString(),
+ total: m.toTransformString(),
+ local: localString,
+ toString: propString
+ };
+ }
+ if (tstr instanceof Snap.Matrix) {
+ this.matrix = tstr;
+ this._.transform = tstr.toTransformString();
+ } else {
+ extractTransform(this, tstr);
+ }
+
+ if (this.node) {
+ if (this.type == "linearGradient" || this.type == "radialGradient") {
+ $(this.node, {gradientTransform: this.matrix});
+ } else if (this.type == "pattern") {
+ $(this.node, {patternTransform: this.matrix});
+ } else {
+ $(this.node, {transform: this.matrix});
+ }
+ }
+
+ return this;
+ };
+ /*\
+ * Element.parent
+ [ method ]
+ **
+ * Returns the element's parent
+ **
+ = (Element) the parent element
+ \*/
+ elproto.parent = function () {
+ return wrap(this.node.parentNode);
+ };
+ /*\
+ * Element.append
+ [ method ]
+ **
+ * Appends the given element to current one
+ **
+ - el (Element|Set) element to append
+ = (Element) the parent element
+ \*/
+ /*\
+ * Element.add
+ [ method ]
+ **
+ * See @Element.append
+ \*/
+ elproto.append = elproto.add = function (el) {
+ if (el) {
+ if (el.type == "set") {
+ var it = this;
+ el.forEach(function (el) {
+ it.add(el);
+ });
+ return this;
+ }
+ el = wrap(el);
+ this.node.appendChild(el.node);
+ el.paper = this.paper;
+ }
+ return this;
+ };
+ /*\
+ * Element.appendTo
+ [ method ]
+ **
+ * Appends the current element to the given one
+ **
+ - el (Element) parent element to append to
+ = (Element) the child element
+ \*/
+ elproto.appendTo = function (el) {
+ if (el) {
+ el = wrap(el);
+ el.append(this);
+ }
+ return this;
+ };
+ /*\
+ * Element.prepend
+ [ method ]
+ **
+ * Prepends the given element to the current one
+ **
+ - el (Element) element to prepend
+ = (Element) the parent element
+ \*/
+ elproto.prepend = function (el) {
+ if (el) {
+ if (el.type == "set") {
+ var it = this,
+ first;
+ el.forEach(function (el) {
+ if (first) {
+ first.after(el);
+ } else {
+ it.prepend(el);
+ }
+ first = el;
+ });
+ return this;
+ }
+ el = wrap(el);
+ var parent = el.parent();
+ this.node.insertBefore(el.node, this.node.firstChild);
+ this.add && this.add();
+ el.paper = this.paper;
+ this.parent() && this.parent().add();
+ parent && parent.add();
+ }
+ return this;
+ };
+ /*\
+ * Element.prependTo
+ [ method ]
+ **
+ * Prepends the current element to the given one
+ **
+ - el (Element) parent element to prepend to
+ = (Element) the child element
+ \*/
+ elproto.prependTo = function (el) {
+ el = wrap(el);
+ el.prepend(this);
+ return this;
+ };
+ /*\
+ * Element.before
+ [ method ]
+ **
+ * Inserts given element before the current one
+ **
+ - el (Element) element to insert
+ = (Element) the parent element
+ \*/
+ elproto.before = function (el) {
+ if (el.type == "set") {
+ var it = this;
+ el.forEach(function (el) {
+ var parent = el.parent();
+ it.node.parentNode.insertBefore(el.node, it.node);
+ parent && parent.add();
+ });
+ this.parent().add();
+ return this;
+ }
+ el = wrap(el);
+ var parent = el.parent();
+ this.node.parentNode.insertBefore(el.node, this.node);
+ this.parent() && this.parent().add();
+ parent && parent.add();
+ el.paper = this.paper;
+ return this;
+ };
+ /*\
+ * Element.after
+ [ method ]
+ **
+ * Inserts given element after the current one
+ **
+ - el (Element) element to insert
+ = (Element) the parent element
+ \*/
+ elproto.after = function (el) {
+ el = wrap(el);
+ var parent = el.parent();
+ if (this.node.nextSibling) {
+ this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
+ } else {
+ this.node.parentNode.appendChild(el.node);
+ }
+ this.parent() && this.parent().add();
+ parent && parent.add();
+ el.paper = this.paper;
+ return this;
+ };
+ /*\
+ * Element.insertBefore
+ [ method ]
+ **
+ * Inserts the element after the given one
+ **
+ - el (Element) element next to whom insert to
+ = (Element) the parent element
+ \*/
+ elproto.insertBefore = function (el) {
+ el = wrap(el);
+ var parent = this.parent();
+ el.node.parentNode.insertBefore(this.node, el.node);
+ this.paper = el.paper;
+ parent && parent.add();
+ el.parent() && el.parent().add();
+ return this;
+ };
+ /*\
+ * Element.insertAfter
+ [ method ]
+ **
+ * Inserts the element after the given one
+ **
+ - el (Element) element next to whom insert to
+ = (Element) the parent element
+ \*/
+ elproto.insertAfter = function (el) {
+ el = wrap(el);
+ var parent = this.parent();
+ el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
+ this.paper = el.paper;
+ parent && parent.add();
+ el.parent() && el.parent().add();
+ return this;
+ };
+ /*\
+ * Element.remove
+ [ method ]
+ **
+ * Removes element from the DOM
+ = (Element) the detached element
+ \*/
+ elproto.remove = function () {
+ var parent = this.parent();
+ this.node.parentNode && this.node.parentNode.removeChild(this.node);
+ delete this.paper;
+ this.removed = true;
+ parent && parent.add();
+ return this;
+ };
+ /*\
+ * Element.select
+ [ method ]
+ **
+ * Gathers the nested @Element matching the given set of CSS selectors
+ **
+ - query (string) CSS selector
+ = (Element) result of query selection
+ \*/
+ elproto.select = function (query) {
+ query = Str(query).replace(/([^\\]):/g, "$1\\:");
+ return wrap(this.node.querySelector(query));
+ };
+ /*\
+ * Element.selectAll
+ [ method ]
+ **
+ * Gathers nested @Element objects matching the given set of CSS selectors
+ **
+ - query (string) CSS selector
+ = (Set|array) result of query selection
+ \*/
+ elproto.selectAll = function (query) {
+ var nodelist = this.node.querySelectorAll(query),
+ set = (Snap.set || Array)();
+ for (var i = 0; i < nodelist.length; i++) {
+ set.push(wrap(nodelist[i]));
+ }
+ return set;
+ };
+ /*\
+ * Element.asPX
+ [ method ]
+ **
+ * Returns given attribute of the element as a `px` value (not %, em, etc.)
+ **
+ - attr (string) attribute name
+ - value (string) #optional attribute value
+ = (Element) result of query selection
+ \*/
+ elproto.asPX = function (attr, value) {
+ if (value == null) {
+ value = this.attr(attr);
+ }
+ return +unit2px(this, attr, value);
+ };
+ // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar.
+ /*\
+ * Element.use
+ [ method ]
+ **
+ * Creates a `<use>` element linked to the current element
+ **
+ = (Element) the `<use>` element
+ \*/
+ elproto.use = function () {
+ var use,
+ id = this.node.id;
+ if (!id) {
+ id = this.id;
+ $(this.node, {
+ id: id
+ });
+ }
+ if (this.type == "linearGradient" || this.type == "radialGradient" ||
+ this.type == "pattern") {
+ use = make(this.type, this.node.parentNode);
+ } else {
+ use = make("use", this.node.parentNode);
+ }
+ $(use.node, {
+ "xlink:href": "#" + id
+ });
+ use.original = this;
+ return use;
+ };
+ function fixids(el) {
+ var els = el.selectAll("*"),
+ it,
+ url = /^\s*url\(("|'|)(.*)\1\)\s*$/,
+ ids = [],
+ uses = {};
+ function urltest(it, name) {
+ var val = $(it.node, name);
+ val = val && val.match(url);
+ val = val && val[2];
+ if (val && val.charAt() == "#") {
+ val = val.substring(1);
+ } else {
+ return;
+ }
+ if (val) {
+ uses[val] = (uses[val] || []).concat(function (id) {
+ var attr = {};
+ attr[name] = URL(id);
+ $(it.node, attr);
+ });
+ }
+ }
+ function linktest(it) {
+ var val = $(it.node, "xlink:href");
+ if (val && val.charAt() == "#") {
+ val = val.substring(1);
+ } else {
+ return;
+ }
+ if (val) {
+ uses[val] = (uses[val] || []).concat(function (id) {
+ it.attr("xlink:href", "#" + id);
+ });
+ }
+ }
+ for (var i = 0, ii = els.length; i < ii; i++) {
+ it = els[i];
+ urltest(it, "fill");
+ urltest(it, "stroke");
+ urltest(it, "filter");
+ urltest(it, "mask");
+ urltest(it, "clip-path");
+ linktest(it);
+ var oldid = $(it.node, "id");
+ if (oldid) {
+ $(it.node, {id: it.id});
+ ids.push({
+ old: oldid,
+ id: it.id
+ });
+ }
+ }
+ for (i = 0, ii = ids.length; i < ii; i++) {
+ var fs = uses[ids[i].old];
+ if (fs) {
+ for (var j = 0, jj = fs.length; j < jj; j++) {
+ fs[j](ids[i].id);
+ }
+ }
+ }
+ }
+ /*\
+ * Element.clone
+ [ method ]
+ **
+ * Creates a clone of the element and inserts it after the element
+ **
+ = (Element) the clone
+ \*/
+ elproto.clone = function () {
+ var clone = wrap(this.node.cloneNode(true));
+ if ($(clone.node, "id")) {
+ $(clone.node, {id: clone.id});
+ }
+ fixids(clone);
+ clone.insertAfter(this);
+ return clone;
+ };
+ /*\
+ * Element.toDefs
+ [ method ]
+ **
+ * Moves element to the shared `<defs>` area
+ **
+ = (Element) the element
+ \*/
+ elproto.toDefs = function () {
+ var defs = getSomeDefs(this);
+ defs.appendChild(this.node);
+ return this;
+ };
+ /*\
+ * Element.toPattern
+ [ method ]
+ **
+ * Creates a `<pattern>` element from the current element
+ **
+ * To create a pattern you have to specify the pattern rect:
+ - x (string|number)
+ - y (string|number)
+ - width (string|number)
+ - height (string|number)
+ = (Element) the `<pattern>` element
+ * You can use pattern later on as an argument for `fill` attribute:
+ | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
+ | fill: "none",
+ | stroke: "#bada55",
+ | strokeWidth: 5
+ | }).pattern(0, 0, 10, 10),
+ | c = paper.circle(200, 200, 100);
+ | c.attr({
+ | fill: p
+ | });
+ \*/
+ elproto.pattern = elproto.toPattern = function (x, y, width, height) {
+ var p = make("pattern", getSomeDefs(this));
+ if (x == null) {
+ x = this.getBBox();
+ }
+ if (is(x, "object") && "x" in x) {
+ y = x.y;
+ width = x.width;
+ height = x.height;
+ x = x.x;
+ }
+ $(p.node, {
+ x: x,
+ y: y,
+ width: width,
+ height: height,
+ patternUnits: "userSpaceOnUse",
+ id: p.id,
+ viewBox: [x, y, width, height].join(" ")
+ });
+ p.node.appendChild(this.node);
+ return p;
+ };
+ // SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path.
+ // SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values?
+ /*\
+ * Element.marker
+ [ method ]
+ **
+ * Creates a `<marker>` element from the current element
+ **
+ * To create a marker you have to specify the bounding rect and reference point:
+ - x (number)
+ - y (number)
+ - width (number)
+ - height (number)
+ - refX (number)
+ - refY (number)
+ = (Element) the `<marker>` element
+ * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end.
+ \*/
+ // TODO add usage for markers
+ elproto.marker = function (x, y, width, height, refX, refY) {
+ var p = make("marker", getSomeDefs(this));
+ if (x == null) {
+ x = this.getBBox();
+ }
+ if (is(x, "object") && "x" in x) {
+ y = x.y;
+ width = x.width;
+ height = x.height;
+ refX = x.refX || x.cx;
+ refY = x.refY || x.cy;
+ x = x.x;
+ }
+ $(p.node, {
+ viewBox: [x, y, width, height].join(" "),
+ markerWidth: width,
+ markerHeight: height,
+ orient: "auto",
+ refX: refX || 0,
+ refY: refY || 0,
+ id: p.id
+ });
+ p.node.appendChild(this.node);
+ return p;
+ };
+ // animation
+ function slice(from, to, f) {
+ return function (arr) {
+ var res = arr.slice(from, to);
+ if (res.length == 1) {
+ res = res[0];
+ }
+ return f ? f(res) : res;
+ };
+ }
+ var Animation = function (attr, ms, easing, callback) {
+ if (typeof easing == "function" && !easing.length) {
+ callback = easing;
+ easing = mina.linear;
+ }
+ this.attr = attr;
+ this.dur = ms;
+ easing && (this.easing = easing);
+ callback && (this.callback = callback);
+ };
+ Snap._.Animation = Animation;
+ /*\
+ * Snap.animation
+ [ method ]
+ **
+ * Creates an animation object
+ **
+ - attr (object) attributes of final destination
+ - duration (number) duration of the animation, in milliseconds
+ - easing (function) #optional one of easing functions of @mina or custom one
+ - callback (function) #optional callback function that fires when animation ends
+ = (object) animation object
+ \*/
+ Snap.animation = function (attr, ms, easing, callback) {
+ return new Animation(attr, ms, easing, callback);
+ };
+ /*\
+ * Element.inAnim
+ [ method ]
+ **
+ * Returns a set of animations that may be able to manipulate the current element
+ **
+ = (object) in format:
+ o {
+ o anim (object) animation object,
+ o mina (object) @mina object,
+ o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
+ o status (function) gets or sets the status of the animation,
+ o stop (function) stops the animation
+ o }
+ \*/
+ elproto.inAnim = function () {
+ var el = this,
+ res = [];
+ for (var id in el.anims) if (el.anims[has](id)) {
+ (function (a) {
+ res.push({
+ anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
+ mina: a,
+ curStatus: a.status(),
+ status: function (val) {
+ return a.status(val);
+ },
+ stop: function () {
+ a.stop();
+ }
+ });
+ }(el.anims[id]));
+ }
+ return res;
+ };
+ /*\
+ * Snap.animate
+ [ method ]
+ **
+ * Runs generic animation of one number into another with a caring function
+ **
+ - from (number|array) number or array of numbers
+ - to (number|array) number or array of numbers
+ - setter (function) caring function that accepts one number argument
+ - duration (number) duration, in milliseconds
+ - easing (function) #optional easing function from @mina or custom
+ - callback (function) #optional callback function to execute when animation ends
+ = (object) animation object in @mina format
+ o {
+ o id (string) animation id, consider it read-only,
+ o duration (function) gets or sets the duration of the animation,
+ o easing (function) easing,
+ o speed (function) gets or sets the speed of the animation,
+ o status (function) gets or sets the status of the animation,
+ o stop (function) stops the animation
+ o }
+ | var rect = Snap().rect(0, 0, 10, 10);
+ | Snap.animate(0, 10, function (val) {
+ | rect.attr({
+ | x: val
+ | });
+ | }, 1000);
+ | // in given context is equivalent to
+ | rect.animate({x: 10}, 1000);
+ \*/
+ Snap.animate = function (from, to, setter, ms, easing, callback) {
+ if (typeof easing == "function" && !easing.length) {
+ callback = easing;
+ easing = mina.linear;
+ }
+ var now = mina.time(),
+ anim = mina(from, to, now, now + ms, mina.time, setter, easing);
+ callback && eve.once("mina.finish." + anim.id, callback);
+ return anim;
+ };
+ /*\
+ * Element.stop
+ [ method ]
+ **
+ * Stops all the animations for the current element
+ **
+ = (Element) the current element
+ \*/
+ elproto.stop = function () {
+ var anims = this.inAnim();
+ for (var i = 0, ii = anims.length; i < ii; i++) {
+ anims[i].stop();
+ }
+ return this;
+ };
+ /*\
+ * Element.animate
+ [ method ]
+ **
+ * Animates the given attributes of the element
+ **
+ - attrs (object) key-value pairs of destination attributes
+ - duration (number) duration of the animation in milliseconds
+ - easing (function) #optional easing function from @mina or custom
+ - callback (function) #optional callback function that executes when the animation ends
+ = (Element) the current element
+ \*/
+ elproto.animate = function (attrs, ms, easing, callback) {
+ if (typeof easing == "function" && !easing.length) {
+ callback = easing;
+ easing = mina.linear;
+ }
+ if (attrs instanceof Animation) {
+ callback = attrs.callback;
+ easing = attrs.easing;
+ ms = easing.dur;
+ attrs = attrs.attr;
+ }
+ var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
+ el = this;
+ for (var key in attrs) if (attrs[has](key)) {
+ if (el.equal) {
+ eq = el.equal(key, Str(attrs[key]));
+ from = eq.from;
+ to = eq.to;
+ f = eq.f;
+ } else {
+ from = +el.attr(key);
+ to = +attrs[key];
+ }
+ var len = is(from, "array") ? from.length : 1;
+ keys[key] = slice(fkeys.length, fkeys.length + len, f);
+ fkeys = fkeys.concat(from);
+ tkeys = tkeys.concat(to);
+ }
+ var now = mina.time(),
+ anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
+ var attr = {};
+ for (var key in keys) if (keys[has](key)) {
+ attr[key] = keys[key](val);
+ }
+ el.attr(attr);
+ }, easing);
+ el.anims[anim.id] = anim;
+ anim._attrs = attrs;
+ anim._callback = callback;
+ eve("snap.animcreated." + el.id, anim);
+ eve.once("mina.finish." + anim.id, function () {
+ delete el.anims[anim.id];
+ callback && callback.call(el);
+ });
+ eve.once("mina.stop." + anim.id, function () {
+ delete el.anims[anim.id];
+ });
+ return el;
+ };
+ var eldata = {};
+ /*\
+ * Element.data
+ [ method ]
+ **
+ * Adds or retrieves given value associated with given key. (Don’t confuse
+ * with `data-` attributes)
+ *
+ * See also @Element.removeData
+ - key (string) key to store data
+ - value (any) #optional value to store
+ = (object) @Element
+ * or, if value is not specified:
+ = (any) value
+ > Usage
+ | for (var i = 0, i < 5, i++) {
+ | paper.circle(10 + 15 * i, 10, 10)
+ | .attr({fill: "#000"})
+ | .data("i", i)
+ | .click(function () {
+ | alert(this.data("i"));
+ | });
+ | }
+ \*/
+ elproto.data = function (key, value) {
+ var data = eldata[this.id] = eldata[this.id] || {};
+ if (arguments.length == 0){
+ eve("snap.data.get." + this.id, this, data, null);
+ return data;
+ }
+ if (arguments.length == 1) {
+ if (Snap.is(key, "object")) {
+ for (var i in key) if (key[has](i)) {
+ this.data(i, key[i]);
+ }
+ return this;
+ }
+ eve("snap.data.get." + this.id, this, data[key], key);
+ return data[key];
+ }
+ data[key] = value;
+ eve("snap.data.set." + this.id, this, value, key);
+ return this;
+ };
+ /*\
+ * Element.removeData
+ [ method ]
+ **
+ * Removes value associated with an element by given key.
+ * If key is not provided, removes all the data of the element.
+ - key (string) #optional key
+ = (object) @Element
+ \*/
+ elproto.removeData = function (key) {
+ if (key == null) {
+ eldata[this.id] = {};
+ } else {
+ eldata[this.id] && delete eldata[this.id][key];
+ }
+ return this;
+ };
+ /*\
+ * Element.outerSVG
+ [ method ]
+ **
+ * Returns SVG code for the element, equivalent to HTML's `outerHTML`.
+ *
+ * See also @Element.innerSVG
+ = (string) SVG code for the element
+ \*/
+ /*\
+ * Element.toString
+ [ method ]
+ **
+ * See @Element.outerSVG
+ \*/
+ elproto.outerSVG = elproto.toString = toString(1);
+ /*\
+ * Element.innerSVG
+ [ method ]
+ **
+ * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML`
+ = (string) SVG code for the element
+ \*/
+ elproto.innerSVG = toString();
+ function toString(type) {
+ return function () {
+ var res = type ? "<" + this.type : "",
+ attr = this.node.attributes,
+ chld = this.node.childNodes;
+ if (type) {
+ for (var i = 0, ii = attr.length; i < ii; i++) {
+ res += " " + attr[i].name + '="' +
+ attr[i].value.replace(/"/g, '\\"') + '"';
+ }
+ }
+ if (chld.length) {
+ type && (res += ">");
+ for (i = 0, ii = chld.length; i < ii; i++) {
+ if (chld[i].nodeType == 3) {
+ res += chld[i].nodeValue;
+ } else if (chld[i].nodeType == 1) {
+ res += wrap(chld[i]).toString();
+ }
+ }
+ type && (res += "</" + this.type + ">");
+ } else {
+ type && (res += "/>");
+ }
+ return res;
+ };
+ }
+ elproto.toDataURL = function () {
+ if (window && window.btoa) {
+ var bb = this.getBBox(),
+ svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', {
+ x: +bb.x.toFixed(3),
+ y: +bb.y.toFixed(3),
+ width: +bb.width.toFixed(3),
+ height: +bb.height.toFixed(3),
+ contents: this.outerSVG()
+ });
+ return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg)));
+ }
+ };
+ /*\
+ * Fragment.select
+ [ method ]
+ **
+ * See @Element.select
+ \*/
+ Fragment.prototype.select = elproto.select;
+ /*\
+ * Fragment.selectAll
+ [ method ]
+ **
+ * See @Element.selectAll
+ \*/
+ Fragment.prototype.selectAll = elproto.selectAll;
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var objectToString = Object.prototype.toString,
+ Str = String,
+ math = Math,
+ E = "";
+ function Matrix(a, b, c, d, e, f) {
+ if (b == null && objectToString.call(a) == "[object SVGMatrix]") {
+ this.a = a.a;
+ this.b = a.b;
+ this.c = a.c;
+ this.d = a.d;
+ this.e = a.e;
+ this.f = a.f;
+ return;
+ }
+ if (a != null) {
+ this.a = +a;
+ this.b = +b;
+ this.c = +c;
+ this.d = +d;
+ this.e = +e;
+ this.f = +f;
+ } else {
+ this.a = 1;
+ this.b = 0;
+ this.c = 0;
+ this.d = 1;
+ this.e = 0;
+ this.f = 0;
+ }
+ }
+ (function (matrixproto) {
+ /*\
+ * Matrix.add
+ [ method ]
+ **
+ * Adds the given matrix to existing one
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ * or
+ - matrix (object) @Matrix
+ \*/
+ matrixproto.add = function (a, b, c, d, e, f) {
+ var out = [[], [], []],
+ m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
+ matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
+ x, y, z, res;
+
+ if (a && a instanceof Matrix) {
+ matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
+ }
+
+ for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++) {
+ res = 0;
+ for (z = 0; z < 3; z++) {
+ res += m[x][z] * matrix[z][y];
+ }
+ out[x][y] = res;
+ }
+ }
+ this.a = out[0][0];
+ this.b = out[1][0];
+ this.c = out[0][1];
+ this.d = out[1][1];
+ this.e = out[0][2];
+ this.f = out[1][2];
+ return this;
+ };
+ /*\
+ * Matrix.invert
+ [ method ]
+ **
+ * Returns an inverted version of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.invert = function () {
+ var me = this,
+ x = me.a * me.d - me.b * me.c;
+ return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
+ };
+ /*\
+ * Matrix.clone
+ [ method ]
+ **
+ * Returns a copy of the matrix
+ = (object) @Matrix
+ \*/
+ matrixproto.clone = function () {
+ return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
+ };
+ /*\
+ * Matrix.translate
+ [ method ]
+ **
+ * Translate the matrix
+ - x (number) horizontal offset distance
+ - y (number) vertical offset distance
+ \*/
+ matrixproto.translate = function (x, y) {
+ return this.add(1, 0, 0, 1, x, y);
+ };
+ /*\
+ * Matrix.scale
+ [ method ]
+ **
+ * Scales the matrix
+ - x (number) amount to be scaled, with `1` resulting in no change
+ - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.)
+ - cx (number) #optional horizontal origin point from which to scale
+ - cy (number) #optional vertical origin point from which to scale
+ * Default cx, cy is the middle point of the element.
+ \*/
+ matrixproto.scale = function (x, y, cx, cy) {
+ y == null && (y = x);
+ (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
+ this.add(x, 0, 0, y, 0, 0);
+ (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
+ return this;
+ };
+ /*\
+ * Matrix.rotate
+ [ method ]
+ **
+ * Rotates the matrix
+ - a (number) angle of rotation, in degrees
+ - x (number) horizontal origin point from which to rotate
+ - y (number) vertical origin point from which to rotate
+ \*/
+ matrixproto.rotate = function (a, x, y) {
+ a = Snap.rad(a);
+ x = x || 0;
+ y = y || 0;
+ var cos = +math.cos(a).toFixed(9),
+ sin = +math.sin(a).toFixed(9);
+ this.add(cos, sin, -sin, cos, x, y);
+ return this.add(1, 0, 0, 1, -x, -y);
+ };
+ /*\
+ * Matrix.x
+ [ method ]
+ **
+ * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y
+ - x (number)
+ - y (number)
+ = (number) x
+ \*/
+ matrixproto.x = function (x, y) {
+ return x * this.a + y * this.c + this.e;
+ };
+ /*\
+ * Matrix.y
+ [ method ]
+ **
+ * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x
+ - x (number)
+ - y (number)
+ = (number) y
+ \*/
+ matrixproto.y = function (x, y) {
+ return x * this.b + y * this.d + this.f;
+ };
+ matrixproto.get = function (i) {
+ return +this[Str.fromCharCode(97 + i)].toFixed(4);
+ };
+ matrixproto.toString = function () {
+ return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
+ };
+ matrixproto.offset = function () {
+ return [this.e.toFixed(4), this.f.toFixed(4)];
+ };
+ function norm(a) {
+ return a[0] * a[0] + a[1] * a[1];
+ }
+ function normalize(a) {
+ var mag = math.sqrt(norm(a));
+ a[0] && (a[0] /= mag);
+ a[1] && (a[1] /= mag);
+ }
+ /*\
+ * Matrix.determinant
+ [ method ]
+ **
+ * Finds determinant of the given matrix.
+ = (number) determinant
+ \*/
+ matrixproto.determinant = function () {
+ return this.a * this.d - this.b * this.c;
+ };
+ /*\
+ * Matrix.split
+ [ method ]
+ **
+ * Splits matrix into primitive transformations
+ = (object) in format:
+ o dx (number) translation by x
+ o dy (number) translation by y
+ o scalex (number) scale by x
+ o scaley (number) scale by y
+ o shear (number) shear
+ o rotate (number) rotation in deg
+ o isSimple (boolean) could it be represented via simple transformations
+ \*/
+ matrixproto.split = function () {
+ var out = {};
+ // translation
+ out.dx = this.e;
+ out.dy = this.f;
+
+ // scale and shear
+ var row = [[this.a, this.c], [this.b, this.d]];
+ out.scalex = math.sqrt(norm(row[0]));
+ normalize(row[0]);
+
+ out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
+ row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
+
+ out.scaley = math.sqrt(norm(row[1]));
+ normalize(row[1]);
+ out.shear /= out.scaley;
+
+ if (this.determinant() < 0) {
+ out.scalex = -out.scalex;
+ }
+
+ // rotation
+ var sin = -row[0][1],
+ cos = row[1][1];
+ if (cos < 0) {
+ out.rotate = Snap.deg(math.acos(cos));
+ if (sin < 0) {
+ out.rotate = 360 - out.rotate;
+ }
+ } else {
+ out.rotate = Snap.deg(math.asin(sin));
+ }
+
+ out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
+ out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
+ out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
+ return out;
+ };
+ /*\
+ * Matrix.toTransformString
+ [ method ]
+ **
+ * Returns transform string that represents given matrix
+ = (string) transform string
+ \*/
+ matrixproto.toTransformString = function (shorter) {
+ var s = shorter || this.split();
+ if (!+s.shear.toFixed(9)) {
+ s.scalex = +s.scalex.toFixed(4);
+ s.scaley = +s.scaley.toFixed(4);
+ s.rotate = +s.rotate.toFixed(4);
+ return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) +
+ (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
+ (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E);
+ } else {
+ return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
+ }
+ };
+ })(Matrix.prototype);
+ /*\
+ * Snap.Matrix
+ [ method ]
+ **
+ * Matrix constructor, extend on your own risk.
+ * To create matrices use @Snap.matrix.
+ \*/
+ Snap.Matrix = Matrix;
+ /*\
+ * Snap.matrix
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns a matrix based on the given parameters
+ - a (number)
+ - b (number)
+ - c (number)
+ - d (number)
+ - e (number)
+ - f (number)
+ * or
+ - svgMatrix (SVGMatrix)
+ = (object) @Matrix
+ \*/
+ Snap.matrix = function (a, b, c, d, e, f) {
+ return new Matrix(a, b, c, d, e, f);
+ };
+ });
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var has = "hasOwnProperty",
+ make = Snap._.make,
+ wrap = Snap._.wrap,
+ is = Snap.is,
+ getSomeDefs = Snap._.getSomeDefs,
+ reURLValue = /^url\(#?([^)]+)\)$/,
+ $ = Snap._.$,
+ URL = Snap.url,
+ Str = String,
+ separator = Snap._.separator,
+ E = "";
+ // Attributes event handlers
+ eve.on("snap.util.attr.mask", function (value) {
+ if (value instanceof Element || value instanceof Fragment) {
+ eve.stop();
+ if (value instanceof Fragment && value.node.childNodes.length == 1) {
+ value = value.node.firstChild;
+ getSomeDefs(this).appendChild(value);
+ value = wrap(value);
+ }
+ if (value.type == "mask") {
+ var mask = value;
+ } else {
+ mask = make("mask", getSomeDefs(this));
+ mask.node.appendChild(value.node);
+ }
+ !mask.node.id && $(mask.node, {
+ id: mask.id
+ });
+ $(this.node, {
+ mask: URL(mask.id)
+ });
+ }
+ });
+ (function (clipIt) {
+ eve.on("snap.util.attr.clip", clipIt);
+ eve.on("snap.util.attr.clip-path", clipIt);
+ eve.on("snap.util.attr.clipPath", clipIt);
+ }(function (value) {
+ if (value instanceof Element || value instanceof Fragment) {
+ eve.stop();
+ if (value.type == "clipPath") {
+ var clip = value;
+ } else {
+ clip = make("clipPath", getSomeDefs(this));
+ clip.node.appendChild(value.node);
+ !clip.node.id && $(clip.node, {
+ id: clip.id
+ });
+ }
+ $(this.node, {
+ "clip-path": URL(clip.node.id || clip.id)
+ });
+ }
+ }));
+ function fillStroke(name) {
+ return function (value) {
+ eve.stop();
+ if (value instanceof Fragment && value.node.childNodes.length == 1 &&
+ (value.node.firstChild.tagName == "radialGradient" ||
+ value.node.firstChild.tagName == "linearGradient" ||
+ value.node.firstChild.tagName == "pattern")) {
+ value = value.node.firstChild;
+ getSomeDefs(this).appendChild(value);
+ value = wrap(value);
+ }
+ if (value instanceof Element) {
+ if (value.type == "radialGradient" || value.type == "linearGradient"
+ || value.type == "pattern") {
+ if (!value.node.id) {
+ $(value.node, {
+ id: value.id
+ });
+ }
+ var fill = URL(value.node.id);
+ } else {
+ fill = value.attr(name);
+ }
+ } else {
+ fill = Snap.color(value);
+ if (fill.error) {
+ var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value);
+ if (grad) {
+ if (!grad.node.id) {
+ $(grad.node, {
+ id: grad.id
+ });
+ }
+ fill = URL(grad.node.id);
+ } else {
+ fill = value;
+ }
+ } else {
+ fill = Str(fill);
+ }
+ }
+ var attrs = {};
+ attrs[name] = fill;
+ $(this.node, attrs);
+ this.node.style[name] = E;
+ };
+ }
+ eve.on("snap.util.attr.fill", fillStroke("fill"));
+ eve.on("snap.util.attr.stroke", fillStroke("stroke"));
+ var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i;
+ eve.on("snap.util.grad.parse", function parseGrad(string) {
+ string = Str(string);
+ var tokens = string.match(gradrg);
+ if (!tokens) {
+ return null;
+ }
+ var type = tokens[1],
+ params = tokens[2],
+ stops = tokens[3];
+ params = params.split(/\s*,\s*/).map(function (el) {
+ return +el == el ? +el : el;
+ });
+ if (params.length == 1 && params[0] == 0) {
+ params = [];
+ }
+ stops = stops.split("-");
+ stops = stops.map(function (el) {
+ el = el.split(":");
+ var out = {
+ color: el[0]
+ };
+ if (el[1]) {
+ out.offset = parseFloat(el[1]);
+ }
+ return out;
+ });
+ return {
+ type: type,
+ params: params,
+ stops: stops
+ };
+ });
+
+ eve.on("snap.util.attr.d", function (value) {
+ eve.stop();
+ if (is(value, "array") && is(value[0], "array")) {
+ value = Snap.path.toString.call(value);
+ }
+ value = Str(value);
+ if (value.match(/[ruo]/i)) {
+ value = Snap.path.toAbsolute(value);
+ }
+ $(this.node, {d: value});
+ })(-1);
+ eve.on("snap.util.attr.#text", function (value) {
+ eve.stop();
+ value = Str(value);
+ var txt = glob.doc.createTextNode(value);
+ while (this.node.firstChild) {
+ this.node.removeChild(this.node.firstChild);
+ }
+ this.node.appendChild(txt);
+ })(-1);
+ eve.on("snap.util.attr.path", function (value) {
+ eve.stop();
+ this.attr({d: value});
+ })(-1);
+ eve.on("snap.util.attr.class", function (value) {
+ eve.stop();
+ this.node.className.baseVal = value;
+ })(-1);
+ eve.on("snap.util.attr.viewBox", function (value) {
+ var vb;
+ if (is(value, "object") && "x" in value) {
+ vb = [value.x, value.y, value.width, value.height].join(" ");
+ } else if (is(value, "array")) {
+ vb = value.join(" ");
+ } else {
+ vb = value;
+ }
+ $(this.node, {
+ viewBox: vb
+ });
+ eve.stop();
+ })(-1);
+ eve.on("snap.util.attr.transform", function (value) {
+ this.transform(value);
+ eve.stop();
+ })(-1);
+ eve.on("snap.util.attr.r", function (value) {
+ if (this.type == "rect") {
+ eve.stop();
+ $(this.node, {
+ rx: value,
+ ry: value
+ });
+ }
+ })(-1);
+ eve.on("snap.util.attr.textpath", function (value) {
+ eve.stop();
+ if (this.type == "text") {
+ var id, tp, node;
+ if (!value && this.textPath) {
+ tp = this.textPath;
+ while (tp.node.firstChild) {
+ this.node.appendChild(tp.node.firstChild);
+ }
+ tp.remove();
+ delete this.textPath;
+ return;
+ }
+ if (is(value, "string")) {
+ var defs = getSomeDefs(this),
+ path = wrap(defs.parentNode).path(value);
+ defs.appendChild(path.node);
+ id = path.id;
+ path.attr({id: id});
+ } else {
+ value = wrap(value);
+ if (value instanceof Element) {
+ id = value.attr("id");
+ if (!id) {
+ id = value.id;
+ value.attr({id: id});
+ }
+ }
+ }
+ if (id) {
+ tp = this.textPath;
+ node = this.node;
+ if (tp) {
+ tp.attr({"xlink:href": "#" + id});
+ } else {
+ tp = $("textPath", {
+ "xlink:href": "#" + id
+ });
+ while (node.firstChild) {
+ tp.appendChild(node.firstChild);
+ }
+ node.appendChild(tp);
+ this.textPath = wrap(tp);
+ }
+ }
+ }
+ })(-1);
+ eve.on("snap.util.attr.text", function (value) {
+ if (this.type == "text") {
+ var i = 0,
+ node = this.node,
+ tuner = function (chunk) {
+ var out = $("tspan");
+ if (is(chunk, "array")) {
+ for (var i = 0; i < chunk.length; i++) {
+ out.appendChild(tuner(chunk[i]));
+ }
+ } else {
+ out.appendChild(glob.doc.createTextNode(chunk));
+ }
+ out.normalize && out.normalize();
+ return out;
+ };
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ var tuned = tuner(value);
+ while (tuned.firstChild) {
+ node.appendChild(tuned.firstChild);
+ }
+ }
+ eve.stop();
+ })(-1);
+ function setFontSize(value) {
+ eve.stop();
+ if (value == +value) {
+ value += "px";
+ }
+ this.node.style.fontSize = value;
+ }
+ eve.on("snap.util.attr.fontSize", setFontSize)(-1);
+ eve.on("snap.util.attr.font-size", setFontSize)(-1);
+
+
+ eve.on("snap.util.getattr.transform", function () {
+ eve.stop();
+ return this.transform();
+ })(-1);
+ eve.on("snap.util.getattr.textpath", function () {
+ eve.stop();
+ return this.textPath;
+ })(-1);
+ // Markers
+ (function () {
+ function getter(end) {
+ return function () {
+ eve.stop();
+ var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end);
+ if (style == "none") {
+ return style;
+ } else {
+ return Snap(glob.doc.getElementById(style.match(reURLValue)[1]));
+ }
+ };
+ }
+ function setter(end) {
+ return function (value) {
+ eve.stop();
+ var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1);
+ if (value == "" || !value) {
+ this.node.style[name] = "none";
+ return;
+ }
+ if (value.type == "marker") {
+ var id = value.node.id;
+ if (!id) {
+ $(value.node, {id: value.id});
+ }
+ this.node.style[name] = URL(id);
+ return;
+ }
+ };
+ }
+ eve.on("snap.util.getattr.marker-end", getter("end"))(-1);
+ eve.on("snap.util.getattr.markerEnd", getter("end"))(-1);
+ eve.on("snap.util.getattr.marker-start", getter("start"))(-1);
+ eve.on("snap.util.getattr.markerStart", getter("start"))(-1);
+ eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1);
+ eve.on("snap.util.getattr.markerMid", getter("mid"))(-1);
+ eve.on("snap.util.attr.marker-end", setter("end"))(-1);
+ eve.on("snap.util.attr.markerEnd", setter("end"))(-1);
+ eve.on("snap.util.attr.marker-start", setter("start"))(-1);
+ eve.on("snap.util.attr.markerStart", setter("start"))(-1);
+ eve.on("snap.util.attr.marker-mid", setter("mid"))(-1);
+ eve.on("snap.util.attr.markerMid", setter("mid"))(-1);
+ }());
+ eve.on("snap.util.getattr.r", function () {
+ if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) {
+ eve.stop();
+ return $(this.node, "rx");
+ }
+ })(-1);
+ function textExtract(node) {
+ var out = [];
+ var children = node.childNodes;
+ for (var i = 0, ii = children.length; i < ii; i++) {
+ var chi = children[i];
+ if (chi.nodeType == 3) {
+ out.push(chi.nodeValue);
+ }
+ if (chi.tagName == "tspan") {
+ if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) {
+ out.push(chi.firstChild.nodeValue);
+ } else {
+ out.push(textExtract(chi));
+ }
+ }
+ }
+ return out;
+ }
+ eve.on("snap.util.getattr.text", function () {
+ if (this.type == "text" || this.type == "tspan") {
+ eve.stop();
+ var out = textExtract(this.node);
+ return out.length == 1 ? out[0] : out;
+ }
+ })(-1);
+ eve.on("snap.util.getattr.#text", function () {
+ return this.node.textContent;
+ })(-1);
+ eve.on("snap.util.getattr.viewBox", function () {
+ eve.stop();
+ var vb = $(this.node, "viewBox");
+ if (vb) {
+ vb = vb.split(separator);
+ return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]);
+ } else {
+ return;
+ }
+ })(-1);
+ eve.on("snap.util.getattr.points", function () {
+ var p = $(this.node, "points");
+ eve.stop();
+ if (p) {
+ return p.split(separator);
+ } else {
+ return;
+ }
+ })(-1);
+ eve.on("snap.util.getattr.path", function () {
+ var p = $(this.node, "d");
+ eve.stop();
+ return p;
+ })(-1);
+ eve.on("snap.util.getattr.class", function () {
+ return this.node.className.baseVal;
+ })(-1);
+ function getFontSize() {
+ eve.stop();
+ return this.node.style.fontSize;
+ }
+ eve.on("snap.util.getattr.fontSize", getFontSize)(-1);
+ eve.on("snap.util.getattr.font-size", getFontSize)(-1);
+ });
+
+ // Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var rgNotSpace = /\S+/g,
+ rgBadSpace = /[\t\r\n\f]/g,
+ rgTrim = /(^\s+|\s+$)/g,
+ Str = String,
+ elproto = Element.prototype;
+ /*\
+ * Element.addClass
+ [ method ]
+ **
+ * Adds given class name or list of class names to the element.
+ - value (string) class name or space separated list of class names
+ **
+ = (Element) original element.
+ \*/
+ elproto.addClass = function (value) {
+ var classes = Str(value || "").match(rgNotSpace) || [],
+ elem = this.node,
+ className = elem.className.baseVal,
+ curClasses = className.match(rgNotSpace) || [],
+ j,
+ pos,
+ clazz,
+ finalValue;
+
+ if (classes.length) {
+ j = 0;
+ while ((clazz = classes[j++])) {
+ pos = curClasses.indexOf(clazz);
+ if (!~pos) {
+ curClasses.push(clazz);
+ }
+ }
+
+ finalValue = curClasses.join(" ");
+ if (className != finalValue) {
+ elem.className.baseVal = finalValue;
+ }
+ }
+ return this;
+ };
+ /*\
+ * Element.removeClass
+ [ method ]
+ **
+ * Removes given class name or list of class names from the element.
+ - value (string) class name or space separated list of class names
+ **
+ = (Element) original element.
+ \*/
+ elproto.removeClass = function (value) {
+ var classes = Str(value || "").match(rgNotSpace) || [],
+ elem = this.node,
+ className = elem.className.baseVal,
+ curClasses = className.match(rgNotSpace) || [],
+ j,
+ pos,
+ clazz,
+ finalValue;
+ if (curClasses.length) {
+ j = 0;
+ while ((clazz = classes[j++])) {
+ pos = curClasses.indexOf(clazz);
+ if (~pos) {
+ curClasses.splice(pos, 1);
+ }
+ }
+
+ finalValue = curClasses.join(" ");
+ if (className != finalValue) {
+ elem.className.baseVal = finalValue;
+ }
+ }
+ return this;
+ };
+ /*\
+ * Element.hasClass
+ [ method ]
+ **
+ * Checks if the element has a given class name in the list of class names applied to it.
+ - value (string) class name
+ **
+ = (boolean) `true` if the element has given class
+ \*/
+ elproto.hasClass = function (value) {
+ var elem = this.node,
+ className = elem.className.baseVal,
+ curClasses = className.match(rgNotSpace) || [];
+ return !!~curClasses.indexOf(value);
+ };
+ /*\
+ * Element.toggleClass
+ [ method ]
+ **
+ * Add or remove one or more classes from the element, depending on either
+ * the class’s presence or the value of the `flag` argument.
+ - value (string) class name or space separated list of class names
+ - flag (boolean) value to determine whether the class should be added or removed
+ **
+ = (Element) original element.
+ \*/
+ elproto.toggleClass = function (value, flag) {
+ if (flag != null) {
+ if (flag) {
+ return this.addClass(value);
+ } else {
+ return this.removeClass(value);
+ }
+ }
+ var classes = (value || "").match(rgNotSpace) || [],
+ elem = this.node,
+ className = elem.className.baseVal,
+ curClasses = className.match(rgNotSpace) || [],
+ j,
+ pos,
+ clazz,
+ finalValue;
+ j = 0;
+ while ((clazz = classes[j++])) {
+ pos = curClasses.indexOf(clazz);
+ if (~pos) {
+ curClasses.splice(pos, 1);
+ } else {
+ curClasses.push(clazz);
+ }
+ }
+
+ finalValue = curClasses.join(" ");
+ if (className != finalValue) {
+ elem.className.baseVal = finalValue;
+ }
+ return this;
+ };
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var operators = {
+ "+": function (x, y) {
+ return x + y;
+ },
+ "-": function (x, y) {
+ return x - y;
+ },
+ "/": function (x, y) {
+ return x / y;
+ },
+ "*": function (x, y) {
+ return x * y;
+ }
+ },
+ Str = String,
+ reUnit = /[a-z]+$/i,
+ reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;
+ function getNumber(val) {
+ return val;
+ }
+ function getUnit(unit) {
+ return function (val) {
+ return +val.toFixed(3) + unit;
+ };
+ }
+ eve.on("snap.util.attr", function (val) {
+ var plus = Str(val).match(reAddon);
+ if (plus) {
+ var evnt = eve.nt(),
+ name = evnt.substring(evnt.lastIndexOf(".") + 1),
+ a = this.attr(name),
+ atr = {};
+ eve.stop();
+ var unit = plus[3] || "",
+ aUnit = a.match(reUnit),
+ op = operators[plus[1]];
+ if (aUnit && aUnit == unit) {
+ val = op(parseFloat(a), +plus[2]);
+ } else {
+ a = this.asPX(name);
+ val = op(this.asPX(name), this.asPX(name, plus[2] + unit));
+ }
+ if (isNaN(a) || isNaN(val)) {
+ return;
+ }
+ atr[name] = val;
+ this.attr(atr);
+ }
+ })(-10);
+ eve.on("snap.util.equal", function (name, b) {
+ var A, B, a = Str(this.attr(name) || ""),
+ el = this,
+ bplus = Str(b).match(reAddon);
+ if (bplus) {
+ eve.stop();
+ var unit = bplus[3] || "",
+ aUnit = a.match(reUnit),
+ op = operators[bplus[1]];
+ if (aUnit && aUnit == unit) {
+ return {
+ from: parseFloat(a),
+ to: op(parseFloat(a), +bplus[2]),
+ f: getUnit(aUnit)
+ };
+ } else {
+ a = this.asPX(name);
+ return {
+ from: a,
+ to: op(a, this.asPX(name, bplus[2] + unit)),
+ f: getNumber
+ };
+ }
+ }
+ })(-10);
+ });
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var proto = Paper.prototype,
+ is = Snap.is;
+ /*\
+ * Paper.rect
+ [ method ]
+ *
+ * Draws a rectangle
+ **
+ - x (number) x coordinate of the top left corner
+ - y (number) y coordinate of the top left corner
+ - width (number) width
+ - height (number) height
+ - rx (number) #optional horizontal radius for rounded corners, default is 0
+ - ry (number) #optional vertical radius for rounded corners, default is rx or 0
+ = (object) the `rect` element
+ **
+ > Usage
+ | // regular rectangle
+ | var c = paper.rect(10, 10, 50, 50);
+ | // rectangle with rounded corners
+ | var c = paper.rect(40, 40, 50, 50, 10);
+ \*/
+ proto.rect = function (x, y, w, h, rx, ry) {
+ var attr;
+ if (ry == null) {
+ ry = rx;
+ }
+ if (is(x, "object") && x == "[object Object]") {
+ attr = x;
+ } else if (x != null) {
+ attr = {
+ x: x,
+ y: y,
+ width: w,
+ height: h
+ };
+ if (rx != null) {
+ attr.rx = rx;
+ attr.ry = ry;
+ }
+ }
+ return this.el("rect", attr);
+ };
+ /*\
+ * Paper.circle
+ [ method ]
+ **
+ * Draws a circle
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - r (number) radius
+ = (object) the `circle` element
+ **
+ > Usage
+ | var c = paper.circle(50, 50, 40);
+ \*/
+ proto.circle = function (cx, cy, r) {
+ var attr;
+ if (is(cx, "object") && cx == "[object Object]") {
+ attr = cx;
+ } else if (cx != null) {
+ attr = {
+ cx: cx,
+ cy: cy,
+ r: r
+ };
+ }
+ return this.el("circle", attr);
+ };
+
+ var preload = (function () {
+ function onerror() {
+ this.parentNode.removeChild(this);
+ }
+ return function (src, f) {
+ var img = glob.doc.createElement("img"),
+ body = glob.doc.body;
+ img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
+ img.onload = function () {
+ f.call(img);
+ img.onload = img.onerror = null;
+ body.removeChild(img);
+ };
+ img.onerror = onerror;
+ body.appendChild(img);
+ img.src = src;
+ };
+ }());
+
+ /*\
+ * Paper.image
+ [ method ]
+ **
+ * Places an image on the surface
+ **
+ - src (string) URI of the source image
+ - x (number) x offset position
+ - y (number) y offset position
+ - width (number) width of the image
+ - height (number) height of the image
+ = (object) the `image` element
+ * or
+ = (object) Snap element object with type `image`
+ **
+ > Usage
+ | var c = paper.image("apple.png", 10, 10, 80, 80);
+ \*/
+ proto.image = function (src, x, y, width, height) {
+ var el = this.el("image");
+ if (is(src, "object") && "src" in src) {
+ el.attr(src);
+ } else if (src != null) {
+ var set = {
+ "xlink:href": src,
+ preserveAspectRatio: "none"
+ };
+ if (x != null && y != null) {
+ set.x = x;
+ set.y = y;
+ }
+ if (width != null && height != null) {
+ set.width = width;
+ set.height = height;
+ } else {
+ preload(src, function () {
+ Snap._.$(el.node, {
+ width: this.offsetWidth,
+ height: this.offsetHeight
+ });
+ });
+ }
+ Snap._.$(el.node, set);
+ }
+ return el;
+ };
+ /*\
+ * Paper.ellipse
+ [ method ]
+ **
+ * Draws an ellipse
+ **
+ - x (number) x coordinate of the centre
+ - y (number) y coordinate of the centre
+ - rx (number) horizontal radius
+ - ry (number) vertical radius
+ = (object) the `ellipse` element
+ **
+ > Usage
+ | var c = paper.ellipse(50, 50, 40, 20);
+ \*/
+ proto.ellipse = function (cx, cy, rx, ry) {
+ var attr;
+ if (is(cx, "object") && cx == "[object Object]") {
+ attr = cx;
+ } else if (cx != null) {
+ attr ={
+ cx: cx,
+ cy: cy,
+ rx: rx,
+ ry: ry
+ };
+ }
+ return this.el("ellipse", attr);
+ };
+ // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier.
+ /*\
+ * Paper.path
+ [ method ]
+ **
+ * Creates a `<path>` element using the given string as the path's definition
+ - pathString (string) #optional path string in SVG format
+ * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example:
+ | "M10,20L30,40"
+ * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates.
+ *
+ # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p>
+ # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
+ # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
+ # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
+ # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
+ # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
+ # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
+ # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
+ # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
+ # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
+ # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
+ # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
+ # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
+ * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier.
+ * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point.
+ > Usage
+ | var c = paper.path("M10 10L90 90");
+ | // draw a diagonal line:
+ | // move to 10,10, line to 90,90
+ \*/
+ proto.path = function (d) {
+ var attr;
+ if (is(d, "object") && !is(d, "array")) {
+ attr = d;
+ } else if (d) {
+ attr = {d: d};
+ }
+ return this.el("path", attr);
+ };
+ /*\
+ * Paper.g
+ [ method ]
+ **
+ * Creates a group element
+ **
+ - varargs (…) #optional elements to nest within the group
+ = (object) the `g` element
+ **
+ > Usage
+ | var c1 = paper.circle(),
+ | c2 = paper.rect(),
+ | g = paper.g(c2, c1); // note that the order of elements is different
+ * or
+ | var c1 = paper.circle(),
+ | c2 = paper.rect(),
+ | g = paper.g();
+ | g.add(c2, c1);
+ \*/
+ /*\
+ * Paper.group
+ [ method ]
+ **
+ * See @Paper.g
+ \*/
+ proto.group = proto.g = function (first) {
+ var attr,
+ el = this.el("g");
+ if (arguments.length == 1 && first && !first.type) {
+ el.attr(first);
+ } else if (arguments.length) {
+ el.add(Array.prototype.slice.call(arguments, 0));
+ }
+ return el;
+ };
+ /*\
+ * Paper.svg
+ [ method ]
+ **
+ * Creates a nested SVG element.
+ - x (number) @optional X of the element
+ - y (number) @optional Y of the element
+ - width (number) @optional width of the element
+ - height (number) @optional height of the element
+ - vbx (number) @optional viewbox X
+ - vby (number) @optional viewbox Y
+ - vbw (number) @optional viewbox width
+ - vbh (number) @optional viewbox height
+ **
+ = (object) the `svg` element
+ **
+ \*/
+ proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) {
+ var attrs = {};
+ if (is(x, "object") && y == null) {
+ attrs = x;
+ } else {
+ if (x != null) {
+ attrs.x = x;
+ }
+ if (y != null) {
+ attrs.y = y;
+ }
+ if (width != null) {
+ attrs.width = width;
+ }
+ if (height != null) {
+ attrs.height = height;
+ }
+ if (vbx != null && vby != null && vbw != null && vbh != null) {
+ attrs.viewBox = [vbx, vby, vbw, vbh];
+ }
+ }
+ return this.el("svg", attrs);
+ };
+ /*\
+ * Paper.mask
+ [ method ]
+ **
+ * Equivalent in behaviour to @Paper.g, except it’s a mask.
+ **
+ = (object) the `mask` element
+ **
+ \*/
+ proto.mask = function (first) {
+ var attr,
+ el = this.el("mask");
+ if (arguments.length == 1 && first && !first.type) {
+ el.attr(first);
+ } else if (arguments.length) {
+ el.add(Array.prototype.slice.call(arguments, 0));
+ }
+ return el;
+ };
+ /*\
+ * Paper.ptrn
+ [ method ]
+ **
+ * Equivalent in behaviour to @Paper.g, except it’s a pattern.
+ - x (number) @optional X of the element
+ - y (number) @optional Y of the element
+ - width (number) @optional width of the element
+ - height (number) @optional height of the element
+ - vbx (number) @optional viewbox X
+ - vby (number) @optional viewbox Y
+ - vbw (number) @optional viewbox width
+ - vbh (number) @optional viewbox height
+ **
+ = (object) the `pattern` element
+ **
+ \*/
+ proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) {
+ if (is(x, "object")) {
+ var attr = x;
+ } else {
+ attr = {patternUnits: "userSpaceOnUse"};
+ if (x) {
+ attr.x = x;
+ }
+ if (y) {
+ attr.y = y;
+ }
+ if (width != null) {
+ attr.width = width;
+ }
+ if (height != null) {
+ attr.height = height;
+ }
+ if (vx != null && vy != null && vw != null && vh != null) {
+ attr.viewBox = [vx, vy, vw, vh];
+ } else {
+ attr.viewBox = [x || 0, y || 0, width || 0, height || 0];
+ }
+ }
+ return this.el("pattern", attr);
+ };
+ /*\
+ * Paper.use
+ [ method ]
+ **
+ * Creates a <use> element.
+ - id (string) @optional id of element to link
+ * or
+ - id (Element) @optional element to link
+ **
+ = (object) the `use` element
+ **
+ \*/
+ proto.use = function (id) {
+ if (id != null) {
+ if (id instanceof Element) {
+ if (!id.attr("id")) {
+ id.attr({id: Snap._.id(id)});
+ }
+ id = id.attr("id");
+ }
+ if (String(id).charAt() == "#") {
+ id = id.substring(1);
+ }
+ return this.el("use", {"xlink:href": "#" + id});
+ } else {
+ return Element.prototype.use.call(this);
+ }
+ };
+ /*\
+ * Paper.symbol
+ [ method ]
+ **
+ * Creates a <symbol> element.
+ - vbx (number) @optional viewbox X
+ - vby (number) @optional viewbox Y
+ - vbw (number) @optional viewbox width
+ - vbh (number) @optional viewbox height
+ = (object) the `symbol` element
+ **
+ \*/
+ proto.symbol = function (vx, vy, vw, vh) {
+ var attr = {};
+ if (vx != null && vy != null && vw != null && vh != null) {
+ attr.viewBox = [vx, vy, vw, vh];
+ }
+
+ return this.el("symbol", attr);
+ };
+ /*\
+ * Paper.text
+ [ method ]
+ **
+ * Draws a text string
+ **
+ - x (number) x coordinate position
+ - y (number) y coordinate position
+ - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements
+ = (object) the `text` element
+ **
+ > Usage
+ | var t1 = paper.text(50, 50, "Snap");
+ | var t2 = paper.text(50, 50, ["S","n","a","p"]);
+ | // Text path usage
+ | t1.attr({textpath: "M10,10L100,100"});
+ | // or
+ | var pth = paper.path("M10,10L100,100");
+ | t1.attr({textpath: pth});
+ \*/
+ proto.text = function (x, y, text) {
+ var attr = {};
+ if (is(x, "object")) {
+ attr = x;
+ } else if (x != null) {
+ attr = {
+ x: x,
+ y: y,
+ text: text || ""
+ };
+ }
+ return this.el("text", attr);
+ };
+ /*\
+ * Paper.line
+ [ method ]
+ **
+ * Draws a line
+ **
+ - x1 (number) x coordinate position of the start
+ - y1 (number) y coordinate position of the start
+ - x2 (number) x coordinate position of the end
+ - y2 (number) y coordinate position of the end
+ = (object) the `line` element
+ **
+ > Usage
+ | var t1 = paper.line(50, 50, 100, 100);
+ \*/
+ proto.line = function (x1, y1, x2, y2) {
+ var attr = {};
+ if (is(x1, "object")) {
+ attr = x1;
+ } else if (x1 != null) {
+ attr = {
+ x1: x1,
+ x2: x2,
+ y1: y1,
+ y2: y2
+ };
+ }
+ return this.el("line", attr);
+ };
+ /*\
+ * Paper.polyline
+ [ method ]
+ **
+ * Draws a polyline
+ **
+ - points (array) array of points
+ * or
+ - varargs (…) points
+ = (object) the `polyline` element
+ **
+ > Usage
+ | var p1 = paper.polyline([10, 10, 100, 100]);
+ | var p2 = paper.polyline(10, 10, 100, 100);
+ \*/
+ proto.polyline = function (points) {
+ if (arguments.length > 1) {
+ points = Array.prototype.slice.call(arguments, 0);
+ }
+ var attr = {};
+ if (is(points, "object") && !is(points, "array")) {
+ attr = points;
+ } else if (points != null) {
+ attr = {points: points};
+ }
+ return this.el("polyline", attr);
+ };
+ /*\
+ * Paper.polygon
+ [ method ]
+ **
+ * Draws a polygon. See @Paper.polyline
+ \*/
+ proto.polygon = function (points) {
+ if (arguments.length > 1) {
+ points = Array.prototype.slice.call(arguments, 0);
+ }
+ var attr = {};
+ if (is(points, "object") && !is(points, "array")) {
+ attr = points;
+ } else if (points != null) {
+ attr = {points: points};
+ }
+ return this.el("polygon", attr);
+ };
+ // gradients
+ (function () {
+ var $ = Snap._.$;
+ // gradients' helpers
+ function Gstops() {
+ return this.selectAll("stop");
+ }
+ function GaddStop(color, offset) {
+ var stop = $("stop"),
+ attr = {
+ offset: +offset + "%"
+ };
+ color = Snap.color(color);
+ attr["stop-color"] = color.hex;
+ if (color.opacity < 1) {
+ attr["stop-opacity"] = color.opacity;
+ }
+ $(stop, attr);
+ this.node.appendChild(stop);
+ return this;
+ }
+ function GgetBBox() {
+ if (this.type == "linearGradient") {
+ var x1 = $(this.node, "x1") || 0,
+ x2 = $(this.node, "x2") || 1,
+ y1 = $(this.node, "y1") || 0,
+ y2 = $(this.node, "y2") || 0;
+ return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1));
+ } else {
+ var cx = this.node.cx || .5,
+ cy = this.node.cy || .5,
+ r = this.node.r || 0;
+ return Snap._.box(cx - r, cy - r, r * 2, r * 2);
+ }
+ }
+ function gradient(defs, str) {
+ var grad = eve("snap.util.grad.parse", null, str).firstDefined(),
+ el;
+ if (!grad) {
+ return null;
+ }
+ grad.params.unshift(defs);
+ if (grad.type.toLowerCase() == "l") {
+ el = gradientLinear.apply(0, grad.params);
+ } else {
+ el = gradientRadial.apply(0, grad.params);
+ }
+ if (grad.type != grad.type.toLowerCase()) {
+ $(el.node, {
+ gradientUnits: "userSpaceOnUse"
+ });
+ }
+ var stops = grad.stops,
+ len = stops.length,
+ start = 0,
+ j = 0;
+ function seed(i, end) {
+ var step = (end - start) / (i - j);
+ for (var k = j; k < i; k++) {
+ stops[k].offset = +(+start + step * (k - j)).toFixed(2);
+ }
+ j = i;
+ start = end;
+ }
+ len--;
+ for (var i = 0; i < len; i++) if ("offset" in stops[i]) {
+ seed(i, stops[i].offset);
+ }
+ stops[len].offset = stops[len].offset || 100;
+ seed(len, stops[len].offset);
+ for (i = 0; i <= len; i++) {
+ var stop = stops[i];
+ el.addStop(stop.color, stop.offset);
+ }
+ return el;
+ }
+ function gradientLinear(defs, x1, y1, x2, y2) {
+ var el = Snap._.make("linearGradient", defs);
+ el.stops = Gstops;
+ el.addStop = GaddStop;
+ el.getBBox = GgetBBox;
+ if (x1 != null) {
+ $(el.node, {
+ x1: x1,
+ y1: y1,
+ x2: x2,
+ y2: y2
+ });
+ }
+ return el;
+ }
+ function gradientRadial(defs, cx, cy, r, fx, fy) {
+ var el = Snap._.make("radialGradient", defs);
+ el.stops = Gstops;
+ el.addStop = GaddStop;
+ el.getBBox = GgetBBox;
+ if (cx != null) {
+ $(el.node, {
+ cx: cx,
+ cy: cy,
+ r: r
+ });
+ }
+ if (fx != null && fy != null) {
+ $(el.node, {
+ fx: fx,
+ fy: fy
+ });
+ }
+ return el;
+ }
+ /*\
+ * Paper.gradient
+ [ method ]
+ **
+ * Creates a gradient element
+ **
+ - gradient (string) gradient descriptor
+ > Gradient Descriptor
+ * The gradient descriptor is an expression formatted as
+ * follows: `<type>(<coords>)<colors>`. The `<type>` can be
+ * either linear or radial. The uppercase `L` or `R` letters
+ * indicate absolute coordinates offset from the SVG surface.
+ * Lowercase `l` or `r` letters indicate coordinates
+ * calculated relative to the element to which the gradient is
+ * applied. Coordinates specify a linear gradient vector as
+ * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`,
+ * `r` and optional `fx`, `fy` specifying a focal point away
+ * from the center of the circle. Specify `<colors>` as a list
+ * of dash-separated CSS color values. Each color may be
+ * followed by a custom offset value, separated with a colon
+ * character.
+ > Examples
+ * Linear gradient, relative from top-left corner to bottom-right
+ * corner, from black through red to white:
+ | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff");
+ * Linear gradient, absolute from (0, 0) to (100, 100), from black
+ * through red at 25% to white:
+ | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff");
+ * Radial gradient, relative from the center of the element with radius
+ * half the width, from black to white:
+ | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff");
+ * To apply the gradient:
+ | paper.circle(50, 50, 40).attr({
+ | fill: g
+ | });
+ = (object) the `gradient` element
+ \*/
+ proto.gradient = function (str) {
+ return gradient(this.defs, str);
+ };
+ proto.gradientLinear = function (x1, y1, x2, y2) {
+ return gradientLinear(this.defs, x1, y1, x2, y2);
+ };
+ proto.gradientRadial = function (cx, cy, r, fx, fy) {
+ return gradientRadial(this.defs, cx, cy, r, fx, fy);
+ };
+ /*\
+ * Paper.toString
+ [ method ]
+ **
+ * Returns SVG code for the @Paper
+ = (string) SVG code for the @Paper
+ \*/
+ proto.toString = function () {
+ var doc = this.node.ownerDocument,
+ f = doc.createDocumentFragment(),
+ d = doc.createElement("div"),
+ svg = this.node.cloneNode(true),
+ res;
+ f.appendChild(d);
+ d.appendChild(svg);
+ Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"});
+ res = d.innerHTML;
+ f.removeChild(f.firstChild);
+ return res;
+ };
+ /*\
+ * Paper.toDataURL
+ [ method ]
+ **
+ * Returns SVG code for the @Paper as Data URI string.
+ = (string) Data URI string
+ \*/
+ proto.toDataURL = function () {
+ if (window && window.btoa) {
+ return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this)));
+ }
+ };
+ /*\
+ * Paper.clear
+ [ method ]
+ **
+ * Removes all child nodes of the paper, except <defs>.
+ \*/
+ proto.clear = function () {
+ var node = this.node.firstChild,
+ next;
+ while (node) {
+ next = node.nextSibling;
+ if (node.tagName != "defs") {
+ node.parentNode.removeChild(node);
+ } else {
+ proto.clear.call({node: node});
+ }
+ node = next;
+ }
+ };
+ }());
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var elproto = Element.prototype,
+ is = Snap.is,
+ clone = Snap._.clone,
+ has = "hasOwnProperty",
+ p2s = /,?([a-z]),?/gi,
+ toFloat = parseFloat,
+ math = Math,
+ PI = math.PI,
+ mmin = math.min,
+ mmax = math.max,
+ pow = math.pow,
+ abs = math.abs;
+ function paths(ps) {
+ var p = paths.ps = paths.ps || {};
+ if (p[ps]) {
+ p[ps].sleep = 100;
+ } else {
+ p[ps] = {
+ sleep: 100
+ };
+ }
+ setTimeout(function () {
+ for (var key in p) if (p[has](key) && key != ps) {
+ p[key].sleep--;
+ !p[key].sleep && delete p[key];
+ }
+ });
+ return p[ps];
+ }
+ function box(x, y, width, height) {
+ if (x == null) {
+ x = y = width = height = 0;
+ }
+ if (y == null) {
+ y = x.y;
+ width = x.width;
+ height = x.height;
+ x = x.x;
+ }
+ return {
+ x: x,
+ y: y,
+ width: width,
+ w: width,
+ height: height,
+ h: height,
+ x2: x + width,
+ y2: y + height,
+ cx: x + width / 2,
+ cy: y + height / 2,
+ r1: math.min(width, height) / 2,
+ r2: math.max(width, height) / 2,
+ r0: math.sqrt(width * width + height * height) / 2,
+ path: rectPath(x, y, width, height),
+ vb: [x, y, width, height].join(" ")
+ };
+ }
+ function toString() {
+ return this.join(",").replace(p2s, "$1");
+ }
+ function pathClone(pathArray) {
+ var res = clone(pathArray);
+ res.toString = toString;
+ return res;
+ }
+ function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
+ if (length == null) {
+ return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
+ } else {
+ return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y,
+ getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
+ }
+ }
+ function getLengthFactory(istotal, subpath) {
+ function O(val) {
+ return +(+val).toFixed(3);
+ }
+ return Snap._.cacher(function (path, length, onlystart) {
+ if (path instanceof Element) {
+ path = path.attr("d");
+ }
+ path = path2curve(path);
+ var x, y, p, l, sp = "", subpaths = {}, point,
+ len = 0;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = +p[1];
+ y = +p[2];
+ } else {
+ l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ if (len + l > length) {
+ if (subpath && !subpaths.start) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ sp += [
+ "C" + O(point.start.x),
+ O(point.start.y),
+ O(point.m.x),
+ O(point.m.y),
+ O(point.x),
+ O(point.y)
+ ];
+ if (onlystart) {return sp;}
+ subpaths.start = sp;
+ sp = [
+ "M" + O(point.x),
+ O(point.y) + "C" + O(point.n.x),
+ O(point.n.y),
+ O(point.end.x),
+ O(point.end.y),
+ O(p[5]),
+ O(p[6])
+ ].join();
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ continue;
+ }
+ if (!istotal && !subpath) {
+ point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
+ return point;
+ }
+ }
+ len += l;
+ x = +p[5];
+ y = +p[6];
+ }
+ sp += p.shift() + p;
+ }
+ subpaths.end = sp;
+ point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
+ return point;
+ }, null, Snap._.clone);
+ }
+ var getTotalLength = getLengthFactory(1),
+ getPointAtLength = getLengthFactory(),
+ getSubpathsAtLength = getLengthFactory(0, 1);
+ function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t,
+ t13 = pow(t1, 3),
+ t12 = pow(t1, 2),
+ t2 = t * t,
+ t3 = t2 * t,
+ x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
+ y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
+ mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
+ my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
+ nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
+ ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
+ ax = t1 * p1x + t * c1x,
+ ay = t1 * p1y + t * c1y,
+ cx = t1 * c2x + t * p2x,
+ cy = t1 * c2y + t * p2y,
+ alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
+ // (mx > nx || my < ny) && (alpha += 180);
+ return {
+ x: x,
+ y: y,
+ m: {x: mx, y: my},
+ n: {x: nx, y: ny},
+ start: {x: ax, y: ay},
+ end: {x: cx, y: cy},
+ alpha: alpha
+ };
+ }
+ function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
+ if (!Snap.is(p1x, "array")) {
+ p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
+ }
+ var bbox = curveDim.apply(null, p1x);
+ return box(
+ bbox.min.x,
+ bbox.min.y,
+ bbox.max.x - bbox.min.x,
+ bbox.max.y - bbox.min.y
+ );
+ }
+ function isPointInsideBBox(bbox, x, y) {
+ return x >= bbox.x &&
+ x <= bbox.x + bbox.width &&
+ y >= bbox.y &&
+ y <= bbox.y + bbox.height;
+ }
+ function isBBoxIntersect(bbox1, bbox2) {
+ bbox1 = box(bbox1);
+ bbox2 = box(bbox2);
+ return isPointInsideBBox(bbox2, bbox1.x, bbox1.y)
+ || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y)
+ || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2)
+ || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2)
+ || isPointInsideBBox(bbox1, bbox2.x, bbox2.y)
+ || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y)
+ || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2)
+ || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2)
+ || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x
+ || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
+ && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y
+ || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
+ }
+ function base3(t, p1, p2, p3, p4) {
+ var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
+ t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
+ return t * t2 - 3 * p1 + 3 * p2;
+ }
+ function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
+ if (z == null) {
+ z = 1;
+ }
+ z = z > 1 ? 1 : z < 0 ? 0 : z;
+ var z2 = z / 2,
+ n = 12,
+ Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],
+ Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472],
+ sum = 0;
+ for (var i = 0; i < n; i++) {
+ var ct = z2 * Tvalues[i] + z2,
+ xbase = base3(ct, x1, x2, x3, x4),
+ ybase = base3(ct, y1, y2, y3, y4),
+ comb = xbase * xbase + ybase * ybase;
+ sum += Cvalues[i] * math.sqrt(comb);
+ }
+ return z2 * sum;
+ }
+ function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
+ if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
+ return;
+ }
+ var t = 1,
+ step = t / 2,
+ t2 = t - step,
+ l,
+ e = .01;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ while (abs(l - ll) > e) {
+ step /= 2;
+ t2 += (l < ll ? 1 : -1) * step;
+ l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
+ }
+ return t2;
+ }
+ function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
+ if (
+ mmax(x1, x2) < mmin(x3, x4) ||
+ mmin(x1, x2) > mmax(x3, x4) ||
+ mmax(y1, y2) < mmin(y3, y4) ||
+ mmin(y1, y2) > mmax(y3, y4)
+ ) {
+ return;
+ }
+ var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
+ ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
+ denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+
+ if (!denominator) {
+ return;
+ }
+ var px = nx / denominator,
+ py = ny / denominator,
+ px2 = +px.toFixed(2),
+ py2 = +py.toFixed(2);
+ if (
+ px2 < +mmin(x1, x2).toFixed(2) ||
+ px2 > +mmax(x1, x2).toFixed(2) ||
+ px2 < +mmin(x3, x4).toFixed(2) ||
+ px2 > +mmax(x3, x4).toFixed(2) ||
+ py2 < +mmin(y1, y2).toFixed(2) ||
+ py2 > +mmax(y1, y2).toFixed(2) ||
+ py2 < +mmin(y3, y4).toFixed(2) ||
+ py2 > +mmax(y3, y4).toFixed(2)
+ ) {
+ return;
+ }
+ return {x: px, y: py};
+ }
+ function inter(bez1, bez2) {
+ return interHelper(bez1, bez2);
+ }
+ function interCount(bez1, bez2) {
+ return interHelper(bez1, bez2, 1);
+ }
+ function interHelper(bez1, bez2, justCount) {
+ var bbox1 = bezierBBox(bez1),
+ bbox2 = bezierBBox(bez2);
+ if (!isBBoxIntersect(bbox1, bbox2)) {
+ return justCount ? 0 : [];
+ }
+ var l1 = bezlen.apply(0, bez1),
+ l2 = bezlen.apply(0, bez2),
+ n1 = ~~(l1 / 8),
+ n2 = ~~(l2 / 8),
+ dots1 = [],
+ dots2 = [],
+ xy = {},
+ res = justCount ? 0 : [];
+ for (var i = 0; i < n1 + 1; i++) {
+ var p = findDotsAtSegment.apply(0, bez1.concat(i / n1));
+ dots1.push({x: p.x, y: p.y, t: i / n1});
+ }
+ for (i = 0; i < n2 + 1; i++) {
+ p = findDotsAtSegment.apply(0, bez2.concat(i / n2));
+ dots2.push({x: p.x, y: p.y, t: i / n2});
+ }
+ for (i = 0; i < n1; i++) {
+ for (var j = 0; j < n2; j++) {
+ var di = dots1[i],
+ di1 = dots1[i + 1],
+ dj = dots2[j],
+ dj1 = dots2[j + 1],
+ ci = abs(di1.x - di.x) < .001 ? "y" : "x",
+ cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
+ is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
+ if (is) {
+ if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
+ continue;
+ }
+ xy[is.x.toFixed(4)] = is.y.toFixed(4);
+ var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
+ t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
+ if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
+ if (justCount) {
+ res++;
+ } else {
+ res.push({
+ x: is.x,
+ y: is.y,
+ t1: t1,
+ t2: t2
+ });
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+ function pathIntersection(path1, path2) {
+ return interPathHelper(path1, path2);
+ }
+ function pathIntersectionNumber(path1, path2) {
+ return interPathHelper(path1, path2, 1);
+ }
+ function interPathHelper(path1, path2, justCount) {
+ path1 = path2curve(path1);
+ path2 = path2curve(path2);
+ var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
+ res = justCount ? 0 : [];
+ for (var i = 0, ii = path1.length; i < ii; i++) {
+ var pi = path1[i];
+ if (pi[0] == "M") {
+ x1 = x1m = pi[1];
+ y1 = y1m = pi[2];
+ } else {
+ if (pi[0] == "C") {
+ bez1 = [x1, y1].concat(pi.slice(1));
+ x1 = bez1[6];
+ y1 = bez1[7];
+ } else {
+ bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
+ x1 = x1m;
+ y1 = y1m;
+ }
+ for (var j = 0, jj = path2.length; j < jj; j++) {
+ var pj = path2[j];
+ if (pj[0] == "M") {
+ x2 = x2m = pj[1];
+ y2 = y2m = pj[2];
+ } else {
+ if (pj[0] == "C") {
+ bez2 = [x2, y2].concat(pj.slice(1));
+ x2 = bez2[6];
+ y2 = bez2[7];
+ } else {
+ bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
+ x2 = x2m;
+ y2 = y2m;
+ }
+ var intr = interHelper(bez1, bez2, justCount);
+ if (justCount) {
+ res += intr;
+ } else {
+ for (var k = 0, kk = intr.length; k < kk; k++) {
+ intr[k].segment1 = i;
+ intr[k].segment2 = j;
+ intr[k].bez1 = bez1;
+ intr[k].bez2 = bez2;
+ }
+ res = res.concat(intr);
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+ function isPointInsidePath(path, x, y) {
+ var bbox = pathBBox(path);
+ return isPointInsideBBox(bbox, x, y) &&
+ interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1;
+ }
+ function pathBBox(path) {
+ var pth = paths(path);
+ if (pth.bbox) {
+ return clone(pth.bbox);
+ }
+ if (!path) {
+ return box();
+ }
+ path = path2curve(path);
+ var x = 0,
+ y = 0,
+ X = [],
+ Y = [],
+ p;
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ p = path[i];
+ if (p[0] == "M") {
+ x = p[1];
+ y = p[2];
+ X.push(x);
+ Y.push(y);
+ } else {
+ var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
+ X = X.concat(dim.min.x, dim.max.x);
+ Y = Y.concat(dim.min.y, dim.max.y);
+ x = p[5];
+ y = p[6];
+ }
+ }
+ var xmin = mmin.apply(0, X),
+ ymin = mmin.apply(0, Y),
+ xmax = mmax.apply(0, X),
+ ymax = mmax.apply(0, Y),
+ bb = box(xmin, ymin, xmax - xmin, ymax - ymin);
+ pth.bbox = clone(bb);
+ return bb;
+ }
+ function rectPath(x, y, w, h, r) {
+ if (r) {
+ return [
+ ["M", +x + (+r), y],
+ ["l", w - r * 2, 0],
+ ["a", r, r, 0, 0, 1, r, r],
+ ["l", 0, h - r * 2],
+ ["a", r, r, 0, 0, 1, -r, r],
+ ["l", r * 2 - w, 0],
+ ["a", r, r, 0, 0, 1, -r, -r],
+ ["l", 0, r * 2 - h],
+ ["a", r, r, 0, 0, 1, r, -r],
+ ["z"]
+ ];
+ }
+ var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
+ res.toString = toString;
+ return res;
+ }
+ function ellipsePath(x, y, rx, ry, a) {
+ if (a == null && ry == null) {
+ ry = rx;
+ }
+ x = +x;
+ y = +y;
+ rx = +rx;
+ ry = +ry;
+ if (a != null) {
+ var rad = Math.PI / 180,
+ x1 = x + rx * Math.cos(-ry * rad),
+ x2 = x + rx * Math.cos(-a * rad),
+ y1 = y + rx * Math.sin(-ry * rad),
+ y2 = y + rx * Math.sin(-a * rad),
+ res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
+ } else {
+ res = [
+ ["M", x, y],
+ ["m", 0, -ry],
+ ["a", rx, ry, 0, 1, 1, 0, 2 * ry],
+ ["a", rx, ry, 0, 1, 1, 0, -2 * ry],
+ ["z"]
+ ];
+ }
+ res.toString = toString;
+ return res;
+ }
+ var unit2px = Snap._unit2px,
+ getPath = {
+ path: function (el) {
+ return el.attr("path");
+ },
+ circle: function (el) {
+ var attr = unit2px(el);
+ return ellipsePath(attr.cx, attr.cy, attr.r);
+ },
+ ellipse: function (el) {
+ var attr = unit2px(el);
+ return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry);
+ },
+ rect: function (el) {
+ var attr = unit2px(el);
+ return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry);
+ },
+ image: function (el) {
+ var attr = unit2px(el);
+ return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height);
+ },
+ line: function (el) {
+ return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")];
+ },
+ polyline: function (el) {
+ return "M" + el.attr("points");
+ },
+ polygon: function (el) {
+ return "M" + el.attr("points") + "z";
+ },
+ deflt: function (el) {
+ var bbox = el.node.getBBox();
+ return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
+ }
+ };
+ function pathToRelative(pathArray) {
+ var pth = paths(pathArray),
+ lowerCase = String.prototype.toLowerCase;
+ if (pth.rel) {
+ return pathClone(pth.rel);
+ }
+ if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) {
+ pathArray = Snap.parsePathString(pathArray);
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0;
+ if (pathArray[0][0] == "M") {
+ x = pathArray[0][1];
+ y = pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res.push(["M", x, y]);
+ }
+ for (var i = start, ii = pathArray.length; i < ii; i++) {
+ var r = res[i] = [],
+ pa = pathArray[i];
+ if (pa[0] != lowerCase.call(pa[0])) {
+ r[0] = lowerCase.call(pa[0]);
+ switch (r[0]) {
+ case "a":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +(pa[6] - x).toFixed(3);
+ r[7] = +(pa[7] - y).toFixed(3);
+ break;
+ case "v":
+ r[1] = +(pa[1] - y).toFixed(3);
+ break;
+ case "m":
+ mx = pa[1];
+ my = pa[2];
+ default:
+ for (var j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
+ }
+ }
+ } else {
+ r = res[i] = [];
+ if (pa[0] == "m") {
+ mx = pa[1] + x;
+ my = pa[2] + y;
+ }
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ res[i][k] = pa[k];
+ }
+ }
+ var len = res[i].length;
+ switch (res[i][0]) {
+ case "z":
+ x = mx;
+ y = my;
+ break;
+ case "h":
+ x += +res[i][len - 1];
+ break;
+ case "v":
+ y += +res[i][len - 1];
+ break;
+ default:
+ x += +res[i][len - 2];
+ y += +res[i][len - 1];
+ }
+ }
+ res.toString = toString;
+ pth.rel = pathClone(res);
+ return res;
+ }
+ function pathToAbsolute(pathArray) {
+ var pth = paths(pathArray);
+ if (pth.abs) {
+ return pathClone(pth.abs);
+ }
+ if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption
+ pathArray = Snap.parsePathString(pathArray);
+ }
+ if (!pathArray || !pathArray.length) {
+ return [["M", 0, 0]];
+ }
+ var res = [],
+ x = 0,
+ y = 0,
+ mx = 0,
+ my = 0,
+ start = 0,
+ pa0;
+ if (pathArray[0][0] == "M") {
+ x = +pathArray[0][1];
+ y = +pathArray[0][2];
+ mx = x;
+ my = y;
+ start++;
+ res[0] = ["M", x, y];
+ }
+ var crz = pathArray.length == 3 &&
+ pathArray[0][0] == "M" &&
+ pathArray[1][0].toUpperCase() == "R" &&
+ pathArray[2][0].toUpperCase() == "Z";
+ for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
+ res.push(r = []);
+ pa = pathArray[i];
+ pa0 = pa[0];
+ if (pa0 != pa0.toUpperCase()) {
+ r[0] = pa0.toUpperCase();
+ switch (r[0]) {
+ case "A":
+ r[1] = pa[1];
+ r[2] = pa[2];
+ r[3] = pa[3];
+ r[4] = pa[4];
+ r[5] = pa[5];
+ r[6] = +pa[6] + x;
+ r[7] = +pa[7] + y;
+ break;
+ case "V":
+ r[1] = +pa[1] + y;
+ break;
+ case "H":
+ r[1] = +pa[1] + x;
+ break;
+ case "R":
+ var dots = [x, y].concat(pa.slice(1));
+ for (var j = 2, jj = dots.length; j < jj; j++) {
+ dots[j] = +dots[j] + x;
+ dots[++j] = +dots[j] + y;
+ }
+ res.pop();
+ res = res.concat(catmullRom2bezier(dots, crz));
+ break;
+ case "O":
+ res.pop();
+ dots = ellipsePath(x, y, pa[1], pa[2]);
+ dots.push(dots[0]);
+ res = res.concat(dots);
+ break;
+ case "U":
+ res.pop();
+ res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
+ r = ["U"].concat(res[res.length - 1].slice(-2));
+ break;
+ case "M":
+ mx = +pa[1] + x;
+ my = +pa[2] + y;
+ default:
+ for (j = 1, jj = pa.length; j < jj; j++) {
+ r[j] = +pa[j] + ((j % 2) ? x : y);
+ }
+ }
+ } else if (pa0 == "R") {
+ dots = [x, y].concat(pa.slice(1));
+ res.pop();
+ res = res.concat(catmullRom2bezier(dots, crz));
+ r = ["R"].concat(pa.slice(-2));
+ } else if (pa0 == "O") {
+ res.pop();
+ dots = ellipsePath(x, y, pa[1], pa[2]);
+ dots.push(dots[0]);
+ res = res.concat(dots);
+ } else if (pa0 == "U") {
+ res.pop();
+ res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
+ r = ["U"].concat(res[res.length - 1].slice(-2));
+ } else {
+ for (var k = 0, kk = pa.length; k < kk; k++) {
+ r[k] = pa[k];
+ }
+ }
+ pa0 = pa0.toUpperCase();
+ if (pa0 != "O") {
+ switch (r[0]) {
+ case "Z":
+ x = +mx;
+ y = +my;
+ break;
+ case "H":
+ x = r[1];
+ break;
+ case "V":
+ y = r[1];
+ break;
+ case "M":
+ mx = r[r.length - 2];
+ my = r[r.length - 1];
+ default:
+ x = r[r.length - 2];
+ y = r[r.length - 1];
+ }
+ }
+ }
+ res.toString = toString;
+ pth.abs = pathClone(res);
+ return res;
+ }
+ function l2c(x1, y1, x2, y2) {
+ return [x1, y1, x2, y2, x2, y2];
+ }
+ function q2c(x1, y1, ax, ay, x2, y2) {
+ var _13 = 1 / 3,
+ _23 = 2 / 3;
+ return [
+ _13 * x1 + _23 * ax,
+ _13 * y1 + _23 * ay,
+ _13 * x2 + _23 * ax,
+ _13 * y2 + _23 * ay,
+ x2,
+ y2
+ ];
+ }
+ function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+ // for more information of where this math came from visit:
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ var _120 = PI * 120 / 180,
+ rad = PI / 180 * (+angle || 0),
+ res = [],
+ xy,
+ rotate = Snap._.cacher(function (x, y, rad) {
+ var X = x * math.cos(rad) - y * math.sin(rad),
+ Y = x * math.sin(rad) + y * math.cos(rad);
+ return {x: X, y: Y};
+ });
+ if (!recursive) {
+ xy = rotate(x1, y1, -rad);
+ x1 = xy.x;
+ y1 = xy.y;
+ xy = rotate(x2, y2, -rad);
+ x2 = xy.x;
+ y2 = xy.y;
+ var cos = math.cos(PI / 180 * angle),
+ sin = math.sin(PI / 180 * angle),
+ x = (x1 - x2) / 2,
+ y = (y1 - y2) / 2;
+ var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+ if (h > 1) {
+ h = math.sqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ var rx2 = rx * rx,
+ ry2 = ry * ry,
+ k = (large_arc_flag == sweep_flag ? -1 : 1) *
+ math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+ cx = k * rx * y / ry + (x1 + x2) / 2,
+ cy = k * -ry * x / rx + (y1 + y2) / 2,
+ f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
+ f2 = math.asin(((y2 - cy) / ry).toFixed(9));
+
+ f1 = x1 < cx ? PI - f1 : f1;
+ f2 = x2 < cx ? PI - f2 : f2;
+ f1 < 0 && (f1 = PI * 2 + f1);
+ f2 < 0 && (f2 = PI * 2 + f2);
+ if (sweep_flag && f1 > f2) {
+ f1 = f1 - PI * 2;
+ }
+ if (!sweep_flag && f2 > f1) {
+ f2 = f2 - PI * 2;
+ }
+ } else {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ var df = f2 - f1;
+ if (abs(df) > _120) {
+ var f2old = f2,
+ x2old = x2,
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * math.cos(f2);
+ y2 = cy + ry * math.sin(f2);
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+ }
+ df = f2 - f1;
+ var c1 = math.cos(f1),
+ s1 = math.sin(f1),
+ c2 = math.cos(f2),
+ s2 = math.sin(f2),
+ t = math.tan(df / 4),
+ hx = 4 / 3 * rx * t,
+ hy = 4 / 3 * ry * t,
+ m1 = [x1, y1],
+ m2 = [x1 + hx * s1, y1 - hy * c1],
+ m3 = [x2 + hx * s2, y2 - hy * c2],
+ m4 = [x2, y2];
+ m2[0] = 2 * m1[0] - m2[0];
+ m2[1] = 2 * m1[1] - m2[1];
+ if (recursive) {
+ return [m2, m3, m4].concat(res);
+ } else {
+ res = [m2, m3, m4].concat(res).join().split(",");
+ var newres = [];
+ for (var i = 0, ii = res.length; i < ii; i++) {
+ newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
+ }
+ return newres;
+ }
+ }
+ function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
+ var t1 = 1 - t;
+ return {
+ x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
+ y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
+ };
+ }
+
+ // Returns bounding box of cubic bezier curve.
+ // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
+ // Original version: NISHIO Hirokazu
+ // Modifications: https://github.com/timo22345
+ function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
+ var tvalues = [],
+ bounds = [[], []],
+ a, b, c, t, t1, t2, b2ac, sqrtb2ac;
+ for (var i = 0; i < 2; ++i) {
+ if (i == 0) {
+ b = 6 * x0 - 12 * x1 + 6 * x2;
+ a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
+ c = 3 * x1 - 3 * x0;
+ } else {
+ b = 6 * y0 - 12 * y1 + 6 * y2;
+ a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
+ c = 3 * y1 - 3 * y0;
+ }
+ if (abs(a) < 1e-12) {
+ if (abs(b) < 1e-12) {
+ continue;
+ }
+ t = -c / b;
+ if (0 < t && t < 1) {
+ tvalues.push(t);
+ }
+ continue;
+ }
+ b2ac = b * b - 4 * c * a;
+ sqrtb2ac = math.sqrt(b2ac);
+ if (b2ac < 0) {
+ continue;
+ }
+ t1 = (-b + sqrtb2ac) / (2 * a);
+ if (0 < t1 && t1 < 1) {
+ tvalues.push(t1);
+ }
+ t2 = (-b - sqrtb2ac) / (2 * a);
+ if (0 < t2 && t2 < 1) {
+ tvalues.push(t2);
+ }
+ }
+
+ var x, y, j = tvalues.length,
+ jlen = j,
+ mt;
+ while (j--) {
+ t = tvalues[j];
+ mt = 1 - t;
+ bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
+ bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
+ }
+
+ bounds[0][jlen] = x0;
+ bounds[1][jlen] = y0;
+ bounds[0][jlen + 1] = x3;
+ bounds[1][jlen + 1] = y3;
+ bounds[0].length = bounds[1].length = jlen + 2;
+
+
+ return {
+ min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])},
+ max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])}
+ };
+ }
+
+ function path2curve(path, path2) {
+ var pth = !path2 && paths(path);
+ if (!path2 && pth.curve) {
+ return pathClone(pth.curve);
+ }
+ var p = pathToAbsolute(path),
+ p2 = path2 && pathToAbsolute(path2),
+ attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+ attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
+ processPath = function (path, d, pcom) {
+ var nx, ny;
+ if (!path) {
+ return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
+ }
+ !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
+ switch (path[0]) {
+ case "M":
+ d.X = path[1];
+ d.Y = path[2];
+ break;
+ case "A":
+ path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
+ break;
+ case "S":
+ if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
+ nx = d.x * 2 - d.bx; // And reflect the previous
+ ny = d.y * 2 - d.by; // command's control point relative to the current point.
+ }
+ else { // or some else or nothing
+ nx = d.x;
+ ny = d.y;
+ }
+ path = ["C", nx, ny].concat(path.slice(1));
+ break;
+ case "T":
+ if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
+ d.qx = d.x * 2 - d.qx; // And make a reflection similar
+ d.qy = d.y * 2 - d.qy; // to case "S".
+ }
+ else { // or something else or nothing
+ d.qx = d.x;
+ d.qy = d.y;
+ }
+ path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
+ break;
+ case "Q":
+ d.qx = path[1];
+ d.qy = path[2];
+ path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
+ break;
+ case "L":
+ path = ["C"].concat(l2c(d.x, d.y, path[1], path[2]));
+ break;
+ case "H":
+ path = ["C"].concat(l2c(d.x, d.y, path[1], d.y));
+ break;
+ case "V":
+ path = ["C"].concat(l2c(d.x, d.y, d.x, path[1]));
+ break;
+ case "Z":
+ path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
+ break;
+ }
+ return path;
+ },
+ fixArc = function (pp, i) {
+ if (pp[i].length > 7) {
+ pp[i].shift();
+ var pi = pp[i];
+ while (pi.length) {
+ pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
+ p2 && (pcoms2[i] = "A"); // the same as above
+ pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
+ }
+ pp.splice(i, 1);
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ fixM = function (path1, path2, a1, a2, i) {
+ if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
+ path2.splice(i, 0, ["M", a2.x, a2.y]);
+ a1.bx = 0;
+ a1.by = 0;
+ a1.x = path1[i][1];
+ a1.y = path1[i][2];
+ ii = mmax(p.length, p2 && p2.length || 0);
+ }
+ },
+ pcoms1 = [], // path commands of original path p
+ pcoms2 = [], // path commands of original path p2
+ pfirst = "", // temporary holder for original path command
+ pcom = ""; // holder for previous path command of original path
+ for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
+ p[i] && (pfirst = p[i][0]); // save current path command
+
+ if (pfirst != "C") // C is not saved yet, because it may be result of conversion
+ {
+ pcoms1[i] = pfirst; // Save current path command
+ i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
+ }
+ p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
+
+ if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
+ // which may produce multiple C:s
+ // so we have to make sure that C is also C in original path
+
+ fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
+
+ if (p2) { // the same procedures is done to p2
+ p2[i] && (pfirst = p2[i][0]);
+ if (pfirst != "C") {
+ pcoms2[i] = pfirst;
+ i && (pcom = pcoms2[i - 1]);
+ }
+ p2[i] = processPath(p2[i], attrs2, pcom);
+
+ if (pcoms2[i] != "A" && pfirst == "C") {
+ pcoms2[i] = "C";
+ }
+
+ fixArc(p2, i);
+ }
+ fixM(p, p2, attrs, attrs2, i);
+ fixM(p2, p, attrs2, attrs, i);
+ var seg = p[i],
+ seg2 = p2 && p2[i],
+ seglen = seg.length,
+ seg2len = p2 && seg2.length;
+ attrs.x = seg[seglen - 2];
+ attrs.y = seg[seglen - 1];
+ attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
+ attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
+ attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
+ attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
+ attrs2.x = p2 && seg2[seg2len - 2];
+ attrs2.y = p2 && seg2[seg2len - 1];
+ }
+ if (!p2) {
+ pth.curve = pathClone(p);
+ }
+ return p2 ? [p, p2] : p;
+ }
+ function mapPath(path, matrix) {
+ if (!matrix) {
+ return path;
+ }
+ var x, y, i, j, ii, jj, pathi;
+ path = path2curve(path);
+ for (i = 0, ii = path.length; i < ii; i++) {
+ pathi = path[i];
+ for (j = 1, jj = pathi.length; j < jj; j += 2) {
+ x = matrix.x(pathi[j], pathi[j + 1]);
+ y = matrix.y(pathi[j], pathi[j + 1]);
+ pathi[j] = x;
+ pathi[j + 1] = y;
+ }
+ }
+ return path;
+ }
+
+ // http://schepers.cc/getting-to-the-point
+ function catmullRom2bezier(crp, z) {
+ var d = [];
+ for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
+ var p = [
+ {x: +crp[i - 2], y: +crp[i - 1]},
+ {x: +crp[i], y: +crp[i + 1]},
+ {x: +crp[i + 2], y: +crp[i + 3]},
+ {x: +crp[i + 4], y: +crp[i + 5]}
+ ];
+ if (z) {
+ if (!i) {
+ p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
+ } else if (iLen - 4 == i) {
+ p[3] = {x: +crp[0], y: +crp[1]};
+ } else if (iLen - 2 == i) {
+ p[2] = {x: +crp[0], y: +crp[1]};
+ p[3] = {x: +crp[2], y: +crp[3]};
+ }
+ } else {
+ if (iLen - 4 == i) {
+ p[3] = p[2];
+ } else if (!i) {
+ p[0] = {x: +crp[i], y: +crp[i + 1]};
+ }
+ }
+ d.push(["C",
+ (-p[0].x + 6 * p[1].x + p[2].x) / 6,
+ (-p[0].y + 6 * p[1].y + p[2].y) / 6,
+ (p[1].x + 6 * p[2].x - p[3].x) / 6,
+ (p[1].y + 6*p[2].y - p[3].y) / 6,
+ p[2].x,
+ p[2].y
+ ]);
+ }
+
+ return d;
+ }
+
+ // export
+ Snap.path = paths;
+
+ /*\
+ * Snap.path.getTotalLength
+ [ method ]
+ **
+ * Returns the length of the given path in pixels
+ **
+ - path (string) SVG path string
+ **
+ = (number) length
+ \*/
+ Snap.path.getTotalLength = getTotalLength;
+ /*\
+ * Snap.path.getPointAtLength
+ [ method ]
+ **
+ * Returns the coordinates of the point located at the given length along the given path
+ **
+ - path (string) SVG path string
+ - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
+ **
+ = (object) representation of the point:
+ o {
+ o x: (number) x coordinate,
+ o y: (number) y coordinate,
+ o alpha: (number) angle of derivative
+ o }
+ \*/
+ Snap.path.getPointAtLength = getPointAtLength;
+ /*\
+ * Snap.path.getSubpath
+ [ method ]
+ **
+ * Returns the subpath of a given path between given start and end lengths
+ **
+ - path (string) SVG path string
+ - from (number) length, in pixels, from the start of the path to the start of the segment
+ - to (number) length, in pixels, from the start of the path to the end of the segment
+ **
+ = (string) path string definition for the segment
+ \*/
+ Snap.path.getSubpath = function (path, from, to) {
+ if (this.getTotalLength(path) - to < 1e-6) {
+ return getSubpathsAtLength(path, from).end;
+ }
+ var a = getSubpathsAtLength(path, to, 1);
+ return from ? getSubpathsAtLength(a, from).end : a;
+ };
+ /*\
+ * Element.getTotalLength
+ [ method ]
+ **
+ * Returns the length of the path in pixels (only works for `path` elements)
+ = (number) length
+ \*/
+ elproto.getTotalLength = function () {
+ if (this.node.getTotalLength) {
+ return this.node.getTotalLength();
+ }
+ };
+ // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length?
+ /*\
+ * Element.getPointAtLength
+ [ method ]
+ **
+ * Returns coordinates of the point located at the given length on the given path (only works for `path` elements)
+ **
+ - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
+ **
+ = (object) representation of the point:
+ o {
+ o x: (number) x coordinate,
+ o y: (number) y coordinate,
+ o alpha: (number) angle of derivative
+ o }
+ \*/
+ elproto.getPointAtLength = function (length) {
+ return getPointAtLength(this.attr("d"), length);
+ };
+ // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear.
+ /*\
+ * Element.getSubpath
+ [ method ]
+ **
+ * Returns subpath of a given element from given start and end lengths (only works for `path` elements)
+ **
+ - from (number) length, in pixels, from the start of the path to the start of the segment
+ - to (number) length, in pixels, from the start of the path to the end of the segment
+ **
+ = (string) path string definition for the segment
+ \*/
+ elproto.getSubpath = function (from, to) {
+ return Snap.path.getSubpath(this.attr("d"), from, to);
+ };
+ Snap._.box = box;
+ /*\
+ * Snap.path.findDotsAtSegment
+ [ method ]
+ **
+ * Utility method
+ **
+ * Finds dot coordinates on the given cubic beziér curve at the given t
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ - t (number) position on the curve (0..1)
+ = (object) point information in format:
+ o {
+ o x: (number) x coordinate of the point,
+ o y: (number) y coordinate of the point,
+ o m: {
+ o x: (number) x coordinate of the left anchor,
+ o y: (number) y coordinate of the left anchor
+ o },
+ o n: {
+ o x: (number) x coordinate of the right anchor,
+ o y: (number) y coordinate of the right anchor
+ o },
+ o start: {
+ o x: (number) x coordinate of the start of the curve,
+ o y: (number) y coordinate of the start of the curve
+ o },
+ o end: {
+ o x: (number) x coordinate of the end of the curve,
+ o y: (number) y coordinate of the end of the curve
+ o },
+ o alpha: (number) angle of the curve derivative at the point
+ o }
+ \*/
+ Snap.path.findDotsAtSegment = findDotsAtSegment;
+ /*\
+ * Snap.path.bezierBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns the bounding box of a given cubic beziér curve
+ - p1x (number) x of the first point of the curve
+ - p1y (number) y of the first point of the curve
+ - c1x (number) x of the first anchor of the curve
+ - c1y (number) y of the first anchor of the curve
+ - c2x (number) x of the second anchor of the curve
+ - c2y (number) y of the second anchor of the curve
+ - p2x (number) x of the second point of the curve
+ - p2y (number) y of the second point of the curve
+ * or
+ - bez (array) array of six points for beziér curve
+ = (object) bounding box
+ o {
+ o x: (number) x coordinate of the left top point of the box,
+ o y: (number) y coordinate of the left top point of the box,
+ o x2: (number) x coordinate of the right bottom point of the box,
+ o y2: (number) y coordinate of the right bottom point of the box,
+ o width: (number) width of the box,
+ o height: (number) height of the box
+ o }
+ \*/
+ Snap.path.bezierBBox = bezierBBox;
+ /*\
+ * Snap.path.isPointInsideBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside bounding box
+ - bbox (string) bounding box
+ - x (string) x coordinate of the point
+ - y (string) y coordinate of the point
+ = (boolean) `true` if point is inside
+ \*/
+ Snap.path.isPointInsideBBox = isPointInsideBBox;
+ Snap.closest = function (x, y, X, Y) {
+ var r = 100,
+ b = box(x - r / 2, y - r / 2, r, r),
+ inside = [],
+ getter = X[0].hasOwnProperty("x") ? function (i) {
+ return {
+ x: X[i].x,
+ y: X[i].y
+ };
+ } : function (i) {
+ return {
+ x: X[i],
+ y: Y[i]
+ };
+ },
+ found = 0;
+ while (r <= 1e6 && !found) {
+ for (var i = 0, ii = X.length; i < ii; i++) {
+ var xy = getter(i);
+ if (isPointInsideBBox(b, xy.x, xy.y)) {
+ found++;
+ inside.push(xy);
+ break;
+ }
+ }
+ if (!found) {
+ r *= 2;
+ b = box(x - r / 2, y - r / 2, r, r)
+ }
+ }
+ if (r == 1e6) {
+ return;
+ }
+ var len = Infinity,
+ res;
+ for (i = 0, ii = inside.length; i < ii; i++) {
+ var l = Snap.len(x, y, inside[i].x, inside[i].y);
+ if (len > l) {
+ len = l;
+ inside[i].len = l;
+ res = inside[i];
+ }
+ }
+ return res;
+ };
+ /*\
+ * Snap.path.isBBoxIntersect
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if two bounding boxes intersect
+ - bbox1 (string) first bounding box
+ - bbox2 (string) second bounding box
+ = (boolean) `true` if bounding boxes intersect
+ \*/
+ Snap.path.isBBoxIntersect = isBBoxIntersect;
+ /*\
+ * Snap.path.intersection
+ [ method ]
+ **
+ * Utility method
+ **
+ * Finds intersections of two paths
+ - path1 (string) path string
+ - path2 (string) path string
+ = (array) dots of intersection
+ o [
+ o {
+ o x: (number) x coordinate of the point,
+ o y: (number) y coordinate of the point,
+ o t1: (number) t value for segment of path1,
+ o t2: (number) t value for segment of path2,
+ o segment1: (number) order number for segment of path1,
+ o segment2: (number) order number for segment of path2,
+ o bez1: (array) eight coordinates representing beziér curve for the segment of path1,
+ o bez2: (array) eight coordinates representing beziér curve for the segment of path2
+ o }
+ o ]
+ \*/
+ Snap.path.intersection = pathIntersection;
+ Snap.path.intersectionNumber = pathIntersectionNumber;
+ /*\
+ * Snap.path.isPointInside
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns `true` if given point is inside a given closed path.
+ *
+ * Note: fill mode doesn’t affect the result of this method.
+ - path (string) path string
+ - x (number) x of the point
+ - y (number) y of the point
+ = (boolean) `true` if point is inside the path
+ \*/
+ Snap.path.isPointInside = isPointInsidePath;
+ /*\
+ * Snap.path.getBBox
+ [ method ]
+ **
+ * Utility method
+ **
+ * Returns the bounding box of a given path
+ - path (string) path string
+ = (object) bounding box
+ o {
+ o x: (number) x coordinate of the left top point of the box,
+ o y: (number) y coordinate of the left top point of the box,
+ o x2: (number) x coordinate of the right bottom point of the box,
+ o y2: (number) y coordinate of the right bottom point of the box,
+ o width: (number) width of the box,
+ o height: (number) height of the box
+ o }
+ \*/
+ Snap.path.getBBox = pathBBox;
+ Snap.path.get = getPath;
+ /*\
+ * Snap.path.toRelative
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path coordinates into relative values
+ - path (string) path string
+ = (array) path string
+ \*/
+ Snap.path.toRelative = pathToRelative;
+ /*\
+ * Snap.path.toAbsolute
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path coordinates into absolute values
+ - path (string) path string
+ = (array) path string
+ \*/
+ Snap.path.toAbsolute = pathToAbsolute;
+ /*\
+ * Snap.path.toCubic
+ [ method ]
+ **
+ * Utility method
+ **
+ * Converts path to a new path where all segments are cubic beziér curves
+ - pathString (string|array) path string or array of segments
+ = (array) array of segments
+ \*/
+ Snap.path.toCubic = path2curve;
+ /*\
+ * Snap.path.map
+ [ method ]
+ **
+ * Transform the path string with the given matrix
+ - path (string) path string
+ - matrix (object) see @Matrix
+ = (string) transformed path string
+ \*/
+ Snap.path.map = mapPath;
+ Snap.path.toString = toString;
+ Snap.path.clone = pathClone;
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var mmax = Math.max,
+ mmin = Math.min;
+
+ // Set
+ var Set = function (items) {
+ this.items = [];
+ this.bindings = {};
+ this.length = 0;
+ this.type = "set";
+ if (items) {
+ for (var i = 0, ii = items.length; i < ii; i++) {
+ if (items[i]) {
+ this[this.items.length] = this.items[this.items.length] = items[i];
+ this.length++;
+ }
+ }
+ }
+ },
+ setproto = Set.prototype;
+ /*\
+ * Set.push
+ [ method ]
+ **
+ * Adds each argument to the current set
+ = (object) original element
+ \*/
+ setproto.push = function () {
+ var item,
+ len;
+ for (var i = 0, ii = arguments.length; i < ii; i++) {
+ item = arguments[i];
+ if (item) {
+ len = this.items.length;
+ this[len] = this.items[len] = item;
+ this.length++;
+ }
+ }
+ return this;
+ };
+ /*\
+ * Set.pop
+ [ method ]
+ **
+ * Removes last element and returns it
+ = (object) element
+ \*/
+ setproto.pop = function () {
+ this.length && delete this[this.length--];
+ return this.items.pop();
+ };
+ /*\
+ * Set.forEach
+ [ method ]
+ **
+ * Executes given function for each element in the set
+ *
+ * If the function returns `false`, the loop stops running.
+ **
+ - callback (function) function to run
+ - thisArg (object) context object for the callback
+ = (object) Set object
+ \*/
+ setproto.forEach = function (callback, thisArg) {
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ if (callback.call(thisArg, this.items[i], i) === false) {
+ return this;
+ }
+ }
+ return this;
+ };
+ /*\
+ * Set.animate
+ [ method ]
+ **
+ * Animates each element in set in sync.
+ *
+ **
+ - attrs (object) key-value pairs of destination attributes
+ - duration (number) duration of the animation in milliseconds
+ - easing (function) #optional easing function from @mina or custom
+ - callback (function) #optional callback function that executes when the animation ends
+ * or
+ - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]`
+ > Usage
+ | // animate all elements in set to radius 10
+ | set.animate({r: 10}, 500, mina.easein);
+ | // or
+ | // animate first element to radius 10, but second to radius 20 and in different time
+ | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]);
+ = (Element) the current element
+ \*/
+ setproto.animate = function (attrs, ms, easing, callback) {
+ if (typeof easing == "function" && !easing.length) {
+ callback = easing;
+ easing = mina.linear;
+ }
+ if (attrs instanceof Snap._.Animation) {
+ callback = attrs.callback;
+ easing = attrs.easing;
+ ms = easing.dur;
+ attrs = attrs.attr;
+ }
+ var args = arguments;
+ if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) {
+ var each = true;
+ }
+ var begin,
+ handler = function () {
+ if (begin) {
+ this.b = begin;
+ } else {
+ begin = this.b;
+ }
+ },
+ cb = 0,
+ set = this,
+ callbacker = callback && function () {
+ if (++cb == set.length) {
+ callback.call(this);
+ }
+ };
+ return this.forEach(function (el, i) {
+ eve.once("snap.animcreated." + el.id, handler);
+ if (each) {
+ args[i] && el.animate.apply(el, args[i]);
+ } else {
+ el.animate(attrs, ms, easing, callbacker);
+ }
+ });
+ };
+ setproto.remove = function () {
+ while (this.length) {
+ this.pop().remove();
+ }
+ return this;
+ };
+ /*\
+ * Set.bind
+ [ method ]
+ **
+ * Specifies how to handle a specific attribute when applied
+ * to a set.
+ *
+ **
+ - attr (string) attribute name
+ - callback (function) function to run
+ * or
+ - attr (string) attribute name
+ - element (Element) specific element in the set to apply the attribute to
+ * or
+ - attr (string) attribute name
+ - element (Element) specific element in the set to apply the attribute to
+ - eattr (string) attribute on the element to bind the attribute to
+ = (object) Set object
+ \*/
+ setproto.bind = function (attr, a, b) {
+ var data = {};
+ if (typeof a == "function") {
+ this.bindings[attr] = a;
+ } else {
+ var aname = b || attr;
+ this.bindings[attr] = function (v) {
+ data[aname] = v;
+ a.attr(data);
+ };
+ }
+ return this;
+ };
+ setproto.attr = function (value) {
+ var unbound = {};
+ for (var k in value) {
+ if (this.bindings[k]) {
+ this.bindings[k](value[k]);
+ } else {
+ unbound[k] = value[k];
+ }
+ }
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ this.items[i].attr(unbound);
+ }
+ return this;
+ };
+ /*\
+ * Set.clear
+ [ method ]
+ **
+ * Removes all elements from the set
+ \*/
+ setproto.clear = function () {
+ while (this.length) {
+ this.pop();
+ }
+ };
+ /*\
+ * Set.splice
+ [ method ]
+ **
+ * Removes range of elements from the set
+ **
+ - index (number) position of the deletion
+ - count (number) number of element to remove
+ - insertion… (object) #optional elements to insert
+ = (object) set elements that were deleted
+ \*/
+ setproto.splice = function (index, count, insertion) {
+ index = index < 0 ? mmax(this.length + index, 0) : index;
+ count = mmax(0, mmin(this.length - index, count));
+ var tail = [],
+ todel = [],
+ args = [],
+ i;
+ for (i = 2; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ for (i = 0; i < count; i++) {
+ todel.push(this[index + i]);
+ }
+ for (; i < this.length - index; i++) {
+ tail.push(this[index + i]);
+ }
+ var arglen = args.length;
+ for (i = 0; i < arglen + tail.length; i++) {
+ this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
+ }
+ i = this.items.length = this.length -= count - arglen;
+ while (this[i]) {
+ delete this[i++];
+ }
+ return new Set(todel);
+ };
+ /*\
+ * Set.exclude
+ [ method ]
+ **
+ * Removes given element from the set
+ **
+ - element (object) element to remove
+ = (boolean) `true` if object was found and removed from the set
+ \*/
+ setproto.exclude = function (el) {
+ for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
+ this.splice(i, 1);
+ return true;
+ }
+ return false;
+ };
+ setproto.insertAfter = function (el) {
+ var i = this.items.length;
+ while (i--) {
+ this.items[i].insertAfter(el);
+ }
+ return this;
+ };
+ setproto.getBBox = function () {
+ var x = [],
+ y = [],
+ x2 = [],
+ y2 = [];
+ for (var i = this.items.length; i--;) if (!this.items[i].removed) {
+ var box = this.items[i].getBBox();
+ x.push(box.x);
+ y.push(box.y);
+ x2.push(box.x + box.width);
+ y2.push(box.y + box.height);
+ }
+ x = mmin.apply(0, x);
+ y = mmin.apply(0, y);
+ x2 = mmax.apply(0, x2);
+ y2 = mmax.apply(0, y2);
+ return {
+ x: x,
+ y: y,
+ x2: x2,
+ y2: y2,
+ width: x2 - x,
+ height: y2 - y,
+ cx: x + (x2 - x) / 2,
+ cy: y + (y2 - y) / 2
+ };
+ };
+ setproto.clone = function (s) {
+ s = new Set;
+ for (var i = 0, ii = this.items.length; i < ii; i++) {
+ s.push(this.items[i].clone());
+ }
+ return s;
+ };
+ setproto.toString = function () {
+ return "Snap\u2018s set";
+ };
+ setproto.type = "set";
+ // export
+ Snap.Set = Set;
+ Snap.set = function () {
+ var set = new Set;
+ if (arguments.length) {
+ set.push.apply(set, Array.prototype.slice.call(arguments, 0));
+ }
+ return set;
+ };
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var names = {},
+ reUnit = /[a-z]+$/i,
+ Str = String;
+ names.stroke = names.fill = "colour";
+ function getEmpty(item) {
+ var l = item[0];
+ switch (l.toLowerCase()) {
+ case "t": return [l, 0, 0];
+ case "m": return [l, 1, 0, 0, 1, 0, 0];
+ case "r": if (item.length == 4) {
+ return [l, 0, item[2], item[3]];
+ } else {
+ return [l, 0];
+ }
+ case "s": if (item.length == 5) {
+ return [l, 1, 1, item[3], item[4]];
+ } else if (item.length == 3) {
+ return [l, 1, 1];
+ } else {
+ return [l, 1];
+ }
+ }
+ }
+ function equaliseTransform(t1, t2, getBBox) {
+ t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
+ t1 = Snap.parseTransformString(t1) || [];
+ t2 = Snap.parseTransformString(t2) || [];
+ var maxlength = Math.max(t1.length, t2.length),
+ from = [],
+ to = [],
+ i = 0, j, jj,
+ tt1, tt2;
+ for (; i < maxlength; i++) {
+ tt1 = t1[i] || getEmpty(t2[i]);
+ tt2 = t2[i] || getEmpty(tt1);
+ if ((tt1[0] != tt2[0]) ||
+ (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
+ (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
+ ) {
+ t1 = Snap._.transform2matrix(t1, getBBox());
+ t2 = Snap._.transform2matrix(t2, getBBox());
+ from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]];
+ to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]];
+ break;
+ }
+ from[i] = [];
+ to[i] = [];
+ for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) {
+ j in tt1 && (from[i][j] = tt1[j]);
+ j in tt2 && (to[i][j] = tt2[j]);
+ }
+ }
+ return {
+ from: path2array(from),
+ to: path2array(to),
+ f: getPath(from)
+ };
+ }
+ function getNumber(val) {
+ return val;
+ }
+ function getUnit(unit) {
+ return function (val) {
+ return +val.toFixed(3) + unit;
+ };
+ }
+ function getViewBox(val) {
+ return val.join(" ");
+ }
+ function getColour(clr) {
+ return Snap.rgb(clr[0], clr[1], clr[2]);
+ }
+ function getPath(path) {
+ var k = 0, i, ii, j, jj, out, a, b = [];
+ for (i = 0, ii = path.length; i < ii; i++) {
+ out = "[";
+ a = ['"' + path[i][0] + '"'];
+ for (j = 1, jj = path[i].length; j < jj; j++) {
+ a[j] = "val[" + (k++) + "]";
+ }
+ out += a + "]";
+ b[i] = out;
+ }
+ return Function("val", "return Snap.path.toString.call([" + b + "])");
+ }
+ function path2array(path) {
+ var out = [];
+ for (var i = 0, ii = path.length; i < ii; i++) {
+ for (var j = 1, jj = path[i].length; j < jj; j++) {
+ out.push(path[i][j]);
+ }
+ }
+ return out;
+ }
+ function isNumeric(obj) {
+ return isFinite(parseFloat(obj));
+ }
+ function arrayEqual(arr1, arr2) {
+ if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) {
+ return false;
+ }
+ return arr1.toString() == arr2.toString();
+ }
+ Element.prototype.equal = function (name, b) {
+ return eve("snap.util.equal", this, name, b).firstDefined();
+ };
+ eve.on("snap.util.equal", function (name, b) {
+ var A, B, a = Str(this.attr(name) || ""),
+ el = this;
+ if (isNumeric(a) && isNumeric(b)) {
+ return {
+ from: parseFloat(a),
+ to: parseFloat(b),
+ f: getNumber
+ };
+ }
+ if (names[name] == "colour") {
+ A = Snap.color(a);
+ B = Snap.color(b);
+ return {
+ from: [A.r, A.g, A.b, A.opacity],
+ to: [B.r, B.g, B.b, B.opacity],
+ f: getColour
+ };
+ }
+ if (name == "viewBox") {
+ A = this.attr(name).vb.split(" ").map(Number);
+ B = b.split(" ").map(Number);
+ return {
+ from: A,
+ to: B,
+ f: getViewBox
+ };
+ }
+ if (name == "transform" || name == "gradientTransform" || name == "patternTransform") {
+ if (b instanceof Snap.Matrix) {
+ b = b.toTransformString();
+ }
+ if (!Snap._.rgTransform.test(b)) {
+ b = Snap._.svgTransform2string(b);
+ }
+ return equaliseTransform(a, b, function () {
+ return el.getBBox(1);
+ });
+ }
+ if (name == "d" || name == "path") {
+ A = Snap.path.toCubic(a, b);
+ return {
+ from: path2array(A[0]),
+ to: path2array(A[1]),
+ f: getPath(A[0])
+ };
+ }
+ if (name == "points") {
+ A = Str(a).split(Snap._.separator);
+ B = Str(b).split(Snap._.separator);
+ return {
+ from: A,
+ to: B,
+ f: function (val) { return val; }
+ };
+ }
+ var aUnit = a.match(reUnit),
+ bUnit = Str(b).match(reUnit);
+ if (aUnit && arrayEqual(aUnit, bUnit)) {
+ return {
+ from: parseFloat(a),
+ to: parseFloat(b),
+ f: getUnit(aUnit)
+ };
+ } else {
+ return {
+ from: this.asPX(name),
+ to: this.asPX(name, b),
+ f: getNumber
+ };
+ }
+ });
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var elproto = Element.prototype,
+ has = "hasOwnProperty",
+ supportsTouch = "createTouch" in glob.doc,
+ events = [
+ "click", "dblclick", "mousedown", "mousemove", "mouseout",
+ "mouseover", "mouseup", "touchstart", "touchmove", "touchend",
+ "touchcancel"
+ ],
+ touchMap = {
+ mousedown: "touchstart",
+ mousemove: "touchmove",
+ mouseup: "touchend"
+ },
+ getScroll = function (xy, el) {
+ var name = xy == "y" ? "scrollTop" : "scrollLeft",
+ doc = el && el.node ? el.node.ownerDocument : glob.doc;
+ return doc[name in doc.documentElement ? "documentElement" : "body"][name];
+ },
+ preventDefault = function () {
+ this.returnValue = false;
+ },
+ preventTouch = function () {
+ return this.originalEvent.preventDefault();
+ },
+ stopPropagation = function () {
+ this.cancelBubble = true;
+ },
+ stopTouch = function () {
+ return this.originalEvent.stopPropagation();
+ },
+ addEvent = function (obj, type, fn, element) {
+ var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
+ f = function (e) {
+ var scrollY = getScroll("y", element),
+ scrollX = getScroll("x", element);
+ if (supportsTouch && touchMap[has](type)) {
+ for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
+ if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
+ var olde = e;
+ e = e.targetTouches[i];
+ e.originalEvent = olde;
+ e.preventDefault = preventTouch;
+ e.stopPropagation = stopTouch;
+ break;
+ }
+ }
+ }
+ var x = e.clientX + scrollX,
+ y = e.clientY + scrollY;
+ return fn.call(element, e, x, y);
+ };
+
+ if (type !== realName) {
+ obj.addEventListener(type, f, false);
+ }
+
+ obj.addEventListener(realName, f, false);
+
+ return function () {
+ if (type !== realName) {
+ obj.removeEventListener(type, f, false);
+ }
+
+ obj.removeEventListener(realName, f, false);
+ return true;
+ };
+ },
+ drag = [],
+ dragMove = function (e) {
+ var x = e.clientX,
+ y = e.clientY,
+ scrollY = getScroll("y"),
+ scrollX = getScroll("x"),
+ dragi,
+ j = drag.length;
+ while (j--) {
+ dragi = drag[j];
+ if (supportsTouch) {
+ var i = e.touches && e.touches.length,
+ touch;
+ while (i--) {
+ touch = e.touches[i];
+ if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) {
+ x = touch.clientX;
+ y = touch.clientY;
+ (e.originalEvent ? e.originalEvent : e).preventDefault();
+ break;
+ }
+ }
+ } else {
+ e.preventDefault();
+ }
+ var node = dragi.el.node,
+ o,
+ next = node.nextSibling,
+ parent = node.parentNode,
+ display = node.style.display;
+ // glob.win.opera && parent.removeChild(node);
+ // node.style.display = "none";
+ // o = dragi.el.paper.getElementByPoint(x, y);
+ // node.style.display = display;
+ // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
+ // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o);
+ x += scrollX;
+ y += scrollY;
+ eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
+ }
+ },
+ dragUp = function (e) {
+ Snap.unmousemove(dragMove).unmouseup(dragUp);
+ var i = drag.length,
+ dragi;
+ while (i--) {
+ dragi = drag[i];
+ dragi.el._drag = {};
+ eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
+ eve.off("snap.drag.*." + dragi.el.id);
+ }
+ drag = [];
+ };
+ /*\
+ * Element.click
+ [ method ]
+ **
+ * Adds a click event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unclick
+ [ method ]
+ **
+ * Removes a click event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.dblclick
+ [ method ]
+ **
+ * Adds a double click event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.undblclick
+ [ method ]
+ **
+ * Removes a double click event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousedown
+ [ method ]
+ **
+ * Adds a mousedown event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousedown
+ [ method ]
+ **
+ * Removes a mousedown event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mousemove
+ [ method ]
+ **
+ * Adds a mousemove event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmousemove
+ [ method ]
+ **
+ * Removes a mousemove event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseout
+ [ method ]
+ **
+ * Adds a mouseout event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseout
+ [ method ]
+ **
+ * Removes a mouseout event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseover
+ [ method ]
+ **
+ * Adds a mouseover event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseover
+ [ method ]
+ **
+ * Removes a mouseover event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.mouseup
+ [ method ]
+ **
+ * Adds a mouseup event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.unmouseup
+ [ method ]
+ **
+ * Removes a mouseup event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchstart
+ [ method ]
+ **
+ * Adds a touchstart event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchstart
+ [ method ]
+ **
+ * Removes a touchstart event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchmove
+ [ method ]
+ **
+ * Adds a touchmove event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchmove
+ [ method ]
+ **
+ * Removes a touchmove event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchend
+ [ method ]
+ **
+ * Adds a touchend event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchend
+ [ method ]
+ **
+ * Removes a touchend event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+
+ /*\
+ * Element.touchcancel
+ [ method ]
+ **
+ * Adds a touchcancel event handler to the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ /*\
+ * Element.untouchcancel
+ [ method ]
+ **
+ * Removes a touchcancel event handler from the element
+ - handler (function) handler for the event
+ = (object) @Element
+ \*/
+ for (var i = events.length; i--;) {
+ (function (eventName) {
+ Snap[eventName] = elproto[eventName] = function (fn, scope) {
+ if (Snap.is(fn, "function")) {
+ this.events = this.events || [];
+ this.events.push({
+ name: eventName,
+ f: fn,
+ unbind: addEvent(this.node || document, eventName, fn, scope || this)
+ });
+ } else {
+ for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) {
+ try {
+ this.events[i].f.call(this);
+ } catch (e) {}
+ }
+ }
+ return this;
+ };
+ Snap["un" + eventName] =
+ elproto["un" + eventName] = function (fn) {
+ var events = this.events || [],
+ l = events.length;
+ while (l--) if (events[l].name == eventName &&
+ (events[l].f == fn || !fn)) {
+ events[l].unbind();
+ events.splice(l, 1);
+ !events.length && delete this.events;
+ return this;
+ }
+ return this;
+ };
+ })(events[i]);
+ }
+ /*\
+ * Element.hover
+ [ method ]
+ **
+ * Adds hover event handlers to the element
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ - icontext (object) #optional context for hover in handler
+ - ocontext (object) #optional context for hover out handler
+ = (object) @Element
+ \*/
+ elproto.hover = function (f_in, f_out, scope_in, scope_out) {
+ return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
+ };
+ /*\
+ * Element.unhover
+ [ method ]
+ **
+ * Removes hover event handlers from the element
+ - f_in (function) handler for hover in
+ - f_out (function) handler for hover out
+ = (object) @Element
+ \*/
+ elproto.unhover = function (f_in, f_out) {
+ return this.unmouseover(f_in).unmouseout(f_out);
+ };
+ var draggable = [];
+ // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture.
+ // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from?
+ // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason.
+ // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID?
+ /*\
+ * Element.drag
+ [ method ]
+ **
+ * Adds event handlers for an element's drag gesture
+ **
+ - onmove (function) handler for moving
+ - onstart (function) handler for drag start
+ - onend (function) handler for drag end
+ - mcontext (object) #optional context for moving handler
+ - scontext (object) #optional context for drag start handler
+ - econtext (object) #optional context for drag end handler
+ * Additionaly following `drag` events are triggered: `drag.start.<id>` on start,
+ * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element
+ * `drag.over.<id>` fires as well.
+ *
+ * Start event and start handler are called in specified context or in context of the element with following parameters:
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * Move event and move handler are called in specified context or in context of the element with following parameters:
+ o dx (number) shift by x from the start point
+ o dy (number) shift by y from the start point
+ o x (number) x position of the mouse
+ o y (number) y position of the mouse
+ o event (object) DOM event object
+ * End event and end handler are called in specified context or in context of the element with following parameters:
+ o event (object) DOM event object
+ = (object) @Element
+ \*/
+ elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
+ var el = this;
+ if (!arguments.length) {
+ var origTransform;
+ return el.drag(function (dx, dy) {
+ this.attr({
+ transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
+ });
+ }, function () {
+ origTransform = this.transform().local;
+ });
+ }
+ function start(e, x, y) {
+ (e.originalEvent || e).preventDefault();
+ el._drag.x = x;
+ el._drag.y = y;
+ el._drag.id = e.identifier;
+ !drag.length && Snap.mousemove(dragMove).mouseup(dragUp);
+ drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
+ onstart && eve.on("snap.drag.start." + el.id, onstart);
+ onmove && eve.on("snap.drag.move." + el.id, onmove);
+ onend && eve.on("snap.drag.end." + el.id, onend);
+ eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e);
+ }
+ function init(e, x, y) {
+ eve("snap.draginit." + el.id, el, e, x, y);
+ }
+ eve.on("snap.draginit." + el.id, start);
+ el._drag = {};
+ draggable.push({el: el, start: start, init: init});
+ el.mousedown(init);
+ return el;
+ };
+ /*
+ * Element.onDragOver
+ [ method ]
+ **
+ * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id)
+ - f (function) handler for event, first argument would be the element you are dragging over
+ \*/
+ // elproto.onDragOver = function (f) {
+ // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id);
+ // };
+ /*\
+ * Element.undrag
+ [ method ]
+ **
+ * Removes all drag event handlers from the given element
+ \*/
+ elproto.undrag = function () {
+ var i = draggable.length;
+ while (i--) if (draggable[i].el == this) {
+ this.unmousedown(draggable[i].init);
+ draggable.splice(i, 1);
+ eve.unbind("snap.drag.*." + this.id);
+ eve.unbind("snap.draginit." + this.id);
+ }
+ !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp);
+ return this;
+ };
+ });
+
+ // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob) {
+ var elproto = Element.prototype,
+ pproto = Paper.prototype,
+ rgurl = /^\s*url\((.+)\)/,
+ Str = String,
+ $ = Snap._.$;
+ Snap.filter = {};
+ /*\
+ * Paper.filter
+ [ method ]
+ **
+ * Creates a `<filter>` element
+ **
+ - filstr (string) SVG fragment of filter provided as a string
+ = (object) @Element
+ * Note: It is recommended to use filters embedded into the page inside an empty SVG element.
+ > Usage
+ | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'),
+ | c = paper.circle(10, 10, 10).attr({
+ | filter: f
+ | });
+ \*/
+ pproto.filter = function (filstr) {
+ var paper = this;
+ if (paper.type != "svg") {
+ paper = paper.paper;
+ }
+ var f = Snap.parse(Str(filstr)),
+ id = Snap._.id(),
+ width = paper.node.offsetWidth,
+ height = paper.node.offsetHeight,
+ filter = $("filter");
+ $(filter, {
+ id: id,
+ filterUnits: "userSpaceOnUse"
+ });
+ filter.appendChild(f.node);
+ paper.defs.appendChild(filter);
+ return new Element(filter);
+ };
+
+ eve.on("snap.util.getattr.filter", function () {
+ eve.stop();
+ var p = $(this.node, "filter");
+ if (p) {
+ var match = Str(p).match(rgurl);
+ return match && Snap.select(match[1]);
+ }
+ });
+ eve.on("snap.util.attr.filter", function (value) {
+ if (value instanceof Element && value.type == "filter") {
+ eve.stop();
+ var id = value.node.id;
+ if (!id) {
+ $(value.node, {id: value.id});
+ id = value.id;
+ }
+ $(this.node, {
+ filter: Snap.url(id)
+ });
+ }
+ if (!value || value == "none") {
+ eve.stop();
+ this.node.removeAttribute("filter");
+ }
+ });
+ /*\
+ * Snap.filter.blur
+ [ method ]
+ **
+ * Returns an SVG markup string for the blur filter
+ **
+ - x (number) amount of horizontal blur, in pixels
+ - y (number) #optional amount of vertical blur, in pixels
+ = (string) filter representation
+ > Usage
+ | var f = paper.filter(Snap.filter.blur(5, 10)),
+ | c = paper.circle(10, 10, 10).attr({
+ | filter: f
+ | });
+ \*/
+ Snap.filter.blur = function (x, y) {
+ if (x == null) {
+ x = 2;
+ }
+ var def = y == null ? x : [x, y];
+ return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', {
+ def: def
+ });
+ };
+ Snap.filter.blur.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.shadow
+ [ method ]
+ **
+ * Returns an SVG markup string for the shadow filter
+ **
+ - dx (number) #optional horizontal shift of the shadow, in pixels
+ - dy (number) #optional vertical shift of the shadow, in pixels
+ - blur (number) #optional amount of blur
+ - color (string) #optional color of the shadow
+ - opacity (number) #optional `0..1` opacity of the shadow
+ * or
+ - dx (number) #optional horizontal shift of the shadow, in pixels
+ - dy (number) #optional vertical shift of the shadow, in pixels
+ - color (string) #optional color of the shadow
+ - opacity (number) #optional `0..1` opacity of the shadow
+ * which makes blur default to `4`. Or
+ - dx (number) #optional horizontal shift of the shadow, in pixels
+ - dy (number) #optional vertical shift of the shadow, in pixels
+ - opacity (number) #optional `0..1` opacity of the shadow
+ = (string) filter representation
+ > Usage
+ | var f = paper.filter(Snap.filter.shadow(0, 2, 3)),
+ | c = paper.circle(10, 10, 10).attr({
+ | filter: f
+ | });
+ \*/
+ Snap.filter.shadow = function (dx, dy, blur, color, opacity) {
+ if (typeof blur == "string") {
+ color = blur;
+ opacity = color;
+ blur = 4;
+ }
+ if (typeof color != "string") {
+ opacity = color;
+ color = "#000";
+ }
+ color = color || "#000";
+ if (blur == null) {
+ blur = 4;
+ }
+ if (opacity == null) {
+ opacity = 1;
+ }
+ if (dx == null) {
+ dx = 0;
+ dy = 2;
+ }
+ if (dy == null) {
+ dy = dx;
+ }
+ color = Snap.color(color);
+ return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
+ color: color,
+ dx: dx,
+ dy: dy,
+ blur: blur,
+ opacity: opacity
+ });
+ };
+ Snap.filter.shadow.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.grayscale
+ [ method ]
+ **
+ * Returns an SVG markup string for the grayscale filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.grayscale = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', {
+ a: 0.2126 + 0.7874 * (1 - amount),
+ b: 0.7152 - 0.7152 * (1 - amount),
+ c: 0.0722 - 0.0722 * (1 - amount),
+ d: 0.2126 - 0.2126 * (1 - amount),
+ e: 0.7152 + 0.2848 * (1 - amount),
+ f: 0.0722 - 0.0722 * (1 - amount),
+ g: 0.2126 - 0.2126 * (1 - amount),
+ h: 0.0722 + 0.9278 * (1 - amount)
+ });
+ };
+ Snap.filter.grayscale.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.sepia
+ [ method ]
+ **
+ * Returns an SVG markup string for the sepia filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.sepia = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', {
+ a: 0.393 + 0.607 * (1 - amount),
+ b: 0.769 - 0.769 * (1 - amount),
+ c: 0.189 - 0.189 * (1 - amount),
+ d: 0.349 - 0.349 * (1 - amount),
+ e: 0.686 + 0.314 * (1 - amount),
+ f: 0.168 - 0.168 * (1 - amount),
+ g: 0.272 - 0.272 * (1 - amount),
+ h: 0.534 - 0.534 * (1 - amount),
+ i: 0.131 + 0.869 * (1 - amount)
+ });
+ };
+ Snap.filter.sepia.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.saturate
+ [ method ]
+ **
+ * Returns an SVG markup string for the saturate filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.saturate = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', {
+ amount: 1 - amount
+ });
+ };
+ Snap.filter.saturate.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.hueRotate
+ [ method ]
+ **
+ * Returns an SVG markup string for the hue-rotate filter
+ **
+ - angle (number) angle of rotation
+ = (string) filter representation
+ \*/
+ Snap.filter.hueRotate = function (angle) {
+ angle = angle || 0;
+ return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', {
+ angle: angle
+ });
+ };
+ Snap.filter.hueRotate.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.invert
+ [ method ]
+ **
+ * Returns an SVG markup string for the invert filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.invert = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ // <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/>
+ return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', {
+ amount: amount,
+ amount2: 1 - amount
+ });
+ };
+ Snap.filter.invert.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.brightness
+ [ method ]
+ **
+ * Returns an SVG markup string for the brightness filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.brightness = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', {
+ amount: amount
+ });
+ };
+ Snap.filter.brightness.toString = function () {
+ return this();
+ };
+ /*\
+ * Snap.filter.contrast
+ [ method ]
+ **
+ * Returns an SVG markup string for the contrast filter
+ **
+ - amount (number) amount of filter (`0..1`)
+ = (string) filter representation
+ \*/
+ Snap.filter.contrast = function (amount) {
+ if (amount == null) {
+ amount = 1;
+ }
+ return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', {
+ amount: amount,
+ amount2: .5 - amount / 2
+ });
+ };
+ Snap.filter.contrast.toString = function () {
+ return this();
+ };
+ });
+
+ // Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
+ //
+ // Licensed 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.
+ Snap.plugin(function (Snap, Element, Paper, glob, Fragment) {
+ var box = Snap._.box,
+ is = Snap.is,
+ firstLetter = /^[^a-z]*([tbmlrc])/i,
+ toString = function () {
+ return "T" + this.dx + "," + this.dy;
+ };
+ /*\
+ * Element.getAlign
+ [ method ]
+ **
+ * Returns shift needed to align the element relatively to given element.
+ * If no elements specified, parent `<svg>` container will be used.
+ - el (object) @optional alignment element
+ - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"`
+ = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string
+ > Usage
+ | el.transform(el.getAlign(el2, "top"));
+ * or
+ | var dy = el.getAlign(el2, "top").dy;
+ \*/
+ Element.prototype.getAlign = function (el, way) {
+ if (way == null && is(el, "string")) {
+ way = el;
+ el = null;
+ }
+ el = el || this.paper;
+ var bx = el.getBBox ? el.getBBox() : box(el),
+ bb = this.getBBox(),
+ out = {};
+ way = way && way.match(firstLetter);
+ way = way ? way[1].toLowerCase() : "c";
+ switch (way) {
+ case "t":
+ out.dx = 0;
+ out.dy = bx.y - bb.y;
+ break;
+ case "b":
+ out.dx = 0;
+ out.dy = bx.y2 - bb.y2;
+ break;
+ case "m":
+ out.dx = 0;
+ out.dy = bx.cy - bb.cy;
+ break;
+ case "l":
+ out.dx = bx.x - bb.x;
+ out.dy = 0;
+ break;
+ case "r":
+ out.dx = bx.x2 - bb.x2;
+ out.dy = 0;
+ break;
+ default:
+ out.dx = bx.cx - bb.cx;
+ out.dy = 0;
+ break;
+ }
+ out.toString = toString;
+ return out;
+ };
+ /*\
+ * Element.align
+ [ method ]
+ **
+ * Aligns the element relatively to given one via transformation.
+ * If no elements specified, parent `<svg>` container will be used.
+ - el (object) @optional alignment element
+ - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"`
+ = (object) this element
+ > Usage
+ | el.align(el2, "top");
+ * or
+ | el.align("middle");
+ \*/
+ Element.prototype.align = function (el, way) {
+ return this.transform("..." + this.getAlign(el, way));
+ };
+ });
+
+ return Snap;
+ }));
+ }.call(window));
+
+/***/ },
+/* 3 */,
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["jQuery"] = __webpack_require__(5);
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
+ * jQuery JavaScript Library v2.2.4
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2016-05-20T17:23Z
+ */
+
+ (function( global, factory ) {
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+ // Pass this if window is not defined yet
+ }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+ // Support: Firefox 18+
+ // Can't be in strict mode, several libs including ASP.NET trace
+ // the stack via arguments.caller.callee and Firefox dies if
+ // you try to trace through "use strict" call chains. (#13335)
+ //"use strict";
+ var arr = [];
+
+ var document = window.document;
+
+ var slice = arr.slice;
+
+ var concat = arr.concat;
+
+ var push = arr.push;
+
+ var indexOf = arr.indexOf;
+
+ var class2type = {};
+
+ var toString = class2type.toString;
+
+ var hasOwn = class2type.hasOwnProperty;
+
+ var support = {};
+
+
+
+ var
+ version = "2.2.4",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Support: Android<4.1
+ // Make sure we trim BOM and NBSP
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // 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();
+ };
+
+ jQuery.fn = jQuery.prototype = {
+
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // Start with an empty selector
+ selector: "",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return 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 just the one element from the set
+ ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+ // Return all the elements in a clean array
+ slice.call( this );
+ },
+
+ // 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.
+ each: function( callback ) {
+ return jQuery.each( this, callback );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ } ) );
+ },
+
+ slice: function() {
+ return this.pushStack( 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 ] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor();
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: arr.sort,
+ splice: arr.splice
+ };
+
+ 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;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // 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 ( i === length ) {
+ 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" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ isFunction: function( obj ) {
+ return jQuery.type( obj ) === "function";
+ },
+
+ isArray: Array.isArray,
+
+ isWindow: function( obj ) {
+ return obj != null && obj === obj.window;
+ },
+
+ isNumeric: function( obj ) {
+
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ // adding 1 corrects loss of precision from parseFloat (#15100)
+ var realStringObj = obj && obj.toString();
+ return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // 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;
+ }
+
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call( obj, "constructor" ) &&
+ !hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+
+ // Support: Android<4.0, iOS<6 (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+ },
+
+ // 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
+ // Support: IE9-11+
+ // 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();
+ },
+
+ each: function( obj, callback ) {
+ var length, i = 0;
+
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // 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 {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var length, value,
+ i = 0,
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return 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 = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( 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;
+ },
+
+ now: Date.now,
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+ } );
+
+ // JSHint would error on this code due to the Symbol not being defined in ES5.
+ // Defining this global in .jshintrc would create a danger of using the global
+ // unguarded in another place, it seems safer to just disable JSHint for these
+ // three lines.
+ /* jshint ignore: start */
+ if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+ }
+ /* jshint ignore: end */
+
+ // Populate the class2type map
+ jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+ function( i, name ) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+ } );
+
+ function isArrayLike( obj ) {
+
+ // Support: iOS 8.2 (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+ }
+ var Sizzle =
+ /*!
+ * Sizzle CSS Selector Engine v2.2.1
+ * http://sizzlejs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-10-17
+ */
+ (function( window ) {
+
+ var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ 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 as it's faster than native
+ // http://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[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
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+ "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" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ 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<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ };
+
+ // 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 m, i, elem, nid, nidselect, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
+
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
+
+ results = results || [];
+
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+
+ // ID selector
+ if ( (m = match[1]) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( (elem = context.getElementById( m )) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+
+ // Element context
+ } else {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && (elem = newContext.getElementById( m )) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Type selector
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Class selector
+ } else if ( (m = match[3]) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !compilerCache[ selector + " " ] &&
+ (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+
+ if ( nodeType !== 1 ) {
+ newContext = context;
+ newSelector = selector;
+
+ // qSA looks outside Element context, which is not what we want
+ // Thanks to Andrew Dupont for this workaround technique
+ // Support: IE <=8
+ // Exclude object elements
+ } else if ( context.nodeName.toLowerCase() !== "object" ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( (nid = context.getAttribute( "id" )) ) {
+ nid = nid.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", (nid = expando) );
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
+ while ( i-- ) {
+ groups[i] = nidselect + " " + toSelector( groups[i] );
+ }
+ newSelector = groups.join( "," );
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+ }
+
+ /**
+ * 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
+ */
+ function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = arr.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+ }
+
+ /**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 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]);
+ }
+ }
+ });
+ });
+ }
+
+ /**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+ function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+ }
+
+ // Expose support vars for convenience
+ support = Sizzle.support = {};
+
+ /**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+ 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;
+ };
+
+ /**
+ * 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 hasCompare, parent,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // Return early if doc is invalid or already selected
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Update global variables
+ document = doc;
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9-11, Edge
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ if ( (parent = document.defaultView) && parent.top !== parent ) {
+ // Support: IE 11
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( document.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+ // 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 !document.getElementsByName || !document.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var m = context.getElementById( id );
+ return m ? [ 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 !== "undefined" &&
+ elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ 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 !== "undefined" && 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 = rnative.test( document.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
+ docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+ "<option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
+ // 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");
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibing-combinator selector` fails
+ if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = document.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + 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 = rnative.test( (matches = docElem.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
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully self-exclusive
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ 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
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === document ? -1 :
+ b === document ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( 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 document;
+ };
+
+ 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 &&
+ !compilerCache[ expr + " " ] &&
+ ( !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 ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+ };
+
+ 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 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ 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
+ while ( (node = elem[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 (jQuery #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[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[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // 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 !== "undefined" && 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.replace( rwhitespace, " " ) + " " ).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, uniqueCache, outerCache, node, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType,
+ diff = false;
+
+ 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
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && 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 ) {
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ } else {
+ // Use previously-cached element index if available
+ if ( useCache ) {
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+ // 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 ) {
+ outerCache = node[ expando ] || (node[ expando ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ (outerCache[ node.uniqueID ] = {});
+
+ uniqueCache[ 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( 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 );
+ // Don't keep the element (issue #299)
+ input[0] = null;
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
+ 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 negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ 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;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // 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;
+ })
+ }
+ };
+
+ Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+ // 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 );
+ }
+
+ // Easy API for creating new setFilters
+ function setFilters() {}
+ setFilters.prototype = Expr.filters = Expr.pseudos;
+ Expr.setFilters = new setFilters();
+
+ tokenize = Sizzle.tokenize = function( 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 oldCache, uniqueCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator 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 ] = {});
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
+
+ if ( (oldCache = uniqueCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ uniqueCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ 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 multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+ }
+
+ 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( 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( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ 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 ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context === document || context || outermost;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ if ( !context && elem.ownerDocument !== document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context || document, xml) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // 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 );
+ }
+ }
+ }
+
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
+ matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
+ 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, match /* 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 ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+ };
+
+ /**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+ select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
+ if ( match.length === 1 ) {
+
+ // Reduce context if the leading compound 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;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ 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 ) && testContext( 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 if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+ };
+
+ // One-time assignments
+
+ // Sort stability
+ support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+ // Support: Chrome 14-35+
+ // Always assume duplicates if they aren't passed to the comparison function
+ support.detectDuplicates = !!hasDuplicate;
+
+ // Initialize against the default document
+ setDocument();
+
+ // 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( document.createElement("div") ) & 1;
+ });
+
+ // Support: IE<8
+ // Prevent attribute/property "interpolation"
+ // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+ if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+ }) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+ }
+
+ // Support: IE<9
+ // Use defaultValue in place of getAttribute("value")
+ if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+ }) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+ }
+
+ // Support: IE<9
+ // Use getAttributeNode to fetch booleans when getAttribute lies
+ if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+ }) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+ }
+
+ return Sizzle;
+
+ })( window );
+
+
+
+ jQuery.find = Sizzle;
+ jQuery.expr = Sizzle.selectors;
+ jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+ jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+ jQuery.text = Sizzle.getText;
+ jQuery.isXMLDoc = Sizzle.isXML;
+ jQuery.contains = Sizzle.contains;
+
+
+
+ var 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;
+ };
+
+
+ var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+ };
+
+
+ var rneedsContext = jQuery.expr.match.needsContext;
+
+ var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );
+
+
+
+ var risSimple = /^.[^:#\[\.,]*$/;
+
+ // 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 ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
+ } );
+ }
+
+ jQuery.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;
+ } ) );
+ };
+
+ jQuery.fn.extend( {
+ find: function( selector ) {
+ var i,
+ len = this.length,
+ ret = [],
+ self = this;
+
+ 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;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], false ) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], true ) );
+ },
+ 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;
+ }
+ } );
+
+
+ // Initialize a jQuery object
+
+
+ // A central reference to the root jQuery(document)
+ var rootjQuery,
+
+ // 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-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context, root ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Method init() accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector[ 0 ] === "<" &&
+ selector[ 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;
+
+ // Option to run scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ 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 ] );
+
+ // Support: Blackberry 4.6
+ // gEBID returns nodes 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 || root ).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 root.ready !== undefined ?
+ root.ready( selector ) :
+
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+ // Give the init function the jQuery prototype for later instantiation
+ init.prototype = jQuery.fn;
+
+ // Initialize central reference
+ rootjQuery = jQuery( document );
+
+
+ var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+ // 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( {
+ 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;
+ }
+ }
+ } );
+ },
+
+ 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 ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+ },
+
+ // Determine the position of an element within the set
+ 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 indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.uniqueSort(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ 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 dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return siblings( 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.uniqueSort( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+ } );
+ var rnotwhite = ( /\S+/g );
+
+
+
+ // Convert String-formatted options into Object-formatted ones
+ function createOptions( options ) {
+ var object = {};
+ jQuery.each( options.match( 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" ?
+ createOptions( options ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+
+ // Last fire value for non-forgettable lists
+ memory,
+
+ // Flag to know if list was already fired
+ fired,
+
+ // Flag to prevent firing
+ locked,
+
+ // Actual callback list
+ list = [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
+ // Fire callbacks
+ fire = function() {
+
+ // Enforce single-firing
+ locked = options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
+ }
+ }
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
+ firing = false;
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
+ list = [];
+
+ // Otherwise, this object is spent
+ } else {
+ list = "";
+ }
+ }
+ },
+
+ // Actual Callbacks object
+ self = {
+
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ if ( jQuery.isFunction( arg ) ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
+
+ // Inspect recursively
+ add( arg );
+ }
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Remove a callback from the list
+ remove: function() {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ 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.length > 0;
+ },
+
+ // Remove all callbacks from the list
+ empty: function() {
+ if ( list ) {
+ list = [];
+ }
+ return this;
+ },
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
+ disable: function() {
+ locked = queue = [];
+ list = memory = "";
+ return this;
+ },
+ disabled: function() {
+ return !list;
+ },
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
+ lock: function() {
+ locked = queue = [];
+ if ( !memory ) {
+ list = memory = "";
+ }
+ return this;
+ },
+ locked: function() {
+ return !!locked;
+ },
+
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( !locked ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ queue.push( args );
+ if ( !firing ) {
+ fire();
+ }
+ }
+ 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 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()
+ .progress( newDefer.notify )
+ .done( newDefer.resolve )
+ .fail( newDefer.reject );
+ } else {
+ newDefer[ tuple[ 0 ] + "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 = 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 ? 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()
+ .progress( updateFunc( i, progressContexts, progressValues ) )
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // If we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+ } );
+
+
+ // The deferred used on DOM ready
+ var readyList;
+
+ jQuery.fn.ready = function( fn ) {
+
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+ };
+
+ jQuery.extend( {
+
+ // 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.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+ } );
+
+ /**
+ * The ready event handler and self cleanup method
+ */
+ function completed() {
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+ jQuery.ready();
+ }
+
+ jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called
+ // after the browser event has already occurred.
+ // Support: IE9-10 only
+ // Older IE sometimes signals "interactive" too soon
+ if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
+
+ } else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+ }
+ }
+ return readyList.promise( obj );
+ };
+
+ // Kick off the DOM ready check even if the user does not
+ jQuery.ready.promise();
+
+
+
+
+ // Multifunctional method to get and set values of a collection
+ // The value/s can optionally be executed if it's a function
+ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ 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 < len; i++ ) {
+ fn(
+ elems[ i ], key, raw ?
+ value :
+ value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ len ? fn( elems[ 0 ], key ) : emptyGet;
+ };
+ var acceptData = function( owner ) {
+
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ /* jshint -W018 */
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+ };
+
+
+
+
+ function Data() {
+ this.expando = jQuery.expando + Data.uid++;
+ }
+
+ Data.uid = 1;
+
+ Data.prototype = {
+
+ register: function( owner, initial ) {
+ var value = initial || {};
+
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
+
+ // Otherwise secure it in a non-enumerable, non-writable property
+ // configurability must be true to allow the property to be
+ // deleted with the delete operator
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ writable: true,
+ configurable: true
+ } );
+ }
+ return owner[ this.expando ];
+ },
+ cache: function( owner ) {
+
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( !acceptData( owner ) ) {
+ return {};
+ }
+
+ // Check if the owner object already has a cache
+ var value = owner[ this.expando ];
+
+ // If not, create one
+ if ( !value ) {
+ value = {};
+
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( acceptData( owner ) ) {
+
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
+
+ // Otherwise secure it in a non-enumerable property
+ // configurable must be true to allow the property to be
+ // deleted when data is removed
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ configurable: true
+ } );
+ }
+ }
+ }
+
+ return value;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ cache = this.cache( owner );
+
+ // Handle: [ owner, key, value ] args
+ if ( typeof data === "string" ) {
+ cache[ data ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+
+ // Copy the properties one-by-one to the cache object
+ for ( prop in data ) {
+ cache[ prop ] = data[ prop ];
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ return key === undefined ?
+ this.cache( owner ) :
+ owner[ this.expando ] && owner[ this.expando ][ key ];
+ },
+ access: function( owner, key, value ) {
+ var stored;
+
+ // 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 ) ) {
+
+ stored = this.get( owner, key );
+
+ return stored !== undefined ?
+ stored : this.get( owner, jQuery.camelCase( 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,
+ cache = owner[ this.expando ];
+
+ if ( cache === undefined ) {
+ return;
+ }
+
+ if ( key === undefined ) {
+ this.register( owner );
+
+ } 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( rnotwhite ) || [] );
+ }
+ }
+
+ i = name.length;
+
+ while ( i-- ) {
+ delete cache[ name[ i ] ];
+ }
+ }
+
+ // Remove the expando if there's no more data
+ if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
+
+ // Support: Chrome <= 35-45+
+ // Webkit & Blink performance suffers when deleting properties
+ // from DOM nodes, so set to undefined instead
+ // https://code.google.com/p/chromium/issues/detail?id=378607
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = undefined;
+ } else {
+ delete owner[ this.expando ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
+ }
+ };
+ var dataPriv = new Data();
+
+ var dataUser = new Data();
+
+
+
+ // 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 rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /[A-Z]/g;
+
+ 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, "-$&" ).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 ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch ( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ dataUser.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+ }
+
+ jQuery.extend( {
+ hasData: function( elem ) {
+ return dataUser.hasData( elem ) || dataPriv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return dataUser.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ dataUser.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to dataPriv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return dataPriv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ dataPriv.remove( elem, name );
+ }
+ } );
+
+ jQuery.fn.extend( {
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = dataUser.get( elem );
+
+ if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice( 5 ) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ dataPriv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each( function() {
+ dataUser.set( this, key );
+ } );
+ }
+
+ return access( this, function( value ) {
+ var data, camelKey;
+
+ // 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 = dataUser.get( elem, key ) ||
+
+ // Try to find dashed key if it exists (gh-2779)
+ // This is for 2.2.x only
+ dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() );
+
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ camelKey = jQuery.camelCase( key );
+
+ // Attempt to get data from the cache
+ // with the key camelized
+ data = dataUser.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...
+ camelKey = jQuery.camelCase( key );
+ 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 = dataUser.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...*
+ dataUser.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 ) {
+ dataUser.set( this, key, value );
+ }
+ } );
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each( function() {
+ dataUser.remove( this, key );
+ } );
+ }
+ } );
+
+
+ jQuery.extend( {
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = dataPriv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray( data ) ) {
+ queue = dataPriv.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 public - generate a queueHooks object, or return the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ dataPriv.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 );
+ } );
+ },
+ 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 = dataPriv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+ } );
+ var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+ var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+ var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+ var isHidden = function( 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 );
+ };
+
+
+
+ function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted,
+ scale = 1,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() { return tween.cur(); } :
+ function() { return jQuery.css( elem, prop, "" ); },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ do {
+
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ initialInUnit = initialInUnit / scale;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // Break the loop if scale is unchanged or perfect, or if we've just had enough.
+ } while (
+ scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
+ );
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+ }
+ var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+ var rtagName = ( /<([\w:-]+)/ );
+
+ var rscriptType = ( /^$|\/(?:java|ecma)script/i );
+
+
+
+ // We have to close these tags to support XHTML (#13200)
+ var wrapMap = {
+
+ // Support: IE9
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+
+ // XHTML parsers do not magically insert elements in the
+ // same way that tag soup parsers do. So we cannot shorten
+ // this by omitting <tbody> or other required elements.
+ 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: IE9
+ wrapMap.optgroup = wrapMap.option;
+
+ wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+ wrapMap.th = wrapMap.td;
+
+
+ function getAll( context, tag ) {
+
+ // Support: IE9-11+
+ // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+ var ret = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== "undefined" ?
+ context.querySelectorAll( tag || "*" ) :
+ [];
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], ret ) :
+ ret;
+ }
+
+
+ // Mark scripts as having already been evaluated
+ function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ dataPriv.set(
+ elems[ i ],
+ "globalEval",
+ !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+ );
+ }
+ }
+
+
+ var rhtml = /<|&#?\w+;/;
+
+ function buildFragment( elems, context, scripts, selection, ignored ) {
+ var elem, tmp, tag, wrap, contains, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+
+ // Support: Android<4.1, PhantomJS<2
+ // push.apply(_, arraylike) throws on ancient WebKit
+ 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 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: Android<4.1, PhantomJS<2
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
+
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+ 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;
+ }
+
+
+ ( function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Android 4.0-4.3, Safari<=5.1
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Safari<=5.1, Android<4.2
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<=11+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+ } )();
+
+
+ var
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+ function returnTrue() {
+ return true;
+ }
+
+ function returnFalse() {
+ return false;
+ }
+
+ // Support: IE9
+ // See #13393 for more info
+ function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+ }
+
+ function on( elem, types, selector, data, fn, 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 ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ 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 elem;
+ }
+
+ 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 elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+ }
+
+ /*
+ * 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 = dataPriv.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 !== "undefined" && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+ };
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( 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 );
+ }
+ }
+ }
+
+ 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;
+ }
+
+ },
+
+ // 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 = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( 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 data and the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ dataPriv.remove( elem, "handle events" );
+ }
+ },
+
+ 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 = slice.call( arguments ),
+ handlers = ( dataPriv.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.rnamespace || event.rnamespace.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;
+
+ // Support (at least): Chrome, IE9
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ //
+ // Support: Firefox<=42+
+ // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
+ if ( delegateCount && cur.nodeType &&
+ ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && ( 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 ) > -1 :
+ 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 detail 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 ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ }
+ };
+
+ jQuery.removeEvent = function( elem, type, handle ) {
+
+ // This "if" is needed for plain objects
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle );
+ }
+ };
+
+ 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.defaultPrevented === undefined &&
+
+ // Support: Android<4.0
+ src.returnValue === false ?
+ 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 = {
+ constructor: jQuery.Event,
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+ isSimulated: false,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+ };
+
+ // Create mouseenter/leave events using mouseover/out and event-time checks
+ // so that event delegation works in jQuery.
+ // Do the same for pointerenter/pointerleave and pointerover/pointerout
+ //
+ // Support: Safari 7 only
+ // Safari sends mouseenter too often; see:
+ // https://code.google.com/p/chromium/issues/detail?id=470258
+ // for the description of the bug (it existed in older Chrome versions as well).
+ jQuery.each( {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+ }, 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 mouseenter/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;
+ }
+ };
+ } );
+
+ jQuery.fn.extend( {
+ on: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn );
+ },
+ one: function( types, selector, data, fn ) {
+ return on( this, 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 );
+ } );
+ }
+ } );
+
+
+ var
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,
+
+ // Support: IE 10-11, Edge 10240+
+ // In IE/Edge using regex groups here causes severe slowdowns.
+ // See https://connect.microsoft.com/IE/feedback/details/1736512/
+ rnoInnerhtml = /<script|<style|<link/i,
+
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+
+ // Manipulating tables requires a tbody
+ function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? 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;
+ }
+
+ 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 ( dataPriv.hasData( src ) ) {
+ pdataOld = dataPriv.access( src );
+ pdataCur = dataPriv.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 ( dataUser.hasData( src ) ) {
+ udataOld = dataUser.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ dataUser.set( dest, udataCur );
+ }
+ }
+
+ // Fix IE bugs, see support tests
+ 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" && 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;
+ }
+ }
+
+ function domManip( collection, args, callback, ignored ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = collection.length,
+ 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" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return collection.each( function( index ) {
+ var self = collection.eq( index );
+ if ( isFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ domManip( self, args, callback, ignored );
+ } );
+ }
+
+ if ( l ) {
+ fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ // Require either new content or an interest in ignored elements to invoke the callback
+ if ( first || ignored ) {
+ 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: Android<4.1, PhantomJS<2
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( collection[ 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 || "" ) &&
+ !dataPriv.access( node, "globalEval" ) &&
+ jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return collection;
+ }
+
+ function remove( elem, selector, keepData ) {
+ var node,
+ nodes = selector ? jQuery.filter( selector, elem ) : elem,
+ i = 0;
+
+ for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+ if ( !keepData && node.nodeType === 1 ) {
+ jQuery.cleanData( getAll( node ) );
+ }
+
+ if ( node.parentNode ) {
+ if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
+ setGlobalEval( getAll( node, "script" ) );
+ }
+ node.parentNode.removeChild( node );
+ }
+ }
+
+ return elem;
+ }
+
+ jQuery.extend( {
+ htmlPrefilter: function( html ) {
+ return html.replace( rxhtmlTag, "<$1></$2>" );
+ },
+
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ // Fix IE cloning issues
+ if ( !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;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, type,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+ if ( acceptData( elem ) ) {
+ if ( ( data = elem[ dataPriv.expando ] ) ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ 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 );
+ }
+ }
+ }
+
+ // Support: Chrome <= 35-45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataPriv.expando ] = undefined;
+ }
+ if ( elem[ dataUser.expando ] ) {
+
+ // Support: Chrome <= 35-45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataUser.expando ] = undefined;
+ }
+ }
+ }
+ }
+ } );
+
+ jQuery.fn.extend( {
+
+ // Keep domManip exposed until 3.0 (gh-2225)
+ domManip: domManip,
+
+ detach: function( selector ) {
+ return remove( this, selector, true );
+ },
+
+ remove: function( selector ) {
+ return remove( this, selector );
+ },
+
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().each( function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ } );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ } );
+ },
+
+ prepend: function() {
+ return domManip( this, 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 domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ } );
+ },
+
+ after: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ } );
+ },
+
+ 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 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 = jQuery.htmlPrefilter( value );
+
+ 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 ignored = [];
+
+ // Make the changes, replacing each non-ignored context element with the new content
+ return domManip( this, arguments, function( elem ) {
+ var parent = this.parentNode;
+
+ if ( jQuery.inArray( this, ignored ) < 0 ) {
+ jQuery.cleanData( getAll( this ) );
+ if ( parent ) {
+ parent.replaceChild( elem, this );
+ }
+ }
+
+ // Force callback invocation
+ }, ignored );
+ }
+ } );
+
+ 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 push.apply(_, arraylike) throws
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+ } );
+
+
+ var iframe,
+ elemdisplay = {
+
+ // Support: Firefox
+ // We have to pre-define these values for FF (#10227)
+ HTML: "block",
+ BODY: "block"
+ };
+
+ /**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+
+ // Called only from within defaultDisplay
+ function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ display = jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+ }
+
+ /**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+ function 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'/>" ) )
+ .appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = iframe[ 0 ].contentDocument;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+ }
+ var rmargin = ( /^margin/ );
+
+ var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+ var getStyles = function( elem ) {
+
+ // Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ var view = elem.ownerDocument.defaultView;
+
+ if ( !view || !view.opener ) {
+ view = window;
+ }
+
+ return view.getComputedStyle( elem );
+ };
+
+ var 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;
+ };
+
+
+ var documentElement = document.documentElement;
+
+
+
+ ( function() {
+ var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
+
+ // Finish early in limited (non-browser) environments
+ if ( !div.style ) {
+ return;
+ }
+
+ // Support: IE9-11+
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
+ "padding:0;margin-top:1px;position:absolute";
+ container.appendChild( div );
+
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computeStyleTests() {
+ div.style.cssText =
+
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" +
+ "position:relative;display:block;" +
+ "margin:auto;border:1px;padding:1px;" +
+ "top:1%;width:50%";
+ div.innerHTML = "";
+ documentElement.appendChild( container );
+
+ var divStyle = window.getComputedStyle( div );
+ pixelPositionVal = divStyle.top !== "1%";
+ reliableMarginLeftVal = divStyle.marginLeft === "2px";
+ boxSizingReliableVal = divStyle.width === "4px";
+
+ // Support: Android 4.0 - 4.3 only
+ // Some styles come back with percentage values, even though they shouldn't
+ div.style.marginRight = "50%";
+ pixelMarginRightVal = divStyle.marginRight === "4px";
+
+ documentElement.removeChild( container );
+ }
+
+ jQuery.extend( support, {
+ pixelPosition: function() {
+
+ // This test is executed only once but we still do memoizing
+ // since we can use the boxSizingReliable pre-computing.
+ // No need to check if the test was already performed, though.
+ computeStyleTests();
+ return pixelPositionVal;
+ },
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingReliableVal;
+ },
+ pixelMarginRight: function() {
+
+ // Support: Android 4.0-4.3
+ // We're checking for boxSizingReliableVal here instead of pixelMarginRightVal
+ // since that compresses better and they're computed together anyway.
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return pixelMarginRightVal;
+ },
+ reliableMarginLeft: function() {
+
+ // Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return reliableMarginLeftVal;
+ },
+ reliableMarginRight: function() {
+
+ // 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
+ // This support function is only executed once so no memoizing is needed.
+ var ret,
+ marginDiv = div.appendChild( document.createElement( "div" ) );
+
+ // Reset CSS: box-sizing; display; margin; border; padding
+ marginDiv.style.cssText = div.style.cssText =
+
+ // Support: Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;box-sizing:content-box;" +
+ "display:block;margin:0;border:0;padding:0";
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+ documentElement.appendChild( container );
+
+ ret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight );
+
+ documentElement.removeChild( container );
+ div.removeChild( marginDiv );
+
+ return ret;
+ }
+ } );
+ } )();
+
+
+ function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+ // Support: Opera 12.1x only
+ // Fall back to style even without computed
+ // computed is undefined for elems on document fragments
+ if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // Support: IE9
+ // getPropertyValue is only needed for .css('filter') (#12537)
+ if ( computed ) {
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Android Browser returns percentage for some values,
+ // but width seems to be reliably pixels.
+ // This is against the CSSOM draft spec:
+ // http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( !support.pixelMarginRight() && 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 !== undefined ?
+
+ // Support: IE9-11+
+ // IE returns zIndex value as an integer.
+ ret + "" :
+ ret;
+ }
+
+
+ function addGetHookIf( conditionFn, hookFn ) {
+
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ if ( conditionFn() ) {
+
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+ return ( this.get = hookFn ).apply( this, arguments );
+ }
+ };
+ }
+
+
+ var
+
+ // 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]).+)/,
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
+ emptyStyle = document.createElement( "div" ).style;
+
+ // Return a css property mapped to a potentially vendor prefixed property
+ function vendorPropName( name ) {
+
+ // Shortcut for names that are not vendor prefixed
+ if ( name in emptyStyle ) {
+ return name;
+ }
+
+ // Check for vendor prefixed names
+ var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ }
+ }
+
+ function setPositiveNumber( elem, value, subtract ) {
+
+ // Any relative (+/-) values have already been
+ // normalized at this point
+ var matches = rcssNum.exec( value );
+ return matches ?
+
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "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.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;
+ }
+
+ // Check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox &&
+ ( 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";
+ }
+
+ 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 ] = dataPriv.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 ] = dataPriv.access(
+ elem,
+ "olddisplay",
+ defaultDisplay( elem.nodeName )
+ );
+ }
+ } else {
+ hidden = isHidden( elem );
+
+ if ( display !== "none" || !hidden ) {
+ dataPriv.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.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: {
+ "animationIterationCount": true,
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": 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: {
+ "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( origName ) || origName );
+
+ // Gets hook for the prefixed version, then unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
+
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set (#7116)
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ if ( type === "number" ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
+ }
+
+ // Support: IE9-11+
+ // background-* props affect original clone's values
+ if ( !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( origName ) || origName );
+
+ // Try prefixed name followed by the unprefixed name
+ 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 ];
+ }
+
+ // Make numeric if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || isFinite( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+ } );
+
+ 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
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+ elem.offsetWidth === 0 ?
+ swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ } ) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var matches,
+ styles = extra && getStyles( elem ),
+ subtract = extra && augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ );
+
+ // Convert to pixels if value adjustment is needed
+ if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+ ( matches[ 3 ] || "px" ) !== "px" ) {
+
+ elem.style[ name ] = value;
+ value = jQuery.css( elem, name );
+ }
+
+ return setPositiveNumber( elem, value, subtract );
+ }
+ };
+ } );
+
+ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
+ function( elem, computed ) {
+ if ( computed ) {
+ return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+ elem.getBoundingClientRect().left -
+ swap( elem, { marginLeft: 0 }, function() {
+ return elem.getBoundingClientRect().left;
+ } )
+ ) + "px";
+ }
+ }
+ );
+
+ // Support: Android 2.3
+ jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ return swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+ );
+
+ // 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;
+ }
+ } );
+
+ jQuery.fn.extend( {
+ css: function( name, value ) {
+ return 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 ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each( function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ } );
+ }
+ } );
+
+
+ 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 || jQuery.easing._default;
+ 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;
+
+ // Use a property on the element directly when it is not a DOM element,
+ // or when there is no matching style property that exists.
+ if ( tween.elem.nodeType !== 1 ||
+ tween.elem[ tween.prop ] != null && 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.
+ // 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 available and use plain properties where available.
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.nodeType === 1 &&
+ ( 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.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ },
+ _default: "swing"
+ };
+
+ jQuery.fx = Tween.prototype.init;
+
+ // Back Compat <1.8 extension point
+ jQuery.fx.step = {};
+
+
+
+
+ var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rrun = /queueHooks$/;
+
+ // Animations created synchronously will run synchronously
+ function createFxNow() {
+ window.setTimeout( function() {
+ fxNow = undefined;
+ } );
+ return ( fxNow = jQuery.now() );
+ }
+
+ // Generate parameters to create a standard animation
+ function genFx( type, includeWidth ) {
+ var which,
+ i = 0,
+ attrs = { height: type };
+
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise 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;
+ }
+
+ function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.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 defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = dataPriv.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() {
+
+ // Ensure the complete handler is 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
+ display = jQuery.css( elem, "display" );
+
+ // Test default display if display is currently "none"
+ checkDisplay = display === "none" ?
+ dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+ if ( checkDisplay === "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 );
+
+ // Any non-fx value stops us from restoring the original display value
+ } else {
+ display = undefined;
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = dataPriv.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;
+
+ dataPriv.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;
+ }
+ }
+ }
+
+ // If this is a noop like .hide().hide(), restore an overwritten display value
+ } else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
+ style.display = display;
+ }
+ }
+
+ 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 won't overwrite existing keys.
+ // Reusing 'index' 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;
+ }
+ }
+ }
+
+ function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = Animation.prefilters.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 ),
+
+ // Support: Android 2.3
+ // 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: {},
+ easing: jQuery.easing._default
+ }, 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.notifyWith( elem, [ animation, 1, 0 ] );
+ 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 = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ if ( jQuery.isFunction( result.stop ) ) {
+ jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+ jQuery.proxy( result.stop, 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 );
+ }
+
+ jQuery.Animation = jQuery.extend( Animation, {
+ tweeners: {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+ return tween;
+ } ]
+ },
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.match( rnotwhite );
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+ Animation.tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilters: [ defaultPrefilter ],
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ Animation.prefilters.unshift( callback );
+ } else {
+ Animation.prefilters.push( 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.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 || dataPriv.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 = dataPriv.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 = dataPriv.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;
+ } );
+ }
+ } );
+
+ 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 );
+ };
+ } );
+
+ // 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.timers = [];
+ jQuery.fx.tick = function() {
+ var timer,
+ i = 0,
+ timers = jQuery.timers;
+
+ 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 ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+ };
+
+ jQuery.fx.interval = 13;
+ jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+ };
+
+ jQuery.fx.stop = function() {
+ window.clearInterval( timerId );
+
+ timerId = null;
+ };
+
+ jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+
+ // Default speed
+ _default: 400
+ };
+
+
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
+ jQuery.fn.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 = window.setTimeout( next, time );
+ hooks.stop = function() {
+ window.clearTimeout( timeout );
+ };
+ } );
+ };
+
+
+ ( function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
+
+ input.type = "checkbox";
+
+ // Support: iOS<=5.1, Android<=4.2+
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
+
+ // Support: IE<=11+
+ // Must access selectedIndex to make default options select
+ support.optSelected = opt.selected;
+
+ // Support: Android<=2.3
+ // Options inside disabled selects are incorrectly marked as disabled
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE<=11+
+ // An input loses its value after becoming a radio
+ input = document.createElement( "input" );
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+ } )();
+
+
+ var boolHook,
+ attrHandle = jQuery.expr.attrHandle;
+
+ jQuery.fn.extend( {
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each( function() {
+ jQuery.removeAttr( this, name );
+ } );
+ }
+ } );
+
+ jQuery.extend( {
+ attr: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set attributes on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ 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 : undefined );
+ }
+
+ if ( value !== undefined ) {
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+ }
+
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ? undefined : ret;
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" &&
+ jQuery.nodeName( elem, "input" ) ) {
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( 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 );
+ }
+ }
+ }
+ } );
+
+ // 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 = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ };
+ } );
+
+
+
+
+ var rfocusable = /^(?:input|select|textarea|button)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+ jQuery.fn.extend( {
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each( function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ } );
+ }
+ } );
+
+ jQuery.extend( {
+ prop: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ return ( elem[ name ] = value );
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ return elem[ name ];
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+
+ // elem.tabIndex doesn't always return the
+ // correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) ||
+ rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ }
+ } );
+
+ // Support: IE <=11 only
+ // Accessing the selectedIndex property
+ // forces the browser to respect setting selected
+ // on the option
+ // The getter ensures a default option is selected
+ // when in an optgroup
+ if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ },
+ set: function( elem ) {
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+ };
+ }
+
+ jQuery.each( [
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+ ], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+ } );
+
+
+
+
+ var rclass = /[\t\r\n\f]/g;
+
+ function getClass( elem ) {
+ return elem.getAttribute && elem.getAttribute( "class" ) || "";
+ }
+
+ jQuery.fn.extend( {
+ addClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ if ( typeof value === "string" && value ) {
+ classes = value.match( rnotwhite ) || [];
+
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+ cur = elem.nodeType === 1 &&
+ ( " " + curValue + " " ).replace( rclass, " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ if ( !arguments.length ) {
+ return this.attr( "class", "" );
+ }
+
+ if ( typeof value === "string" && value ) {
+ classes = value.match( rnotwhite ) || [];
+
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 &&
+ ( " " + curValue + " " ).replace( rclass, " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).toggleClass(
+ value.call( this, i, getClass( this ), stateVal ),
+ stateVal
+ );
+ } );
+ }
+
+ return this.each( function() {
+ var className, i, self, classNames;
+
+ if ( type === "string" ) {
+
+ // Toggle individual class names
+ i = 0;
+ self = jQuery( this );
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( ( className = classNames[ i++ ] ) ) {
+
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( value === undefined || type === "boolean" ) {
+ className = getClass( this );
+ if ( className ) {
+
+ // Store className if set
+ dataPriv.set( this, "__className__", 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.
+ if ( this.setAttribute ) {
+ this.setAttribute( "class",
+ className || value === false ?
+ "" :
+ dataPriv.get( this, "__className__" ) || ""
+ );
+ }
+ }
+ } );
+ },
+
+ hasClass: function( selector ) {
+ var className, elem,
+ i = 0;
+
+ className = " " + selector + " ";
+ while ( ( elem = this[ i++ ] ) ) {
+ if ( elem.nodeType === 1 &&
+ ( " " + getClass( elem ) + " " ).replace( rclass, " " )
+ .indexOf( className ) > -1
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ } );
+
+
+
+
+ var rreturn = /\r/g,
+ rspaces = /[\x20\t\r\n\f]+/g;
+
+ jQuery.fn.extend( {
+ 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 ) {
+
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+
+ // Support: IE10-11+
+ // option.text throws exceptions (#14686, #14858)
+ // Strip and collapse whitespace
+ // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+ jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
+ }
+ },
+ 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 ];
+
+ // IE8-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
+ ( 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.valHooks.option.get( option ), values ) > -1
+ ) {
+ optionSet = true;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+ } );
+
+ // 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 ) > -1 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+ };
+ }
+ } );
+
+
+
+
+ // Return jQuery for attributes-only inclusion
+
+
+ var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
+
+ jQuery.extend( jQuery.event, {
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = 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( "." ) > -1 ) {
+
+ // 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.rnamespace = 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 = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
+ dataPriv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === 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 ) &&
+ 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;
+ },
+
+ // Piggyback on a donor event to simulate a different one
+ // Used only for `focus(in | out)` events
+ simulate: function( type, elem, event ) {
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true
+ }
+ );
+
+ jQuery.event.trigger( e, null, elem );
+ }
+
+ } );
+
+ jQuery.fn.extend( {
+
+ 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 );
+ }
+ }
+ } );
+
+
+ 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 );
+ }
+ } );
+
+
+
+
+ support.focusin = "onfocusin" in window;
+
+
+ // Support: Firefox
+ // Firefox doesn't have focus(in | out) events
+ // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+ //
+ // Support: Chrome, Safari
+ // focus(in | out) events fire after focus & blur events,
+ // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+ // Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
+ if ( !support.focusin ) {
+ jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = dataPriv.access( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = dataPriv.access( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ dataPriv.remove( doc, fix );
+
+ } else {
+ dataPriv.access( doc, fix, attaches );
+ }
+ }
+ };
+ } );
+ }
+ var location = window.location;
+
+ var nonce = jQuery.now();
+
+ var rquery = ( /\?/ );
+
+
+
+ // Support: Android 2.3
+ // Workaround failure to string-cast null input
+ jQuery.parseJSON = function( data ) {
+ return JSON.parse( data + "" );
+ };
+
+
+ // Cross-browser xml parsing
+ jQuery.parseXML = function( data ) {
+ var xml;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE9
+ try {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {
+ xml = undefined;
+ }
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ };
+
+
+ var
+ 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 = /^\/\//,
+
+ /* 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( "*" ),
+
+ // Anchor tag for parsing the document origin
+ originAnchor = document.createElement( "a" );
+ originAnchor.href = location.href;
+
+ // 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( 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;
+ }
+
+ /* 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 };
+ }
+
+ jQuery.extend( {
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: location.href,
+ type: "GET",
+ isLocal: rlocalProtocol.test( location.protocol ),
+ 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: /\bxml\b/,
+ html: /\bhtml/,
+ json: /\bjson\b/
+ },
+
+ 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,
+
+ // Url cleanup var
+ urlAnchor,
+
+ // 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 || location.href ) + "" ).replace( rhash, "" )
+ .replace( rprotocol, location.protocol + "//" );
+
+ // 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( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when the origin doesn't match the current origin.
+ if ( s.crossDomain == null ) {
+ urlAnchor = document.createElement( "a" );
+
+ // Support: IE8-11+
+ // IE throws exception if url is malformed, e.g. http://example.com:80x/
+ try {
+ urlAnchor.href = s.url;
+
+ // Support: IE8-11+
+ // Anchor's host property isn't correctly set when s.url is relative
+ urlAnchor.href = urlAnchor.href;
+ s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+ urlAnchor.protocol + "//" + urlAnchor.host;
+ } catch ( e ) {
+
+ // If there is an error parsing the URL, assume it is crossDomain,
+ // it can be rejected by the transport if it is invalid
+ s.crossDomain = true;
+ }
+ }
+
+ // 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
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && 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 += ( 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_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + 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 ] );
+ }
+
+ // If request was aborted inside ajaxSend, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = window.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 ) {
+ window.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 {
+
+ // Extract error from statusText and normalize 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;
+ }
+
+ // The url can be an options object (which then must have .url)
+ return jQuery.ajax( jQuery.extend( {
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ }, jQuery.isPlainObject( url ) && url ) );
+ };
+ } );
+
+
+ jQuery._evalUrl = function( url ) {
+ return jQuery.ajax( {
+ url: url,
+
+ // Make this explicit, since user can override this through ajaxSetup (#11264)
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ } );
+ };
+
+
+ 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();
+ }
+ } );
+
+
+ jQuery.expr.filters.hidden = function( elem ) {
+ return !jQuery.expr.filters.visible( elem );
+ };
+ jQuery.expr.filters.visible = function( elem ) {
+
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ // Use OR instead of AND as the element is not visible if either is true
+ // See tickets #10406 and #13132
+ return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0;
+ };
+
+
+
+
+ var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+ 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" && v != null ? 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 );
+ }
+ }
+
+ // 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, "+" );
+ };
+
+ 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 || !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();
+ }
+ } );
+
+
+ jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch ( e ) {}
+ };
+
+ var 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
+ },
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+ support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+ support.ajax = xhrSupported = !!xhrSupported;
+
+ jQuery.ajaxTransport( function( options ) {
+ var callback, errorCallback;
+
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ 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 ) {
+ callback = errorCallback = xhr.onload =
+ xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+
+ // Support: IE9
+ // On a manual native abort, IE9 throws
+ // errors on any property access that is not readyState
+ if ( typeof xhr.status !== "number" ) {
+ complete( 0, "error" );
+ } else {
+ complete(
+
+ // File: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
+ }
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+
+ // Support: IE9 only
+ // IE9 has no XHR2 but throws on binary (trac-11426)
+ // For XHR2 non-text, let the caller handle it (gh-2498)
+ ( xhr.responseType || "text" ) !== "text" ||
+ typeof xhr.responseText !== "string" ?
+ { binary: xhr.response } :
+ { text: xhr.responseText },
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ errorCallback = xhr.onerror = callback( "error" );
+
+ // Support: IE9
+ // Use onreadystatechange to replace onabort
+ // to handle uncaught aborts
+ if ( xhr.onabort !== undefined ) {
+ xhr.onabort = errorCallback;
+ } else {
+ xhr.onreadystatechange = function() {
+
+ // Check readyState before timeout as it changes
+ if ( xhr.readyState === 4 ) {
+
+ // Allow onerror to be called first,
+ // but that will not handle a native abort
+ // Also, save errorCallback to a variable
+ // as xhr.onerror cannot be accessed
+ window.setTimeout( function() {
+ if ( callback ) {
+ errorCallback();
+ }
+ } );
+ }
+ };
+ }
+
+ // Create the abort callback
+ callback = callback( "abort" );
+
+ try {
+
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+
+ // #14683: Only rethrow if this hasn't been notified as an error yet
+ if ( callback ) {
+ throw e;
+ }
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+ } );
+
+
+
+
+ // Install script dataType
+ jQuery.ajaxSetup( {
+ accepts: {
+ script: "text/javascript, application/javascript, " +
+ "application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /\b(?:java|ecma)script\b/
+ },
+ 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( {
+ 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 );
+ }
+ }
+ );
+
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ 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 + "_" + ( 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" ) === 0 &&
+ 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 += ( 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() {
+
+ // If previous value didn't exist - remove it
+ if ( overwritten === undefined ) {
+ jQuery( window ).removeProp( callbackName );
+
+ // Otherwise restore preexisting value
+ } else {
+ 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";
+ }
+ } );
+
+
+
+
+ // Argument "data" should be 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
+ jQuery.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 = buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+ };
+
+
+ // Keep a copy of the old load method
+ var _load = jQuery.fn.load;
+
+ /**
+ * Load a url into a page
+ */
+ 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 > -1 ) {
+ selector = jQuery.trim( 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.
+ // Make value of this field explicit since
+ // user can override it through ajaxSetup method
+ type: type || "GET",
+ 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 );
+
+ // If the request succeeds, this function gets "data", "status", "jqXHR"
+ // but they are ignored because response was set above.
+ // If it fails, this function gets "jqXHR", "status", "error"
+ } ).always( callback && function( jqXHR, status ) {
+ self.each( function() {
+ callback.apply( this, 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.expr.filters.animated = function( elem ) {
+ return jQuery.grep( jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ } ).length;
+ };
+
+
+
+
+ /**
+ * Gets a window from an element
+ */
+ function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
+ }
+
+ 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 ) ) {
+
+ // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+ options = options.call( elem, i, jQuery.extend( {}, 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( {
+ 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;
+ }
+
+ box = elem.getBoundingClientRect();
+ win = getWindow( doc );
+ return {
+ top: box.top + win.pageYOffset - docElem.clientTop,
+ left: box.left + win.pageXOffset - docElem.clientLeft
+ };
+ },
+
+ 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 its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+
+ // Assume getBoundingClientRect is there 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 )
+ };
+ },
+
+ // This method will return documentElement in the following cases:
+ // 1) For the element inside the iframe without offsetParent, this method will return
+ // documentElement of the parent window
+ // 2) For the hidden or detached element
+ // 3) For body or html element, i.e. in case of the html node - it will return itself
+ //
+ // but those exceptions were never presented as a real life use-cases
+ // and might be considered as more preferable results.
+ //
+ // This logic, however, is not guaranteed and can change at any point in the future
+ offsetParent: function() {
+ return this.map( function() {
+ var offsetParent = this.offsetParent;
+
+ while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || documentElement;
+ } );
+ }
+ } );
+
+ // Create scrollLeft and scrollTop methods
+ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return 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 : win.pageXOffset,
+ top ? val : win.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length );
+ };
+ } );
+
+ // Support: Safari<7-8+, Chrome<37-44+
+ // Add the top/left cssHooks using jQuery.fn.position
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
+ // getComputedStyle returns percent when specified for top/left/bottom/right;
+ // rather than make the css module depend on the offset module, just check for it here
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ 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;
+ }
+ }
+ );
+ } );
+
+
+ // 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 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 );
+ };
+ } );
+ } );
+
+
+ jQuery.fn.extend( {
+
+ 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 );
+ },
+ size: function() {
+ return this.length;
+ }
+ } );
+
+ jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+ // 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.
+
+ // Note that for maximum portability, libraries that are not jQuery should
+ // declare themselves as anonymous modules, and avoid setting a global if an
+ // AMD loader is present. jQuery is a special case. For more information, see
+ // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+ if ( true ) {
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() {
+ return jQuery;
+ }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+ }
+
+
+
+ var
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+ jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ };
+
+ // Expose jQuery and $ identifiers, even in AMD
+ // (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+ // and CommonJS for browser emulators (#13566)
+ if ( !noGlobal ) {
+ window.jQuery = window.$ = jQuery;
+ }
+
+ return jQuery;
+ }));
+
+
+/***/ }
+/******/ ]);
\ No newline at end of file