123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.page=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
- (function (process){
- /* globals require, module */
-
- 'use strict';
-
- /**
- * Module dependencies.
- */
-
- var pathtoRegexp = require('path-to-regexp');
-
- /**
- * Module exports.
- */
-
- module.exports = page;
-
- /**
- * Detect click event
- */
- var clickEvent = ('undefined' !== typeof document) && document.ontouchstart ? 'touchstart' : 'click';
-
- /**
- * To work properly with the URL
- * history.location generated polyfill in https://github.com/devote/HTML5-History-API
- */
-
- var location = ('undefined' !== typeof window) && (window.history.location || window.location);
-
- /**
- * Perform initial dispatch.
- */
-
- var dispatch = true;
-
-
- /**
- * Decode URL components (query string, pathname, hash).
- * Accommodates both regular percent encoding and x-www-form-urlencoded format.
- */
- var decodeURLComponents = true;
-
- /**
- * Base path.
- */
-
- var base = '';
-
- /**
- * Running flag.
- */
-
- var running;
-
- /**
- * HashBang option
- */
-
- var hashbang = false;
-
- /**
- * Previous context, for capturing
- * page exit events.
- */
-
- var prevContext;
-
- /**
- * Register `path` with callback `fn()`,
- * or route `path`, or redirection,
- * or `page.start()`.
- *
- * page(fn);
- * page('*', fn);
- * page('/user/:id', load, user);
- * page('/user/' + user.id, { some: 'thing' });
- * page('/user/' + user.id);
- * page('/from', '/to')
- * page();
- *
- * @param {String|Function} path
- * @param {Function} fn...
- * @api public
- */
-
- function page(path, fn) {
- // <callback>
- if ('function' === typeof path) {
- return page('*', path);
- }
-
- // route <path> to <callback ...>
- if ('function' === typeof fn) {
- var route = new Route(path);
- for (var i = 1; i < arguments.length; ++i) {
- page.callbacks.push(route.middleware(arguments[i]));
- }
- // show <path> with [state]
- } else if ('string' === typeof path) {
- page['string' === typeof fn ? 'redirect' : 'show'](path, fn);
- // start [options]
- } else {
- page.start(path);
- }
- }
-
- /**
- * Callback functions.
- */
-
- page.callbacks = [];
- page.exits = [];
-
- /**
- * Current path being processed
- * @type {String}
- */
- page.current = '';
-
- /**
- * Number of pages navigated to.
- * @type {number}
- *
- * page.len == 0;
- * page('/login');
- * page.len == 1;
- */
-
- page.len = 0;
-
- /**
- * Get or set basepath to `path`.
- *
- * @param {String} path
- * @api public
- */
-
- page.base = function(path) {
- if (0 === arguments.length) return base;
- base = path;
- };
-
- /**
- * Bind with the given `options`.
- *
- * Options:
- *
- * - `click` bind to click events [true]
- * - `popstate` bind to popstate [true]
- * - `dispatch` perform initial dispatch [true]
- *
- * @param {Object} options
- * @api public
- */
-
- page.start = function(options) {
- options = options || {};
- if (running) return;
- running = true;
- if (false === options.dispatch) dispatch = false;
- if (false === options.decodeURLComponents) decodeURLComponents = false;
- if (false !== options.popstate) window.addEventListener('popstate', onpopstate, false);
- if (false !== options.click) {
- document.addEventListener(clickEvent, onclick, false);
- }
- if (true === options.hashbang) hashbang = true;
- if (!dispatch) return;
- var url = (hashbang && ~location.hash.indexOf('#!')) ? location.hash.substr(2) + location.search : location.pathname + location.search + location.hash;
- page.replace(url, null, true, dispatch);
- };
-
- /**
- * Unbind click and popstate event handlers.
- *
- * @api public
- */
-
- page.stop = function() {
- if (!running) return;
- page.current = '';
- page.len = 0;
- running = false;
- document.removeEventListener(clickEvent, onclick, false);
- window.removeEventListener('popstate', onpopstate, false);
- };
-
- /**
- * Show `path` with optional `state` object.
- *
- * @param {String} path
- * @param {Object} state
- * @param {Boolean} dispatch
- * @return {Context}
- * @api public
- */
-
- page.show = function(path, state, dispatch, push) {
- var ctx = new Context(path, state);
- page.current = ctx.path;
- if (false !== dispatch) page.dispatch(ctx);
- if (false !== ctx.handled && false !== push) ctx.pushState();
- return ctx;
- };
-
- /**
- * Goes back in the history
- * Back should always let the current route push state and then go back.
- *
- * @param {String} path - fallback path to go back if no more history exists, if undefined defaults to page.base
- * @param {Object} [state]
- * @api public
- */
-
- page.back = function(path, state) {
- if (page.len > 0) {
- // this may need more testing to see if all browsers
- // wait for the next tick to go back in history
- history.back();
- page.len--;
- } else if (path) {
- setTimeout(function() {
- page.show(path, state);
- });
- }else{
- setTimeout(function() {
- page.show(base, state);
- });
- }
- };
-
-
- /**
- * Register route to redirect from one path to other
- * or just redirect to another route
- *
- * @param {String} from - if param 'to' is undefined redirects to 'from'
- * @param {String} [to]
- * @api public
- */
- page.redirect = function(from, to) {
- // Define route from a path to another
- if ('string' === typeof from && 'string' === typeof to) {
- page(from, function(e) {
- setTimeout(function() {
- page.replace(to);
- }, 0);
- });
- }
-
- // Wait for the push state and replace it with another
- if ('string' === typeof from && 'undefined' === typeof to) {
- setTimeout(function() {
- page.replace(from);
- }, 0);
- }
- };
-
- /**
- * Replace `path` with optional `state` object.
- *
- * @param {String} path
- * @param {Object} state
- * @return {Context}
- * @api public
- */
-
-
- page.replace = function(path, state, init, dispatch) {
- var ctx = new Context(path, state);
- page.current = ctx.path;
- ctx.init = init;
- ctx.save(); // save before dispatching, which may redirect
- if (false !== dispatch) page.dispatch(ctx);
- return ctx;
- };
-
- /**
- * Dispatch the given `ctx`.
- *
- * @param {Object} ctx
- * @api private
- */
-
- page.dispatch = function(ctx) {
- var prev = prevContext,
- i = 0,
- j = 0;
-
- prevContext = ctx;
-
- function nextExit() {
- var fn = page.exits[j++];
- if (!fn) return nextEnter();
- fn(prev, nextExit);
- }
-
- function nextEnter() {
- var fn = page.callbacks[i++];
-
- if (ctx.path !== page.current) {
- ctx.handled = false;
- return;
- }
- if (!fn) return unhandled(ctx);
- fn(ctx, nextEnter);
- }
-
- if (prev) {
- nextExit();
- } else {
- nextEnter();
- }
- };
-
- /**
- * Unhandled `ctx`. When it's not the initial
- * popstate then redirect. If you wish to handle
- * 404s on your own use `page('*', callback)`.
- *
- * @param {Context} ctx
- * @api private
- */
-
- function unhandled(ctx) {
- if (ctx.handled) return;
- var current;
-
- if (hashbang) {
- current = base + location.hash.replace('#!', '');
- } else {
- current = location.pathname + location.search;
- }
-
- if (current === ctx.canonicalPath) return;
- page.stop();
- ctx.handled = false;
- location.href = ctx.canonicalPath;
- }
-
- /**
- * Register an exit route on `path` with
- * callback `fn()`, which will be called
- * on the previous context when a new
- * page is visited.
- */
- page.exit = function(path, fn) {
- if (typeof path === 'function') {
- return page.exit('*', path);
- }
-
- var route = new Route(path);
- for (var i = 1; i < arguments.length; ++i) {
- page.exits.push(route.middleware(arguments[i]));
- }
- };
-
- /**
- * Remove URL encoding from the given `str`.
- * Accommodates whitespace in both x-www-form-urlencoded
- * and regular percent-encoded form.
- *
- * @param {str} URL component to decode
- */
- function decodeURLEncodedURIComponent(val) {
- if (typeof val !== 'string') { return val; }
- return decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, ' ')) : val;
- }
-
- /**
- * Initialize a new "request" `Context`
- * with the given `path` and optional initial `state`.
- *
- * @param {String} path
- * @param {Object} state
- * @api public
- */
-
- function Context(path, state) {
- if ('/' === path[0] && 0 !== path.indexOf(base)) path = base + (hashbang ? '#!' : '') + path;
- var i = path.indexOf('?');
-
- this.canonicalPath = path;
- this.path = path.replace(base, '') || '/';
- if (hashbang) this.path = this.path.replace('#!', '') || '/';
-
- this.title = document.title;
- this.state = state || {};
- this.state.path = path;
- this.querystring = ~i ? decodeURLEncodedURIComponent(path.slice(i + 1)) : '';
- this.pathname = decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path);
- this.params = {};
-
- // fragment
- this.hash = '';
- if (!hashbang) {
- if (!~this.path.indexOf('#')) return;
- var parts = this.path.split('#');
- this.path = parts[0];
- this.hash = decodeURLEncodedURIComponent(parts[1]) || '';
- this.querystring = this.querystring.split('#')[0];
- }
- }
-
- /**
- * Expose `Context`.
- */
-
- page.Context = Context;
-
- /**
- * Push state.
- *
- * @api private
- */
-
- Context.prototype.pushState = function() {
- page.len++;
- history.pushState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
- };
-
- /**
- * Save the context state.
- *
- * @api public
- */
-
- Context.prototype.save = function() {
- history.replaceState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
- };
-
- /**
- * Initialize `Route` with the given HTTP `path`,
- * and an array of `callbacks` and `options`.
- *
- * Options:
- *
- * - `sensitive` enable case-sensitive routes
- * - `strict` enable strict matching for trailing slashes
- *
- * @param {String} path
- * @param {Object} options.
- * @api private
- */
-
- function Route(path, options) {
- options = options || {};
- this.path = (path === '*') ? '(.*)' : path;
- this.method = 'GET';
- this.regexp = pathtoRegexp(this.path,
- this.keys = [],
- options.sensitive,
- options.strict);
- }
-
- /**
- * Expose `Route`.
- */
-
- page.Route = Route;
-
- /**
- * Return route middleware with
- * the given callback `fn()`.
- *
- * @param {Function} fn
- * @return {Function}
- * @api public
- */
-
- Route.prototype.middleware = function(fn) {
- var self = this;
- return function(ctx, next) {
- if (self.match(ctx.path, ctx.params)) return fn(ctx, next);
- next();
- };
- };
-
- /**
- * Check if this route matches `path`, if so
- * populate `params`.
- *
- * @param {String} path
- * @param {Object} params
- * @return {Boolean}
- * @api private
- */
-
- Route.prototype.match = function(path, params) {
- var keys = this.keys,
- qsIndex = path.indexOf('?'),
- pathname = ~qsIndex ? path.slice(0, qsIndex) : path,
- m = this.regexp.exec(decodeURIComponent(pathname));
-
- if (!m) return false;
-
- for (var i = 1, len = m.length; i < len; ++i) {
- var key = keys[i - 1];
- var val = decodeURLEncodedURIComponent(m[i]);
- if (val !== undefined || !(hasOwnProperty.call(params, key.name))) {
- params[key.name] = val;
- }
- }
-
- return true;
- };
-
-
- /**
- * Handle "populate" events.
- */
-
- var onpopstate = (function () {
- var loaded = false;
- if ('undefined' === typeof window) {
- return;
- }
- if (document.readyState === 'complete') {
- loaded = true;
- } else {
- window.addEventListener('load', function() {
- setTimeout(function() {
- loaded = true;
- }, 0);
- });
- }
- return function onpopstate(e) {
- if (!loaded) return;
- if (e.state) {
- var path = e.state.path;
- page.replace(path, e.state);
- } else {
- page.show(location.pathname + location.hash, undefined, undefined, false);
- }
- };
- })();
- /**
- * Handle "click" events.
- */
-
- function onclick(e) {
-
- if (1 !== which(e)) return;
-
- if (e.metaKey || e.ctrlKey || e.shiftKey) return;
- if (e.defaultPrevented) return;
-
-
-
- // ensure link
- var el = e.target;
- while (el && 'A' !== el.nodeName) el = el.parentNode;
- if (!el || 'A' !== el.nodeName) return;
-
-
-
- // Ignore if tag has
- // 1. "download" attribute
- // 2. rel="external" attribute
- if (el.hasAttribute('download') || el.getAttribute('rel') === 'external') return;
-
- // ensure non-hash for the same path
- var link = el.getAttribute('href');
- if (!hashbang && el.pathname === location.pathname && (el.hash || '#' === link)) return;
-
-
-
- // Check for mailto: in the href
- if (link && link.indexOf('mailto:') > -1) return;
-
- // check target
- if (el.target) return;
-
- // x-origin
- if (!sameOrigin(el.href)) return;
-
-
-
- // rebuild path
- var path = el.pathname + el.search + (el.hash || '');
-
- // strip leading "/[drive letter]:" on NW.js on Windows
- if (typeof process !== 'undefined' && path.match(/^\/[a-zA-Z]:\//)) {
- path = path.replace(/^\/[a-zA-Z]:\//, '/');
- }
-
- // same page
- var orig = path;
-
- if (path.indexOf(base) === 0) {
- path = path.substr(base.length);
- }
-
- if (hashbang) path = path.replace('#!', '');
-
- if (base && orig === path) return;
-
- e.preventDefault();
- page.show(orig);
- }
-
- /**
- * Event button.
- */
-
- function which(e) {
- e = e || window.event;
- return null === e.which ? e.button : e.which;
- }
-
- /**
- * Check if `href` is the same origin.
- */
-
- function sameOrigin(href) {
- var origin = location.protocol + '//' + location.hostname;
- if (location.port) origin += ':' + location.port;
- return (href && (0 === href.indexOf(origin)));
- }
-
- page.sameOrigin = sameOrigin;
-
- }).call(this,require('_process'))
- },{"_process":2,"path-to-regexp":3}],2:[function(require,module,exports){
- // shim for using process in browser
-
- var process = module.exports = {};
-
- process.nextTick = (function () {
- var canSetImmediate = typeof window !== 'undefined'
- && window.setImmediate;
- var canMutationObserver = typeof window !== 'undefined'
- && window.MutationObserver;
- var canPost = typeof window !== 'undefined'
- && window.postMessage && window.addEventListener
- ;
-
- if (canSetImmediate) {
- return function (f) { return window.setImmediate(f) };
- }
-
- var queue = [];
-
- if (canMutationObserver) {
- var hiddenDiv = document.createElement("div");
- var observer = new MutationObserver(function () {
- var queueList = queue.slice();
- queue.length = 0;
- queueList.forEach(function (fn) {
- fn();
- });
- });
-
- observer.observe(hiddenDiv, { attributes: true });
-
- return function nextTick(fn) {
- if (!queue.length) {
- hiddenDiv.setAttribute('yes', 'no');
- }
- queue.push(fn);
- };
- }
-
- if (canPost) {
- window.addEventListener('message', function (ev) {
- var source = ev.source;
- if ((source === window || source === null) && ev.data === 'process-tick') {
- ev.stopPropagation();
- if (queue.length > 0) {
- var fn = queue.shift();
- fn();
- }
- }
- }, true);
-
- return function nextTick(fn) {
- queue.push(fn);
- window.postMessage('process-tick', '*');
- };
- }
-
- return function nextTick(fn) {
- setTimeout(fn, 0);
- };
- })();
-
- process.title = 'browser';
- process.browser = true;
- process.env = {};
- process.argv = [];
-
- function noop() {}
-
- process.on = noop;
- process.addListener = noop;
- process.once = noop;
- process.off = noop;
- process.removeListener = noop;
- process.removeAllListeners = noop;
- process.emit = noop;
-
- process.binding = function (name) {
- throw new Error('process.binding is not supported');
- };
-
- // TODO(shtylman)
- process.cwd = function () { return '/' };
- process.chdir = function (dir) {
- throw new Error('process.chdir is not supported');
- };
-
- },{}],3:[function(require,module,exports){
- var isArray = require('isarray');
-
- /**
- * Expose `pathToRegexp`.
- */
- module.exports = pathToRegexp;
-
- /**
- * The main path matching regexp utility.
- *
- * @type {RegExp}
- */
- var PATH_REGEXP = new RegExp([
- // Match escaped characters that would otherwise appear in future matches.
- // This allows the user to escape special characters that won't transform.
- '(\\\\.)',
- // Match Express-style parameters and un-named parameters with a prefix
- // and optional suffixes. Matches appear as:
- //
- // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
- // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
- '([\\/.])?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^)])*)\\))?|\\(((?:\\\\.|[^)])*)\\))([+*?])?',
- // Match regexp special characters that are always escaped.
- '([.+*?=^!:${}()[\\]|\\/])'
- ].join('|'), 'g');
-
- /**
- * Escape the capturing group by escaping special characters and meaning.
- *
- * @param {String} group
- * @return {String}
- */
- function escapeGroup (group) {
- return group.replace(/([=!:$\/()])/g, '\\$1');
- }
-
- /**
- * Attach the keys as a property of the regexp.
- *
- * @param {RegExp} re
- * @param {Array} keys
- * @return {RegExp}
- */
- function attachKeys (re, keys) {
- re.keys = keys;
- return re;
- }
-
- /**
- * Get the flags for a regexp from the options.
- *
- * @param {Object} options
- * @return {String}
- */
- function flags (options) {
- return options.sensitive ? '' : 'i';
- }
-
- /**
- * Pull out keys from a regexp.
- *
- * @param {RegExp} path
- * @param {Array} keys
- * @return {RegExp}
- */
- function regexpToRegexp (path, keys) {
- // Use a negative lookahead to match only capturing groups.
- var groups = path.source.match(/\((?!\?)/g);
-
- if (groups) {
- for (var i = 0; i < groups.length; i++) {
- keys.push({
- name: i,
- delimiter: null,
- optional: false,
- repeat: false
- });
- }
- }
-
- return attachKeys(path, keys);
- }
-
- /**
- * Transform an array into a regexp.
- *
- * @param {Array} path
- * @param {Array} keys
- * @param {Object} options
- * @return {RegExp}
- */
- function arrayToRegexp (path, keys, options) {
- var parts = [];
-
- for (var i = 0; i < path.length; i++) {
- parts.push(pathToRegexp(path[i], keys, options).source);
- }
-
- var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
- return attachKeys(regexp, keys);
- }
-
- /**
- * Replace the specific tags with regexp strings.
- *
- * @param {String} path
- * @param {Array} keys
- * @return {String}
- */
- function replacePath (path, keys) {
- var index = 0;
-
- function replace (_, escaped, prefix, key, capture, group, suffix, escape) {
- if (escaped) {
- return escaped;
- }
-
- if (escape) {
- return '\\' + escape;
- }
-
- var repeat = suffix === '+' || suffix === '*';
- var optional = suffix === '?' || suffix === '*';
-
- keys.push({
- name: key || index++,
- delimiter: prefix || '/',
- optional: optional,
- repeat: repeat
- });
-
- prefix = prefix ? ('\\' + prefix) : '';
- capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');
-
- if (repeat) {
- capture = capture + '(?:' + prefix + capture + ')*';
- }
-
- if (optional) {
- return '(?:' + prefix + '(' + capture + '))?';
- }
-
- // Basic parameter support.
- return prefix + '(' + capture + ')';
- }
-
- return path.replace(PATH_REGEXP, replace);
- }
-
- /**
- * Normalize the given path string, returning a regular expression.
- *
- * An empty array can be passed in for the keys, which will hold the
- * placeholder key descriptions. For example, using `/user/:id`, `keys` will
- * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
- *
- * @param {(String|RegExp|Array)} path
- * @param {Array} [keys]
- * @param {Object} [options]
- * @return {RegExp}
- */
- function pathToRegexp (path, keys, options) {
- keys = keys || [];
-
- if (!isArray(keys)) {
- options = keys;
- keys = [];
- } else if (!options) {
- options = {};
- }
-
- if (path instanceof RegExp) {
- return regexpToRegexp(path, keys, options);
- }
-
- if (isArray(path)) {
- return arrayToRegexp(path, keys, options);
- }
-
- var strict = options.strict;
- var end = options.end !== false;
- var route = replacePath(path, keys);
- var endsWithSlash = path.charAt(path.length - 1) === '/';
-
- // In non-strict mode we allow a slash at the end of match. If the path to
- // match already ends with a slash, we remove it for consistency. The slash
- // is valid at the end of a path match, not in the middle. This is important
- // in non-ending mode, where "/test/" shouldn't match "/test//route".
- if (!strict) {
- route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?';
- }
-
- if (end) {
- route += '$';
- } else {
- // In non-ending mode, we need the capturing groups to match as much as
- // possible by using a positive lookahead to the end or next path segment.
- route += strict && endsWithSlash ? '' : '(?=\\/|$)';
- }
-
- return attachKeys(new RegExp('^' + route, flags(options)), keys);
- }
-
- },{"isarray":4}],4:[function(require,module,exports){
- module.exports = Array.isArray || function (arr) {
- return Object.prototype.toString.call(arr) == '[object Array]';
- };
-
- },{}]},{},[1])(1)
- });
|