Source: polyfills.js

/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
;if("document" in self&&!("classList" in document.createElement("_"))){(function(j){"use strict";if(!("Element" in j)){return}var a="classList",f="prototype",m=j.Element[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===""){throw new n("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(o)){throw new n("INVALID_CHARACTER_ERR","String contains an invalid character")}return c.call(p,o)},d=function(s){var r=k.call(s.getAttribute("class")||""),q=r?r.split(/\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.setAttribute("class",this.toString())}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+="";return g(this,o)!==-1};e.add=function(){var s=arguments,r=0,p=s.length,q,o=false;do{q=s[r]+"";if(g(this,q)===-1){this.push(q);o=true}}while(++r<p);if(o){this._updateClassName()}};e.remove=function(){var t=arguments,s=0,p=t.length,r,o=false;do{r=t[s]+"";var q=g(this,r);if(q!==-1){this.splice(q,1);o=true}}while(++s<p);if(o){this._updateClassName()}};e.toggle=function(p,q){p+="";var o=this.contains(p),r=o?q!==true&&"remove":q!==false&&"add";if(r){this[r](p)}return !o};e.toString=function(){return this.join(" ")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))};

/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */

window.matchMedia || (window.matchMedia = function() {
    "use strict";

    // For browsers that support matchMedium api such as IE 9 and webkit
    var styleMedia = (window.styleMedia || window.media);

    // For those that don't support matchMedium
    if (!styleMedia) {
        var style       = document.createElement('style'),
            script      = document.getElementsByTagName('script')[0],
            info        = null;

        style.type  = 'text/css';
        style.id    = 'matchmediajs-test';

        script.parentNode.insertBefore(style, script);

        // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
        info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;

        styleMedia = {
            matchMedium: function(media) {
                var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';

                // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
                if (style.styleSheet) {
                    style.styleSheet.cssText = text;
                } else {
                    style.textContent = text;
                }

                // Test if media query is true or false
                return info.width === '1px';
            }
        };
    }

    return function(media) {
        return {
            matches: styleMedia.matchMedium(media || 'all'),
            media: media || 'all'
        };
    };
}());

(function(){
    if (!Element.prototype.matches)
        Element.prototype.matches = Element.prototype.msMatchesSelector ||
            Element.prototype.webkitMatchesSelector;

    if (!Element.prototype.closest)
        Element.prototype.closest = function(s) {
            var el = this;
            var ancestor = this;
            if (!document.documentElement.contains(el)) return null;
            do {
                if (ancestor.matches(s)) return ancestor;
                ancestor = ancestor.parentElement;
            } while (ancestor !== null);
            return null;
        };
}());

/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
(function(){
    // Bail out for browsers that have addListener support
    if (window.matchMedia && window.matchMedia('all').addListener) {
        return false;
    }

    var localMatchMedia = window.matchMedia,
        hasMediaQueries = localMatchMedia('only all').matches,
        isListening     = false,
        timeoutID       = 0,    // setTimeout for debouncing 'handleChange'
        queries         = [],   // Contains each 'mql' and associated 'listeners' if 'addListener' is used
        handleChange    = function(evt) {
            // Debounce
            clearTimeout(timeoutID);

            timeoutID = setTimeout(function() {
                for (var i = 0, il = queries.length; i < il; i++) {
                    var mql         = queries[i].mql,
                        listeners   = queries[i].listeners || [],
                        matches     = localMatchMedia(mql.media).matches;

                    // Update mql.matches value and call listeners
                    // Fire listeners only if transitioning to or from matched state
                    if (matches !== mql.matches) {
                        mql.matches = matches;

                        for (var j = 0, jl = listeners.length; j < jl; j++) {
                            listeners[j].call(window, mql);
                        }
                    }
                }
            }, 30);
        };

    window.matchMedia = function(media) {
        var mql         = localMatchMedia(media),
            listeners   = [],
            index       = 0;

        mql.addListener = function(listener) {
            // Changes would not occur to css media type so return now (Affects IE <= 8)
            if (!hasMediaQueries) {
                return;
            }

            // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8)
            // There should only ever be 1 resize listener running for performance
            if (!isListening) {
                isListening = true;
                window.addEventListener('resize', handleChange, true);
            }

            // Push object only if it has not been pushed already
            if (index === 0) {
                index = queries.push({
                    mql         : mql,
                    listeners   : listeners
                });
            }

            listeners.push(listener);
        };

        mql.removeListener = function(listener) {
            for (var i = 0, il = listeners.length; i < il; i++){
                if (listeners[i] === listener){
                    listeners.splice(i, 1);
                }
            }
        };

        return mql;
    };
}());

/* Mutation Observer */
var MutationObserver = window.MutationObserver
    || window.WebKitMutationObserver
    || window.MozMutationObserver;

/*
 * Copyright 2012 The Polymer Authors. All rights reserved.
 * Use of this source code is goverened by a BSD-style
 * license that can be found in the LICENSE file.
 */

var WeakMap = window.WeakMap;

if (typeof WeakMap === 'undefined') {
    var defineProperty = Object.defineProperty;
    var counter = Date.now() % 1e9;

    WeakMap = function() {
        this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
    };

    WeakMap.prototype = {
        set: function(key, value) {
            var entry = key[this.name];
            if (entry && entry[0] === key)
                entry[1] = value;
            else
                defineProperty(key, this.name, {value: [key, value], writable: true});
            return this;
        },
        get: function(key) {
            var entry;
            return (entry = key[this.name]) && entry[0] === key ?
                entry[1] : undefined;
        },
        'delete': function(key) {
            var entry = key[this.name];
            if (!entry) return false;
            var hasValue = entry[0] === key;
            entry[0] = entry[1] = undefined;
            return hasValue;
        },
        has: function(key) {
            var entry = key[this.name];
            if (!entry) return false;
            return entry[0] === key;
        }
    };
}

var registrationsTable = new WeakMap();

// We use setImmediate or postMessage for our future callback.
var setImmediate = window.msSetImmediate;

// Use post message to emulate setImmediate.
if (!setImmediate) {
    var setImmediateQueue = [];
    var sentinel = String(Math.random());
    window.addEventListener('message', function(e) {
        if (e.data === sentinel) {
            var queue = setImmediateQueue;
            setImmediateQueue = [];
            queue.forEach(function(func) {
                func();
            });
        }
    });
    setImmediate = function(func) {
        setImmediateQueue.push(func);
        window.postMessage(sentinel, '*');
    };
}

// This is used to ensure that we never schedule 2 callas to setImmediate
var isScheduled = false;

// Keep track of observers that needs to be notified next time.
var scheduledObservers = [];

/**
 * Schedules |dispatchCallback| to be called in the future.
 * @param {MutationObserver} observer
 */
function scheduleCallback(observer) {
    scheduledObservers.push(observer);
    if (!isScheduled) {
        isScheduled = true;
        setImmediate(dispatchCallbacks);
    }
}

function wrapIfNeeded(node) {
    return window.ShadowDOMPolyfill &&
        window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
        node;
}

function dispatchCallbacks() {
    // http://dom.spec.whatwg.org/#mutation-observers

    isScheduled = false; // Used to allow a new setImmediate call above.

    var observers = scheduledObservers;
    scheduledObservers = [];
    // Sort observers based on their creation UID (incremental).
    observers.sort(function(o1, o2) {
        return o1.uid_ - o2.uid_;
    });

    var anyNonEmpty = false;
    observers.forEach(function(observer) {

        // 2.1, 2.2
        var queue = observer.takeRecords();
        // 2.3. Remove all transient registered observers whose observer is mo.
        removeTransientObserversFor(observer);

        // 2.4
        if (queue.length) {
            observer.callback_(queue, observer);
            anyNonEmpty = true;
        }
    });

    // 3.
    if (anyNonEmpty)
        dispatchCallbacks();
}

function removeTransientObserversFor(observer) {
    observer.nodes_.forEach(function(node) {
        var registrations = registrationsTable.get(node);
        if (!registrations)
            return;
        registrations.forEach(function(registration) {
            if (registration.observer === observer)
                registration.removeTransientObservers();
        });
    });
}

/**
 * This function is used for the "For each registered observer observer (with
 * observer's options as options) in target's list of registered observers,
 * run these substeps:" and the "For each ancestor ancestor of target, and for
 * each registered observer observer (with options options) in ancestor's list
 * of registered observers, run these substeps:" part of the algorithms. The
 * |options.subtree| is checked to ensure that the callback is called
 * correctly.
 *
 * @param {Node} target
 * @param {function(MutationObserverInit):MutationRecord} callback
 */
function forEachAncestorAndObserverEnqueueRecord(target, callback) {
    for (var node = target; node; node = node.parentNode) {
        var registrations = registrationsTable.get(node);

        if (registrations) {
            for (var j = 0; j < registrations.length; j++) {
                var registration = registrations[j];
                var options = registration.options;

                // Only target ignores subtree.
                if (node !== target && !options.subtree)
                    continue;

                var record = callback(options);
                if (record)
                    registration.enqueue(record);
            }
        }
    }
}

var uidCounter = 0;

/**
 * The class that maps to the DOM MutationObserver interface.
 * @param {Function} callback.
 * @constructor
 */
function JsMutationObserver(callback) {
    this.callback_ = callback;
    this.nodes_ = [];
    this.records_ = [];
    this.uid_ = ++uidCounter;
}

JsMutationObserver.prototype = {
    observe: function(target, options) {
        target = wrapIfNeeded(target);

        // 1.1
        if (!options.childList && !options.attributes && !options.characterData ||

            // 1.2
            options.attributeOldValue && !options.attributes ||

            // 1.3
            options.attributeFilter && options.attributeFilter.length &&
            !options.attributes ||

            // 1.4
            options.characterDataOldValue && !options.characterData) {

            throw new SyntaxError();
        }

        var registrations = registrationsTable.get(target);
        if (!registrations)
            registrationsTable.set(target, registrations = []);

        // 2
        // If target's list of registered observers already includes a registered
        // observer associated with the context object, replace that registered
        // observer's options with options.
        var registration;
        for (var i = 0; i < registrations.length; i++) {
            if (registrations[i].observer === this) {
                registration = registrations[i];
                registration.removeListeners();
                registration.options = options;
                break;
            }
        }

        // 3.
        // Otherwise, add a new registered observer to target's list of registered
        // observers with the context object as the observer and options as the
        // options, and add target to context object's list of nodes on which it
        // is registered.
        if (!registration) {
            registration = new Registration(this, target, options);
            registrations.push(registration);
            this.nodes_.push(target);
        }

        registration.addListeners();
    },

    disconnect: function() {
        this.nodes_.forEach(function(node) {
            var registrations = registrationsTable.get(node);
            for (var i = 0; i < registrations.length; i++) {
                var registration = registrations[i];
                if (registration.observer === this) {
                    registration.removeListeners();
                    registrations.splice(i, 1);
                    // Each node can only have one registered observer associated with
                    // this observer.
                    break;
                }
            }
        }, this);
        this.records_ = [];
    },

    takeRecords: function() {
        var copyOfRecords = this.records_;
        this.records_ = [];
        return copyOfRecords;
    }
};

/**
 * @param {string} type
 * @param {Node} target
 * @constructor
 */
function MutationRecord(type, target) {
    this.type = type;
    this.target = target;
    this.addedNodes = [];
    this.removedNodes = [];
    this.previousSibling = null;
    this.nextSibling = null;
    this.attributeName = null;
    this.attributeNamespace = null;
    this.oldValue = null;
}

function copyMutationRecord(original) {
    var record = new MutationRecord(original.type, original.target);
    record.addedNodes = original.addedNodes.slice();
    record.removedNodes = original.removedNodes.slice();
    record.previousSibling = original.previousSibling;
    record.nextSibling = original.nextSibling;
    record.attributeName = original.attributeName;
    record.attributeNamespace = original.attributeNamespace;
    record.oldValue = original.oldValue;
    return record;
};

// We keep track of the two (possibly one) records used in a single mutation.
var currentRecord, recordWithOldValue;

/**
 * Creates a record without |oldValue| and caches it as |currentRecord| for
 * later use.
 * @param {string} oldValue
 * @return {MutationRecord}
 */
function getRecord(type, target) {
    return currentRecord = new MutationRecord(type, target);
}

/**
 * Gets or creates a record with |oldValue| based in the |currentRecord|
 * @param {string} oldValue
 * @return {MutationRecord}
 */
function getRecordWithOldValue(oldValue) {
    if (recordWithOldValue)
        return recordWithOldValue;
    recordWithOldValue = copyMutationRecord(currentRecord);
    recordWithOldValue.oldValue = oldValue;
    return recordWithOldValue;
}

function clearRecords() {
    currentRecord = recordWithOldValue = undefined;
}

/**
 * @param {MutationRecord} record
 * @return {boolean} Whether the record represents a record from the current
 * mutation event.
 */
function recordRepresentsCurrentMutation(record) {
    return record === recordWithOldValue || record === currentRecord;
}

/**
 * Selects which record, if any, to replace the last record in the queue.
 * This returns |null| if no record should be replaced.
 *
 * @param {MutationRecord} lastRecord
 * @param {MutationRecord} newRecord
 * @param {MutationRecord}
 */
function selectRecord(lastRecord, newRecord) {
    if (lastRecord === newRecord)
        return lastRecord;

    // Check if the the record we are adding represents the same record. If
    // so, we keep the one with the oldValue in it.
    if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
        return recordWithOldValue;

    return null;
}

/**
 * Class used to represent a registered observer.
 * @param {MutationObserver} observer
 * @param {Node} target
 * @param {MutationObserverInit} options
 * @constructor
 */
function Registration(observer, target, options) {
    this.observer = observer;
    this.target = target;
    this.options = options;
    this.transientObservedNodes = [];
}

Registration.prototype = {
    enqueue: function(record) {
        var records = this.observer.records_;
        var length = records.length;

        // There are cases where we replace the last record with the new record.
        // For example if the record represents the same mutation we need to use
        // the one with the oldValue. If we get same record (this can happen as we
        // walk up the tree) we ignore the new record.
        if (records.length > 0) {
            var lastRecord = records[length - 1];
            var recordToReplaceLast = selectRecord(lastRecord, record);
            if (recordToReplaceLast) {
                records[length - 1] = recordToReplaceLast;
                return;
            }
        } else {
            scheduleCallback(this.observer);
        }

        records[length] = record;
    },

    addListeners: function() {
        this.addListeners_(this.target);
    },

    addListeners_: function(node) {
        var options = this.options;
        if (options.attributes)
            node.addEventListener('DOMAttrModified', this, true);

        if (options.characterData)
            node.addEventListener('DOMCharacterDataModified', this, true);

        if (options.childList)
            node.addEventListener('DOMNodeInserted', this, true);

        if (options.childList || options.subtree)
            node.addEventListener('DOMNodeRemoved', this, true);
    },

    removeListeners: function() {
        this.removeListeners_(this.target);
    },

    removeListeners_: function(node) {
        var options = this.options;
        if (options.attributes)
            node.removeEventListener('DOMAttrModified', this, true);

        if (options.characterData)
            node.removeEventListener('DOMCharacterDataModified', this, true);

        if (options.childList)
            node.removeEventListener('DOMNodeInserted', this, true);

        if (options.childList || options.subtree)
            node.removeEventListener('DOMNodeRemoved', this, true);
    },

    /**
     * Adds a transient observer on node. The transient observer gets removed
     * next time we deliver the change records.
     * @param {Node} node
     */
    addTransientObserver: function(node) {
        // Don't add transient observers on the target itself. We already have all
        // the required listeners set up on the target.
        if (node === this.target)
            return;

        this.addListeners_(node);
        this.transientObservedNodes.push(node);
        var registrations = registrationsTable.get(node);
        if (!registrations)
            registrationsTable.set(node, registrations = []);

        // We know that registrations does not contain this because we already
        // checked if node === this.target.
        registrations.push(this);
    },

    removeTransientObservers: function() {
        var transientObservedNodes = this.transientObservedNodes;
        this.transientObservedNodes = [];

        transientObservedNodes.forEach(function(node) {
            // Transient observers are never added to the target.
            this.removeListeners_(node);

            var registrations = registrationsTable.get(node);
            for (var i = 0; i < registrations.length; i++) {
                if (registrations[i] === this) {
                    registrations.splice(i, 1);
                    // Each node can only have one registered observer associated with
                    // this observer.
                    break;
                }
            }
        }, this);
    },

    handleEvent: function(e) {
        // Stop propagation since we are managing the propagation manually.
        // This means that other mutation events on the page will not work
        // correctly but that is by design.
        e.stopImmediatePropagation();

        switch (e.type) {
            case 'DOMAttrModified':
                // http://dom.spec.whatwg.org/#concept-mo-queue-attributes

                var name = e.attrName;
                var namespace = e.relatedNode.namespaceURI;
                var target = e.target;

                // 1.
                var record = new getRecord('attributes', target);
                record.attributeName = name;
                record.attributeNamespace = namespace;

                // 2.
                var oldValue = null;
                if (!(typeof MutationEvent !== 'undefined' && e.attrChange === MutationEvent.ADDITION))
                    oldValue = e.prevValue;

                forEachAncestorAndObserverEnqueueRecord(target, function(options) {
                    // 3.1, 4.2
                    if (!options.attributes)
                        return;

                    // 3.2, 4.3
                    if (options.attributeFilter && options.attributeFilter.length &&
                        options.attributeFilter.indexOf(name) === -1 &&
                        options.attributeFilter.indexOf(namespace) === -1) {
                        return;
                    }
                    // 3.3, 4.4
                    if (options.attributeOldValue)
                        return getRecordWithOldValue(oldValue);

                    // 3.4, 4.5
                    return record;
                });

                break;

            case 'DOMCharacterDataModified':
                // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
                var target = e.target;

                // 1.
                var record = getRecord('characterData', target);

                // 2.
                var oldValue = e.prevValue;


                forEachAncestorAndObserverEnqueueRecord(target, function(options) {
                    // 3.1, 4.2
                    if (!options.characterData)
                        return;

                    // 3.2, 4.3
                    if (options.characterDataOldValue)
                        return getRecordWithOldValue(oldValue);

                    // 3.3, 4.4
                    return record;
                });

                break;

            case 'DOMNodeRemoved':
                this.addTransientObserver(e.target);
            // Fall through.
            case 'DOMNodeInserted':
                // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
                var target = e.relatedNode;
                var changedNode = e.target;
                var addedNodes, removedNodes;
                if (e.type === 'DOMNodeInserted') {
                    addedNodes = [changedNode];
                    removedNodes = [];
                } else {

                    addedNodes = [];
                    removedNodes = [changedNode];
                }
                var previousSibling = changedNode.previousSibling;
                var nextSibling = changedNode.nextSibling;

                // 1.
                var record = getRecord('childList', target);
                record.addedNodes = addedNodes;
                record.removedNodes = removedNodes;
                record.previousSibling = previousSibling;
                record.nextSibling = nextSibling;

                forEachAncestorAndObserverEnqueueRecord(target, function(options) {
                    // 2.1, 3.2
                    if (!options.childList)
                        return;

                    // 2.2, 3.3
                    return record;
                });

        }

        clearRecords();
    }
};

if (!MutationObserver) {
    MutationObserver = JsMutationObserver;
}

// from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md
(function (arr) {
    arr.forEach(function (item) {
        if (item.hasOwnProperty('remove')) {
            return;
        }
        Object.defineProperty(item, 'remove', {
            configurable: true,
            enumerable: true,
            writable: true,
            value: function remove() {
                if (this.parentNode !== null)
                    this.parentNode.removeChild(this);
            }
        });
    });
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);

if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = function (callback, thisArg) {
        thisArg = thisArg || window;
        for (var i = 0; i < this.length; i++) {
            callback.call(thisArg, this[i], i, this);
        }
    };
}

/*
 * @preserve dataset polyfill for IE < 11. See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset and http://caniuse.com/#search=dataset
 *
 * @author ShirtlessKirk copyright 2015
 * @license WTFPL (http://www.wtfpl.net/txt/copying)
 */
/*global define: false, module: false */
/*jslint nomen: true, regexp: true, unparam: true */
(function datasetModule(global, definition) { // non-exporting module magic dance
    'use strict';

    var
        amd = 'amd',
        exports = 'exports'; // keeps the method names for CommonJS / AMD from being compiled to single character variable

    if (typeof define === 'function' && define[amd]) {
        define(function definer() {
            return definition(global);
        });
    } else if (typeof module === 'function' && module[exports]) {
        module[exports] = definition(global);
    } else {
        definition(global);
    }
}(this, function datasetPolyfill(global) {
    'use strict';

    var
        attribute,
        attributes,
        counter,
        dash,
        dataRegEx,
        document = global.document,
        hasEventListener,
        length,
        match,
        mutationSupport,
        test = document.createElement('_'),
        DOMAttrModified = 'DOMAttrModified';

    function clearDataset(event) {
        delete event.target._datasetCache;
    }

    function toCamelCase(string) {
        return string.replace(dash, function (m, letter) {
            return letter.toUpperCase();
        });
    }

    function getDataset() {
        var
            dataset = {};

        attributes = this.attributes;
        for (counter = 0, length = attributes.length; counter < length; counter += 1) {
            attribute = attributes[counter];
            match = attribute.name.match(dataRegEx);
            if (match) {
                dataset[toCamelCase(match[1])] = attribute.value;
            }
        }

        return dataset;
    }

    function mutation() {
        if (hasEventListener) {
            test.removeEventListener(DOMAttrModified, mutation, false);
        } else {
            test.detachEvent('on' + DOMAttrModified, mutation);
        }

        mutationSupport = true;
    }

    if (test.dataset !== undefined) {
        return;
    }

    dash = /\-([a-z])/ig;
    dataRegEx = /^data\-(.+)/;
    hasEventListener = !!document.addEventListener;
    mutationSupport = false;

    if (hasEventListener) {
        test.addEventListener(DOMAttrModified, mutation, false);
    } else {
        test.attachEvent('on' + DOMAttrModified, mutation);
    }

    // trigger event (if supported)
    test.setAttribute('foo', 'bar');

    Object.defineProperty(global.Element.prototype, 'dataset', {
        get: mutationSupport
            ? function get() {
                if (!this._datasetCache) {
                    this._datasetCache = getDataset.call(this);
                }

                return this._datasetCache;
            } : getDataset
    });

    if (mutationSupport && hasEventListener) { // < IE9 supports neither
        document.addEventListener(DOMAttrModified, clearDataset, false);
    }
}));

/*! (C) Andrea Giammarchi - Mit Style License */
var URLSearchParams=URLSearchParams||function(){"use strict";function URLSearchParams(query){var index,key,value,pairs,i,length,dict=Object.create(null);this[secret]=dict;if(!query)return;if(typeof query==="string"){if(query.charAt(0)==="?"){query=query.slice(1)}for(pairs=query.split("&"),i=0,length=pairs.length;i<length;i++){value=pairs[i];index=value.indexOf("=");if(-1<index){appendTo(dict,decode(value.slice(0,index)),decode(value.slice(index+1)))}else if(value.length){appendTo(dict,decode(value),"")}}}else{if(isArray(query)){for(i=0,length=query.length;i<length;i++){value=query[i];appendTo(dict,value[0],value[1])}}else{for(key in query){appendTo(dict,key,query[key])}}}}var isArray=Array.isArray,URLSearchParamsProto=URLSearchParams.prototype,find=/[!'\(\)~]|%20|%00/g,plus=/\+/g,replace={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"},replacer=function(match){return replace[match]},secret="__URLSearchParams__:"+Math.random();function appendTo(dict,name,value){if(name in dict){dict[name].push(""+value)}else{dict[name]=isArray(value)?value:[""+value]}}function decode(str){return decodeURIComponent(str.replace(plus," "))}function encode(str){return encodeURIComponent(str).replace(find,replacer)}URLSearchParamsProto.append=function append(name,value){appendTo(this[secret],name,value)};URLSearchParamsProto["delete"]=function del(name){delete this[secret][name]};URLSearchParamsProto.get=function get(name){var dict=this[secret];return name in dict?dict[name][0]:null};URLSearchParamsProto.getAll=function getAll(name){var dict=this[secret];return name in dict?dict[name].slice(0):[]};URLSearchParamsProto.has=function has(name){return name in this[secret]};URLSearchParamsProto.set=function set(name,value){this[secret][name]=[""+value]};URLSearchParamsProto.forEach=function forEach(callback,thisArg){var dict=this[secret];Object.getOwnPropertyNames(dict).forEach(function(name){dict[name].forEach(function(value){callback.call(thisArg,value,name,this)},this)},this)};URLSearchParamsProto.toJSON=function toJSON(){return{}};URLSearchParamsProto.toString=function toString(){var dict=this[secret],query=[],i,key,name,value;for(key in dict){name=encode(key);for(i=0,value=dict[key];i<value.length;i++){query.push(name+"="+encode(value[i]))}}return query.join("&")};var dP=Object.defineProperty,gOPD=Object.getOwnPropertyDescriptor,createSearchParamsPollute=function(search){function append(name,value){URLSearchParamsProto.append.call(this,name,value);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}function del(name){URLSearchParamsProto["delete"].call(this,name);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}function set(name,value){URLSearchParamsProto.set.call(this,name,value);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}return function(sp,value){sp.append=append;sp["delete"]=del;sp.set=set;return dP(sp,"_usp",{configurable:true,writable:true,value:value})}},createSearchParamsCreate=function(polluteSearchParams){return function(obj,sp){dP(obj,"_searchParams",{configurable:true,writable:true,value:polluteSearchParams(sp,obj)});return sp}},updateSearchParams=function(sp){var append=sp.append;sp.append=URLSearchParamsProto.append;URLSearchParams.call(sp,sp._usp.search.slice(1));sp.append=append},verifySearchParams=function(obj,Class){if(!(obj instanceof Class))throw new TypeError("'searchParams' accessed on an object that "+"does not implement interface "+Class.name)},upgradeClass=function(Class){var ClassProto=Class.prototype,searchParams=gOPD(ClassProto,"searchParams"),href=gOPD(ClassProto,"href"),search=gOPD(ClassProto,"search"),createSearchParams;if(!searchParams&&search&&search.set){createSearchParams=createSearchParamsCreate(createSearchParamsPollute(search));Object.defineProperties(ClassProto,{href:{get:function(){return href.get.call(this)},set:function(value){var sp=this._searchParams;href.set.call(this,value);if(sp)updateSearchParams(sp)}},search:{get:function(){return search.get.call(this)},set:function(value){var sp=this._searchParams;search.set.call(this,value);if(sp)updateSearchParams(sp)}},searchParams:{get:function(){verifySearchParams(this,Class);return this._searchParams||createSearchParams(this,new URLSearchParams(this.search.slice(1)))},set:function(sp){verifySearchParams(this,Class);createSearchParams(this,sp)}}})}};upgradeClass(HTMLAnchorElement);if(/^function|object$/.test(typeof URL)&&URL.prototype)upgradeClass(URL);return URLSearchParams}();(function(URLSearchParamsProto){var iterable=function(){try{return!!Symbol.iterator}catch(error){return false}}();if(!("forEach"in URLSearchParamsProto)){URLSearchParamsProto.forEach=function forEach(callback,thisArg){var names=Object.create(null);this.toString().replace(/=[\s\S]*?(?:&|$)/g,"=").split("=").forEach(function(name){if(!name.length||name in names)return;(names[name]=this.getAll(name)).forEach(function(value){callback.call(thisArg,value,name,this)},this)},this)}}if(!("keys"in URLSearchParamsProto)){URLSearchParamsProto.keys=function keys(){var items=[];this.forEach(function(value,name){items.push(name)});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(!("values"in URLSearchParamsProto)){URLSearchParamsProto.values=function values(){var items=[];this.forEach(function(value){items.push(value)});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(!("entries"in URLSearchParamsProto)){URLSearchParamsProto.entries=function entries(){var items=[];this.forEach(function(value,name){items.push([name,value])});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(iterable&&!(Symbol.iterator in URLSearchParamsProto)){URLSearchParamsProto[Symbol.iterator]=URLSearchParamsProto.entries}if(!("sort"in URLSearchParamsProto)){URLSearchParamsProto.sort=function sort(){var entries=this.entries(),entry=entries.next(),done=entry.done,keys=[],values=Object.create(null),i,key,value;while(!done){value=entry.value;key=value[0];keys.push(key);if(!(key in values)){values[key]=[]}values[key].push(value[1]);entry=entries.next();done=entry.done}keys.sort();for(i=0;i<keys.length;i++){this["delete"](keys[i])}for(i=0;i<keys.length;i++){key=keys[i];this.append(key,values[key].shift())}}}})(URLSearchParams.prototype);

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik M�ller. fixes from Paul Irish and Tino Zijdel

// MIT license

(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
            || window[vendors[x]+'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
                timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());

// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md
(function (arr) {
    arr.forEach(function (item) {
        if (item.hasOwnProperty('append')) {
            return;
        }
        Object.defineProperty(item, 'append', {
            configurable: true,
            enumerable: true,
            writable: true,
            value: function append() {
                var argArr = Array.prototype.slice.call(arguments),
                    docFrag = document.createDocumentFragment();

                argArr.forEach(function (argItem) {
                    var isNode = argItem instanceof Node;
                    docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
                });

                this.appendChild(docFrag);
            }
        });
    });
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
if (!String.prototype.endsWith) {
    String.prototype.endsWith = function(search, this_len) {
        if (this_len === undefined || this_len > this.length) {
            this_len = this.length;
        }
        return this.substring(this_len - search.length, this_len) === search;
    };
}