/*!

   Flowplayer v6.0.5 (Wednesday, 13. January 2016 09:17AM) | flowplayer.org/license

*/
/*! (C) WebReflection Mit Style License */
(function (e) {
    function g(e, t, n, r) {
        for (var i, s = n.slice(), o = w(t, e), u = 0, a = s.length; u < a; u++) {
            handler = s[u], typeof handler == "object" && typeof handler.handleEvent == "function" ? handler.handleEvent(o) : handler.call(e, o);
            if (o.stoppedImmediatePropagation) break
        }
        return i = !o.stoppedPropagation, r && i && e.parentNode ? e.parentNode.dispatchEvent(o) : !o.defaultPrevented
    }

    function y(e, t) {
        return {configurable: !0, get: e, set: t}
    }

    function b(e, t, n) {
        var r = f(t || e, n);
        u(e, "textContent", y(function () {
            return r.get.call(this)
        }, function (e) {
            r.set.call(this, e)
        }))
    }

    function w(e, t) {
        return e.currentTarget = t, e.eventPhase = e.target === e.currentTarget ? 2 : 3, e
    }

    function E(e, t) {
        var n = e.length;
        while (n-- && e[n] !== t) ;
        return n
    }

    function S() {
        if (this.tagName === "BR") return "\n";
        var e = this.firstChild, t = [];
        while (e) e.nodeType !== 8 && e.nodeType !== 7 && t.push(e.textContent), e = e.nextSibling;
        return t.join("")
    }

    function x(e) {
        return e.nodeType !== 9 && document.documentElement.contains(e)
    }

    function T(e) {
        !n && d.test(document.readyState) && (n = !n, document.detachEvent(r, T), e = document.createEvent("Event"), e.initEvent(i, !0, !0), document.dispatchEvent(e))
    }

    function N(e) {
        var t;
        while (t = this.lastChild) this.removeChild(t);
        e != null && this.appendChild(document.createTextNode(e))
    }

    function C(t, n) {
        return n || (n = e.event), n.target || (n.target = n.srcElement || n.fromElement || document), n.timeStamp || (n.timeStamp = (new Date).getTime()), n
    }

    if (document.createEvent) return;
    var t = !0, n = !1, r = "onreadystatechange", i = "DOMContentLoaded", s = "__IE8__" + Math.random(), o = e.Object, u = o.defineProperty || function (e, t, n) {
            e[t] = n.value
        }, a = o.defineProperties || function (t, n) {
            for (var r in n) if (l.call(n, r)) try {
                u(t, r, n[r])
            } catch (i) {
                e.console && console.log(r + " failed on object:", t, i.message)
            }
        }, f = o.getOwnPropertyDescriptor, l = o.prototype.hasOwnProperty, c = e.Element.prototype, h = e.Text.prototype, p = /^[a-z]+$/, d = /loaded|complete/, v = {},
        m = document.createElement("div");
    b(e.HTMLCommentElement.prototype, c, "nodeValue"), b(e.HTMLScriptElement.prototype, null, "text"), b(h, null, "nodeValue"), b(e.HTMLTitleElement.prototype, null, "text"), u(e.HTMLStyleElement.prototype, "textContent", function (e) {
        return y(function () {
            return e.get.call(this.styleSheet)
        }, function (t) {
            e.set.call(this.styleSheet, t)
        })
    }(f(e.CSSStyleSheet.prototype, "cssText"))), a(c, {
        textContent: {get: S, set: N}, firstElementChild: {
            get: function () {
                for (var e = this.childNodes || [], t = 0, n = e.length; t < n; t++) if (e[t].nodeType == 1) return e[t]
            }
        }, lastElementChild: {
            get: function () {
                for (var e = this.childNodes || [], t = e.length; t--;) if (e[t].nodeType == 1) return e[t]
            }
        }, previousElementSibling: {
            get: function () {
                var e = this.previousSibling;
                while (e && e.nodeType != 1) e = e.previousSibling;
                return e
            }
        }, nextElementSibling: {
            get: function () {
                var e = this.nextSibling;
                while (e && e.nodeType != 1) e = e.nextSibling;
                return e
            }
        }, childElementCount: {
            get: function () {
                for (var e = 0, t = this.childNodes || [], n = t.length; n--; e += t[n].nodeType == 1) ;
                return e
            }
        }, addEventListener: {
            value: function (e, t, n) {
                var r = this, i = "on" + e, o = r[s] || u(r, s, {value: {}})[s], a = o[i] || (o[i] = {}), f = a.h || (a.h = []), c;
                if (!l.call(a, "w")) {
                    a.w = function (e) {
                        return e[s] || g(r, C(r, e), f, !1)
                    };
                    if (!l.call(v, i)) if (p.test(e)) try {
                        c = document.createEventObject(), c[s] = !0, r.nodeType != 9 && r.parentNode == null && m.appendChild(r), r.fireEvent(i, c), v[i] = !0
                    } catch (c) {
                        v[i] = !1;
                        while (m.hasChildNodes()) m.removeChild(m.firstChild)
                    } else v[i] = !1;
                    (a.n = v[i]) && r.attachEvent(i, a.w)
                }
                E(f, t) < 0 && f[n ? "unshift" : "push"](t)
            }
        }, dispatchEvent: {
            value: function (e) {
                var t = this, n = "on" + e.type, r = t[s], i = r && r[n], o = !!i, u;
                return e.target || (e.target = t), o ? i.n ? t.fireEvent(n, e) : g(t, e, i.h, !0) : (u = t.parentNode) ? u.dispatchEvent(e) : !0, !e.defaultPrevented
            }
        }, removeEventListener: {
            value: function (e, t, n) {
                var r = this, i = "on" + e, o = r[s], u = o && o[i], a = u && u.h, f = a ? E(a, t) : -1;
                -1 < f && a.splice(f, 1)
            }
        }
    }), a(h, {
        addEventListener: {value: c.addEventListener},
        dispatchEvent: {value: c.dispatchEvent},
        removeEventListener: {value: c.removeEventListener}
    }), a(e.XMLHttpRequest.prototype, {
        addEventListener: {
            value: function (e, t, n) {
                var r = this, i = "on" + e, o = r[s] || u(r, s, {value: {}})[s], a = o[i] || (o[i] = {}), f = a.h || (a.h = []);
                E(f, t) < 0 && (r[i] || (r[i] = function () {
                    var t = document.createEvent("Event");
                    t.initEvent(e, !0, !0), r.dispatchEvent(t)
                }), f[n ? "unshift" : "push"](t))
            }
        }, dispatchEvent: {
            value: function (e) {
                var t = this, n = "on" + e.type, r = t[s], i = r && r[n], o = !!i;
                return o && (i.n ? t.fireEvent(n, e) : g(t, e, i.h, !0))
            }
        }, removeEventListener: {value: c.removeEventListener}
    }), a(e.Event.prototype, {
        bubbles: {value: !0, writable: !0}, cancelable: {value: !0, writable: !0}, preventDefault: {
            value: function () {
                this.cancelable && (this.defaultPrevented = !0, this.returnValue = !1)
            }
        }, stopPropagation: {
            value: function () {
                this.stoppedPropagation = !0, this.cancelBubble = !0
            }
        }, stopImmediatePropagation: {
            value: function () {
                this.stoppedImmediatePropagation = !0, this.stopPropagation()
            }
        }, initEvent: {
            value: function (e, t, n) {
                this.type = e, this.bubbles = !!t, this.cancelable = !!n, this.bubbles || this.stopPropagation()
            }
        }
    }), a(e.HTMLDocument.prototype, {
        textContent: {
            get: function () {
                return this.nodeType === 11 ? S.call(this) : null
            }, set: function (e) {
                this.nodeType === 11 && N.call(this, e)
            }
        }, addEventListener: {
            value: function (n, s, o) {
                var u = this;
                c.addEventListener.call(u, n, s, o), t && n === i && !d.test(u.readyState) && (t = !1, u.attachEvent(r, T), e == top && function a(e) {
                    try {
                        u.documentElement.doScroll("left"), T()
                    } catch (t) {
                        setTimeout(a, 50)
                    }
                }())
            }
        }, dispatchEvent: {value: c.dispatchEvent}, removeEventListener: {value: c.removeEventListener}, createEvent: {
            value: function (e) {
                var t;
                if (e !== "Event") throw new Error("unsupported " + e);
                return t = document.createEventObject(), t.timeStamp = (new Date).getTime(), t
            }
        }
    }), a(e.Window.prototype, {
        getComputedStyle: {
            value: function () {
                function i(e) {
                    this._ = e
                }

                function s() {
                }

                var e = /^(?:[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/, t = /^(top|right|bottom|left)$/, n = /\-([a-z])/g, r = function (e, t) {
                    return t.toUpperCase()
                };
                return i.prototype.getPropertyValue = function (i) {
                    var s = this._, o = s.style, u = s.currentStyle, a = s.runtimeStyle, f, l, c;
                    return i = (i === "float" ? "style-float" : i).replace(n, r), f = u ? u[i] : o[i], e.test(f) && !t.test(i) && (l = o.left, c = a && a.left, c && (a.left = u.left), o.left = i === "fontSize" ? "1em" : f, f = o.pixelLeft + "px", o.left = l, c && (a.left = c)), f == null ? f : f + "" || "auto"
                }, s.prototype.getPropertyValue = function () {
                    return null
                }, function (e, t) {
                    return t ? new s(e) : new i(e)
                }
            }()
        }, addEventListener: {
            value: function (t, n, r) {
                var i = e, o = "on" + t, u;
                i[o] || (i[o] = function (e) {
                    return g(i, C(i, e), u, !1)
                }), u = i[o][s] || (i[o][s] = []), E(u, n) < 0 && u[r ? "unshift" : "push"](n)
            }
        }, dispatchEvent: {
            value: function (t) {
                var n = e["on" + t.type];
                return n ? n.call(e, t) !== !1 && !t.defaultPrevented : !0
            }
        }, removeEventListener: {
            value: function (t, n, r) {
                var i = "on" + t, u = (e[i] || o)[s], a = u ? E(u, n) : -1;
                -1 < a && u.splice(a, 1)
            }
        }
    })
})(this);
!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.flowplayer = 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 (_dereq_, module, exports) {
            'use strict';
            var common = module.exports = {},
                ClassList = _dereq_('class-list'),
                $ = window.jQuery,
                punycode = _dereq_('punycode'),
                computedStyle = _dereq_('computed-style');

            common.noop = function () {
            };
            common.identity = function (i) {
                return i;
            };

            common.removeNode = function (el) {
                if (!el || !el.parentNode) return;
                el.parentNode.removeChild(el);
            };

            common.find = function (query, ctx) {
                if ($) return $(query, ctx).toArray();
                ctx = ctx || document;
                return Array.prototype.map.call(ctx.querySelectorAll(query), function (el) {
                    return el;
                });
            };

            common.text = function (el, txt) {
                el[('innerText' in el) ? 'innerText' : 'textContent'] = txt;
            };

            common.findDirect = function (query, ctx) {
                return common.find(query, ctx).filter(function (node) {
                    return node.parentNode === ctx;
                });
            };

            common.hasClass = function (el, kls) {
                return ClassList(el).contains(kls);
            };

            common.isSameDomain = function (url) {
                var w = window.location,
                    a = common.createElement('a', {href: url});
                return w.hostname === a.hostname &&
                    w.protocol === a.protocol &&
                    w.port === a.port;
            };

            common.css = function (el, property, value) {
                if (typeof property === 'object') {
                    return Object.keys(property).forEach(function (key) {
                        common.css(el, key, property[key]);
                    });
                }
                if (typeof value !== 'undefined') {
                    if (value === '') return el ? el.style.removeProperty(property) : undefined;
                    return el ? el.style.setProperty(property, value) : undefined;
                }
                return el ? computedStyle(el, property) : undefined;
            };

            common.createElement = function (tag, attributes, innerHTML) {
                try {
                    var el = document.createElement(tag);
                    for (var key in attributes) {
                        if (!attributes.hasOwnProperty(key)) continue;
                        if (key === 'css') {
                            common.css(el, attributes[key]);
                        } else {
                            common.attr(el, key, attributes[key]);
                        }
                    }
                    el.innerHTML = innerHTML || '';
                    return el;
                } catch (e) {
                    if (!$) throw e;
                    return $('<' + tag + '>' + innerHTML + '</' + tag + '>').attr(attributes)[0];
                }
            };

            common.toggleClass = function (el, cls, flag) {
                if (!el) return;
                var classes = ClassList(el);
                if (typeof flag === 'undefined') classes.toggle(cls);
                else if (flag) classes.add(cls);
                else if (!flag) classes.remove(cls);
            };

            common.addClass = function (el, cls) {
                return common.toggleClass(el, cls, true);
            };

            common.removeClass = function (el, cls) {
                return common.toggleClass(el, cls, false);
            };

            common.append = function (par, child) {
                par.appendChild(child);
                return par;
            };

            common.appendTo = function (child, par) {
                common.append(par, child);
                return child;
            };

            common.prepend = function (par, child) {
                par.insertBefore(child, par.firstChild);
            };


// Inserts `el` after `child` that is child of `par`
            common.insertAfter = function (par, child, el) {
                if (child == common.lastChild(par)) par.appendChild(el);
                var childIndex = Array.prototype.indexOf.call(par.children, child);
                par.insertBefore(el, par.children[childIndex + 1]);
            };

            common.html = function (elms, val) {
                elms = elms.length ? elms : [elms];
                elms.forEach(function (elm) {
                    elm.innerHTML = val;
                });
            };


            common.attr = function (el, key, val) {
                if (key === 'class') key = 'className';
                if (common.hasOwnOrPrototypeProperty(el, key)) {
                    try {
                        el[key] = val;
                    } catch (e) { // Most likely IE not letting set property
                        if ($) {
                            $(el).attr(key, val);
                        } else {
                            throw e;
                        }
                    }
                } else {
                    if (val === false) {
                        el.removeAttribute(key);
                    } else {
                        el.setAttribute(key, val);
                    }
                }
                return el;
            };

            common.prop = function (el, key, val) {
                if (typeof val === 'undefined') {
                    return el && el[key];
                }
                el[key] = val;
            };

            common.offset = function (el) {
                var ret = el.getBoundingClientRect();
                if (el.offsetWidth / el.offsetHeight > el.clientWidth / el.clientHeight) { // https://github.com/flowplayer/flowplayer/issues/757
                    ret = {
                        left: ret.left * 100,
                        right: ret.right * 100,
                        top: ret.top * 100,
                        bottom: ret.bottom * 100,
                        width: ret.width * 100,
                        height: ret.height * 100
                    };
                }
                return ret;
            };

            common.width = function (el, val) {
                /*jshint -W093 */
                if (val) return el.style.width = ('' + val).replace(/px$/, '') + 'px';
                var ret = common.offset(el).width;
                return typeof ret === 'undefined' ? el.offsetWidth : ret;
            };

            common.height = function (el, val) {
                /*jshint -W093 */
                if (val) return el.style.height = ('' + val).replace(/px$/, '') + 'px';
                var ret = common.offset(el).height;
                return typeof ret === 'undefined' ? el.offsetHeight : ret;
            };

            common.lastChild = function (el) {
                return el.children[el.children.length - 1];
            };

            common.hasParent = function (el, parentSelector) {
                var parent = el.parentElement;
                while (parent) {
                    if (common.matches(parent, parentSelector)) return true;
                    parent = parent.parentElement;
                }
                return false;
            };

            common.createAbsoluteUrl = function (url) {
                return common.createElement('a', {href: url}).href; // This won't work on IE7
            };

            common.xhrGet = function (url, successCb, errorCb) {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function () {
                    if (this.readyState !== 4) return;
                    if (this.status >= 400) return errorCb();
                    successCb(this.responseText);
                };
                xhr.open('get', url, true);
                xhr.send();
            };

            common.pick = function (obj, props) {
                var ret = {};
                props.forEach(function (prop) {
                    if (obj.hasOwnProperty(prop)) ret[prop] = obj[prop];
                });
                return ret;
            };

            common.hostname = function (host) {
                return punycode.toUnicode(host || window.location.hostname);
            };

//Hacks
            common.browser = {
                webkit: 'WebkitAppearance' in document.documentElement.style
            };

            common.getPrototype = function (el) {
                /* jshint proto:true */
                if (!Object.getPrototypeOf) return el.__proto__;
                return Object.getPrototypeOf(el);
            };

            common.hasOwnOrPrototypeProperty = function (obj, prop) {
                var o = obj;
                while (o) {
                    if (Object.prototype.hasOwnProperty.call(o, prop)) return true;
                    o = common.getPrototype(o);
                }
                return false;
            };


// Polyfill for Element.matches
// adapted from https://developer.mozilla.org/en/docs/Web/API/Element/matches
            common.matches = function (elem, selector) {
                var proto = Element.prototype,
                    fn = proto.matches ||
                        proto.matchesSelector ||
                        proto.mozMatchesSelector ||
                        proto.msMatchesSelector ||
                        proto.oMatchesSelector ||
                        proto.webkitMatchesSelector ||
                        function (selector) {
                            var element = this,
                                matches = (element.document || element.ownerDocument).querySelectorAll(selector),
                                i = 0;
                            while (matches[i] && matches[i] !== element) {
                                i++;
                            }

                            return matches[i] ? true : false;
                        };
                return fn.call(elem, selector);
            };


// Polyfill for CSSStyleDeclaration
// from https://github.com/shawnbot/aight
            (function (CSSSDProto) {

                function getAttribute(property) {
                    return property.replace(/-[a-z]/g, function (bit) {
                        return bit[1].toUpperCase();
                    });
                }

                // patch CSSStyleDeclaration.prototype using IE8's methods
                if (typeof CSSSDProto.setAttribute !== "undefined") {
                    CSSSDProto.setProperty = function (property, value) {
                        return this.setAttribute(getAttribute(property), String(value) /*, important */);
                    };
                    CSSSDProto.getPropertyValue = function (property) {
                        return this.getAttribute(getAttribute(property)) || null;
                    };
                    CSSSDProto.removeProperty = function (property) {
                        var value = this.getPropertyValue(property);
                        this.removeAttribute(getAttribute(property));
                        return value;
                    };
                }

            })(window.CSSStyleDeclaration.prototype);

        }, {"class-list": 22, "computed-style": 24, "punycode": 21}],
        2: [function (_dereq_, module, exports) {
            'use strict';
            var common = _dereq_('../common');

// movie required in opts
            module.exports = function embed(swf, flashvars, wmode, bgColor) {
                wmode = wmode || "opaque";

                var id = "obj" + ("" + Math.random()).slice(2, 15),
                    tag = '<object class="fp-engine" id="' + id + '" name="' + id + '" ',
                    msie = navigator.userAgent.indexOf('MSIE') > -1;

                tag += msie ? 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">' :
                    ' data="' + swf + '" type="application/x-shockwave-flash">';

                var opts = {
                    width: "100%",
                    height: "100%",
                    allowscriptaccess: "always",
                    wmode: wmode,
                    quality: "high",
                    flashvars: "",

                    // https://github.com/flowplayer/flowplayer/issues/13#issuecomment-9369919
                    movie: swf + (msie ? "?" + id : ""),
                    name: id
                };

                if (wmode !== 'transparent') opts.bgcolor = bgColor || '#333333';

                // flashvars
                Object.keys(flashvars).forEach(function (key) {
                    opts.flashvars += key + "=" + flashvars[key] + "&";
                });

                // parameters
                Object.keys(opts).forEach(function (key) {
                    tag += '<param name="' + key + '" value="' + opts[key] + '"/>';
                });

                tag += "</object>";
                var el = common.createElement('div', {}, tag);
                return common.find('object', el);

            };


// Flash is buggy allover
            if (window.attachEvent) {
                window.attachEvent("onbeforeunload", function () {
                    window.__flash_savedUnloadHandler = window.__flash_unloadHandler = function () {
                    };
                });
            }


        }, {"../common": 1}],
        3: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                common = _dereq_('../common'),
                embed = _dereq_('./embed'),
                extend = _dereq_('extend-object'),
                bean = _dereq_('bean'),
                engineImpl;

            engineImpl = function flashEngine(player, root) {

                var conf = player.conf,
                    video = player.video,
                    loadVideo,
                    callbackId,
                    objectTag,
                    api;

                var win = window;

                var engine = {
                    engineName: engineImpl.engineName,

                    pick: function (sources) {

                        var source = extend({}, (function () {
                            if (flowplayer.support.flashVideo) {
                                var selectedSource;
                                for (var i = 0, source; i < sources.length; i++) {
                                    source = sources[i];
                                    if (/mp4|flv|flash/i.test(source.type)) selectedSource = source;
                                    if (player.conf.swfHls && /mpegurl/i.test(source.type)) selectedSource = source;
                                    if (selectedSource && !/mp4/i.test(selectedSource.type)) return selectedSource;
                                    // Did not find any source or source was video/mp4, let's try find more
                                }
                                return selectedSource; // Accept the fact we don't have anything or just an MP4
                            }
                        })());
                        if (!source) return;
                        if (source.src && !isAbsolute(source.src) && !player.conf.rtmp && !source.rtmp) source.src = common.createAbsoluteUrl(source.src);
                        return source;
                    },

                    load: function (video) {
                        loadVideo = video;

                        function escapeURL(url) {
                            return url.replace(/&amp;/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D');
                        }

                        var html5Tag = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0],
                            url = video.src,
                            is_absolute = isAbsolute(url);

                        var removeTag = function () {
                            common.removeNode(html5Tag);
                        };
                        var hasSupportedSource = function (sources) {
                            return sources.some(function (src) {
                                return !!html5Tag.canPlayType(src.type);
                            });
                        };
                        if (flowplayer.support.video &&
                            common.prop(html5Tag, 'autoplay') &&
                            hasSupportedSource(video.sources)) bean.one(html5Tag, 'timeupdate', removeTag);
                        else removeTag();

                        // convert to absolute
                        var rtmp = video.rtmp || conf.rtmp;
                        if (!is_absolute && !rtmp) url = common.createAbsoluteUrl(url);

                        if (api && isHLS(video) && api.data !== conf.swfHls) engine.unload();

                        if (api) {
                            ['live', 'preload', 'loop'].forEach(function (prop) {
                                if (!video.hasOwnProperty(prop)) return;
                                api.__set(prop, video[prop]);
                            });
                            Object.keys(video.flashls || {}).forEach(function (key) {
                                api.__set('hls_' + key, video.flashls[key]);
                            });
                            var providerChangeNeeded = false;
                            if (!is_absolute && rtmp) api.__set('rtmp', rtmp.url || rtmp);
                            else {
                                var oldRtmp = api.__get('rtmp');
                                providerChangeNeeded = !!oldRtmp;
                                api.__set('rtmp', null);
                            }
                            api.__play(url, providerChangeNeeded || video.rtmp && video.rtmp !== conf.rtmp);

                        } else {

                            callbackId = "fpCallback" + ("" + Math.random()).slice(3, 15);
                            url = escapeURL(url);

                            var opts = {
                                hostname: conf.embedded ? common.hostname(conf.hostname) : common.hostname(location.hostname),
                                url: url,
                                callback: callbackId
                            };
                            if (root.getAttribute('data-origin')) {
                                opts.origin = root.getAttribute('data-origin');
                            }

                            // optional conf
                            ['proxy', 'key', 'autoplay', 'preload', 'subscribe', 'live', 'loop', 'debug', 'splash', 'poster', 'rtmpt'].forEach(function (key) {
                                if (conf.hasOwnProperty(key)) opts[key] = conf[key];
                                if (video.hasOwnProperty(key)) opts[key] = video[key];
                                if ((conf.rtmp || {}).hasOwnProperty(key)) opts[key] = (conf.rtmp || {})[key];
                                if ((video.rtmp || {}).hasOwnProperty(key)) opts[key] = (video.rtmp || {})[key];
                            });
                            if (conf.rtmp) opts.rtmp = conf.rtmp.url || conf.rtmp;
                            if (video.rtmp) opts.rtmp = video.rtmp.url || video.rtmp;
                            Object.keys(video.flashls || {}).forEach(function (key) {
                                var val = video.flashls[key];
                                opts['hls_' + key] = val;
                            });
                            // bufferTime might be 0
                            if (conf.bufferTime !== undefined) opts.bufferTime = conf.bufferTime;

                            if (is_absolute) delete opts.rtmp;

                            // issues #376
                            if (opts.rtmp) {
                                opts.rtmp = escapeURL(opts.rtmp);
                            }

                            // issues #733, 906
                            var bgColor = conf.bgcolor || common.css(root, 'background-color') || '', bg;
                            if (bgColor.indexOf('rgb') === 0) {
                                bg = toHex(bgColor);
                            } else if (bgColor.indexOf('#') === 0) {
                                bg = toLongHex(bgColor);
                            }

                            // issues #387
                            opts.initialVolume = player.volumeLevel;

                            var swfUrl = isHLS(video) ? conf.swfHls : conf.swf;

                            api = embed(swfUrl, opts, conf.wmode, bg)[0];

                            var container = common.find('.fp-player', root)[0];

                            common.prepend(container, api);

                            // throw error if no loading occurs
                            setTimeout(function () {
                                try {
                                    if (!api.PercentLoaded()) {
                                        return player.trigger("error", [player, {code: 7, url: conf.swf}]);
                                    }
                                } catch (e) {
                                }
                            }, 5000);

                            // detect disabled flash
                            setTimeout(function () {
                                if (typeof api.PercentLoaded === 'undefined') {
                                    player.trigger('flashdisabled', [player]);
                                }
                            }, 1000);

                            player.off('resume.flashhack').on('resume.flashhack', function () {
                                var timer = setTimeout(function () {
                                    if (player.playing) {
                                        player.trigger('flashdisabled', [player]);
                                    }
                                }, 1000);
                                player.one('progress', function () {
                                    clearTimeout(timer);
                                });
                            });


                            api.pollInterval = setInterval(function () {
                                if (!api) return;
                                var status = api.__status ? api.__status() : null;

                                if (!status) return;

                                if (player.playing && status.time && status.time !== player.video.time) player.trigger("progress", [player, status.time]);

                                video.buffer = status.buffer / video.bytes * video.duration;
                                player.trigger("buffer", [player, video.buffer]);
                                if (!video.buffered && status.time > 0) {
                                    video.buffered = true;
                                    player.trigger("buffered", [player]);
                                }

                            }, 250);

                            // listen
                            window[callbackId] = function (type, arg) {
                                var video = loadVideo;

                                if (conf.debug) {
                                    if (type.indexOf('debug') === 0 && arg && arg.length) {
                                        console.log.apply(console, ['-- ' + type].concat(arg));
                                    }
                                    else console.log("--", type, arg);
                                }

                                var event = {
                                    type: type
                                };

                                switch (type) {

                                    // RTMP sends a lot of finish events in vain
                                    // case "finish": if (conf.rtmp) return;
                                    case "ready":
                                        arg = extend(video, arg);
                                        break;
                                    case "click":
                                        event.flash = true;
                                        break;
                                    case "keydown":
                                        event.which = arg;
                                        break;
                                    case "seek":
                                        video.time = arg;
                                        break;
                                    case "status":
                                        player.trigger("progress", [player, arg.time]);

                                        if (arg.buffer < video.bytes && !video.buffered) {
                                            video.buffer = arg.buffer / video.bytes * video.duration;
                                            player.trigger("buffer", video.buffer);
                                        } else if (!video.buffered) {
                                            video.buffered = true;
                                            player.trigger("buffered");
                                        }

                                        break;
                                }
                                if (type === 'click' || type === 'keydown') {
                                    event.target = root;
                                    bean.fire(root, type, [event]);
                                }
                                else if (type != 'buffered' && type !== 'unload') {
                                    // add some delay so that player is truly ready after an event
                                    setTimeout(function () {
                                        player.trigger(event, [player, arg]);
                                    }, 1);
                                } else if (type === 'unload') {
                                    player.trigger(event, [player, arg]);
                                }

                            };

                        }

                    },

                    // not supported yet
                    speed: common.noop,


                    unload: function () {
                        if (api && api.__unload) api.__unload();
                        try {
                            if (callbackId && window[callbackId]) delete window[callbackId];
                        } catch (e) {
                        }
                        common.find("object", root).forEach(common.removeNode);
                        api = 0;
                        player.off('.flashengine');
                        clearInterval(api.pollInterval);
                    }

                };

                ['pause', 'resume', 'seek', 'volume'].forEach(function (name) {

                    engine[name] = function (arg) {
                        try {
                            if (player.ready) {

                                if (arg === undefined) {
                                    api["__" + name]();

                                } else {
                                    api["__" + name](arg);
                                }

                            }
                        } catch (e) {
                            if (typeof api["__" + name] === 'undefined') { //flash lost it's methods
                                return player.trigger('flashdisabled', [player]);
                            }
                            throw e;
                        }
                    };

                });

                function toHex(bg) {
                    function hex(x) {
                        return ("0" + parseInt(x).toString(16)).slice(-2);
                    }

                    bg = bg.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
                    if (!bg) return;

                    return '#' + hex(bg[1]) + hex(bg[2]) + hex(bg[3]);
                }

                function toLongHex(bg) {
                    if (bg.length === 7) return bg;
                    var a = bg.split('').slice(1);
                    return '#' + a.map(function (i) {
                        return i + i;
                    }).join('');
                }

                function isHLS(video) {
                    return /application\/x-mpegurl/i.test(video.type);
                }

                return engine;

            };


            engineImpl.engineName = 'flash';
            engineImpl.canPlay = function (type, conf) {
                return flowplayer.support.flashVideo && /video\/(mp4|flash|flv)/i.test(type) || flowplayer.support.flashVideo && conf.swfHls && /mpegurl/i.test(type);
            };
            flowplayer.engines.push(engineImpl);


            function isAbsolute(url) {
                return /^https?:/.test(url);
            }

        }, {"../common": 1, "../flowplayer": 18, "./embed": 2, "bean": 20, "extend-object": 26}],
        4: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                bean = _dereq_('bean'),
                ClassList = _dereq_('class-list'),
                extend = _dereq_('extend-object'),
                common = _dereq_('../common');
            var VIDEO = document.createElement('video');

// HTML5 --> Flowplayer event
            var EVENTS = {

                // fired
                ended: 'finish',
                pause: 'pause',
                play: 'resume',
                progress: 'buffer',
                timeupdate: 'progress',
                volumechange: 'volume',
                ratechange: 'speed',
                //seeking: 'beforeseek',
                seeked: 'seek',
                // abort: 'resume',

                // not fired
                loadeddata: 'ready',
                // loadedmetadata: 0,
                // canplay: 0,

                // error events
                // load: 0,
                // emptied: 0,
                // empty: 0,
                error: 'error',
                dataunavailable: 'error',
                webkitendfullscreen: !flowplayer.support.inlineVideo && 'unload'

            };

            function round(val, per) {
                per = per || 100;
                return Math.round(val * per) / per;
            }

            function getType(type) {
                return /mpegurl/i.test(type) ? "application/x-mpegurl" : type;
            }

            function canPlay(type) {
                if (!/^(video|application)/i.test(type))
                    type = getType(type);
                return !!VIDEO.canPlayType(type).replace("no", '');
            }

            function findFromSourcesByType(sources, type) {
                var arr = sources.filter(function (s) {
                    return s.type === type;
                });
                return arr.length ? arr[0] : null;
            }

            var videoTagCache;
            var createVideoTag = function (video, autoplay, preload, useCache) {
                if (typeof autoplay === 'undefined') autoplay = true;
                if (typeof preload === 'undefined') preload = 'none';
                if (typeof useCache === 'undefined') useCache = true;
                if (useCache && videoTagCache) {
                    videoTagCache.type = getType(video.type);
                    videoTagCache.src = video.src;
                    common.find('track', videoTagCache).forEach(common.removeNode);
                    videoTagCache.removeAttribute('crossorigin');
                    return videoTagCache;
                }
                var el = document.createElement('video');
                el.src = video.src;
                el.type = getType(video.type);
                el.className = 'fp-engine';
                el.autoplay = autoplay ? 'autoplay' : false;
                el.preload = preload;
                el.setAttribute('x-webkit-airplay', 'allow');
                if (useCache) videoTagCache = el;
                return el;
            };

            var engine;

            engine = function (player, root) {

                var api = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0],
                    support = flowplayer.support,
                    track = common.find("track", api)[0],
                    conf = player.conf,
                    self,
                    timer,
                    volumeLevel;
                /*jshint -W093 */
                return self = {
                    engineName: engine.engineName,

                    pick: function (sources) {
                        var source = (function () {
                            if (support.video) {
                                if (conf.videoTypePreference) {
                                    var mp4source = findFromSourcesByType(sources, conf.videoTypePreference);
                                    if (mp4source) return mp4source;
                                }

                                for (var i = 0, source; i < sources.length; i++) {
                                    if (canPlay(sources[i].type)) return sources[i];
                                }
                            }
                        })();
                        if (!source) return;
                        if (typeof source.src === 'string') source.src = common.createAbsoluteUrl(source.src);
                        return source;
                    },

                    load: function (video) {
                        var created = false, container = common.find('.fp-player', root)[0], reload = false;
                        if (conf.splash && !api) {
                            api = createVideoTag(video);
                            common.prepend(container, api);
                            created = true;
                        } else if (!api) {
                            api = createVideoTag(video, !!video.autoplay || !!conf.autoplay, conf.clip.preload || 'metadata', false);
                            common.prepend(container, api);
                            created = true;
                        } else {
                            ClassList(api).add('fp-engine');
                            common.find('source,track', api).forEach(common.removeNode);
                            if (!player.conf.nativesubtitles) common.attr(api, 'crossorigin', false);
                            reload = api.src === video.src;
                        }
                        if (!support.inlineVideo) {
                            common.css(api, {
                                position: 'absolute',
                                top: '-9999em'
                            });
                        }
                        //TODO subtitles support

                        // IE does not fire delegated timeupdate events
                        bean.off(api, 'timeupdate', common.noop);
                        bean.on(api, 'timeupdate', common.noop);

                        common.prop(api, 'loop', !!(video.loop || conf.loop));

                        if (typeof volumeLevel !== 'undefined') {
                            api.volume = volumeLevel;
                        }

                        if (player.video.src && video.src != player.video.src || video.index) common.attr(api, 'autoplay', 'autoplay');
                        api.src = video.src;
                        api.type = video.type;

                        self._listeners = listen(api, common.find("source", api).concat(api), video);

                        // iPad (+others?) demands load()
                        if (conf.clip.preload != 'none' && video.type != "mpegurl" || !support.zeropreload || !support.dataload) api.load();
                        if (created || reload) api.load();
                        if (api.paused && (video.autoplay || conf.autoplay)) api.play();
                    },

                    pause: function () {
                        api.pause();
                    },

                    resume: function () {
                        api.play();
                    },

                    speed: function (val) {
                        api.playbackRate = val;
                    },

                    seek: function (time) {
                        try {
                            var pausedState = player.paused;
                            api.currentTime = time;
                            if (pausedState) api.pause();
                        } catch (ignored) {
                        }
                    },

                    volume: function (level) {
                        volumeLevel = level;
                        if (api) {
                            api.volume = level;
                        }
                    },

                    unload: function () {
                        common.find('video.fp-engine', root).forEach(common.removeNode);
                        if (!support.cachedVideoTag) videoTagCache = null;
                        timer = clearInterval(timer);
                        var instanceId = root.getAttribute('data-flowplayer-instance-id');
                        delete api.listeners[instanceId];
                        api = 0;
                        if (self._listeners) Object.keys(self._listeners).forEach(function (typ) {
                            self._listeners[typ].forEach(function (l) {
                                root.removeEventListener(typ, l, true);
                            });
                        });
                    }

                };

                function listen(api, sources, video) {
                    // listen only once
                    var instanceId = root.getAttribute('data-flowplayer-instance-id');

                    if (api.listeners && api.listeners.hasOwnProperty(instanceId)) {
                        api.listeners[instanceId] = video;
                        return;
                    }
                    (api.listeners || (api.listeners = {}))[instanceId] = video;

                    bean.on(sources, 'error', function (e) {
                        try {
                            if (canPlay(e.target.getAttribute('type'))) {
                                player.trigger("error", [player, {code: 4, video: extend(video, {src: api.src, url: api.src})}]);
                            }
                        } catch (er) {
                            // Most likely: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
                        }
                    });

                    player.on('shutdown', function () {
                        bean.off(sources);
                    });

                    var eventListeners = {};

                    Object.keys(EVENTS).forEach(function (type) {
                        var flow = EVENTS[type];
                        if (!flow) return;
                        var l = function (e) {
                            video = api.listeners[instanceId];
                            if (!e.target || !ClassList(e.target).contains('fp-engine')) return;

                            if (conf.debug && !/progress/.test(flow)) console.log(type, "->", flow, e);

                            // no events if player not ready
                            if (!player.ready && !/ready|error/.test(flow) || !flow || !common.find('video', root).length) {
                                return;
                            }

                            var arg, vtype;

                            if (flow === 'unload') { //Call player unload
                                player.unload();
                                return;
                            }

                            var triggerEvent = function () {
                                player.trigger(flow, [player, arg]);
                            };

                            switch (flow) {

                                case "ready":

                                    arg = extend(video, {
                                        duration: api.duration,
                                        width: api.videoWidth,
                                        height: api.videoHeight,
                                        url: api.currentSrc,
                                        src: api.currentSrc
                                    });

                                    try {
                                        arg.seekable = !player.live && /mpegurl/i.test(video ? (video.type || '') : '') && api.duration || api.seekable && api.seekable.end(null);

                                    } catch (ignored) {
                                    }

                                    // buffer
                                    timer = timer || setInterval(function () {

                                        try {
                                            arg.buffer = api.buffered.end(null);

                                        } catch (ignored) {
                                        }

                                        if (arg.buffer) {
                                            if (round(arg.buffer, 1000) < round(arg.duration, 1000) && !arg.buffered) {
                                                player.trigger("buffer", e);

                                            } else if (!arg.buffered) {
                                                arg.buffered = true;
                                                player.trigger("buffer", e).trigger("buffered", e);
                                                clearInterval(timer);
                                                timer = 0;
                                            }
                                        }

                                    }, 250);

                                    if (!player.live && !arg.duration && !support.hlsDuration && type === "loadeddata") {
                                        var durationChanged = function () {
                                            arg.duration = api.duration;
                                            try {
                                                arg.seekable = api.seekable && api.seekable.end(null);

                                            } catch (ignored) {
                                            }
                                            triggerEvent();
                                            api.removeEventListener('durationchange', durationChanged);
                                            ClassList(root).remove('is-live');
                                        };
                                        api.addEventListener('durationchange', durationChanged);

                                        // Ugly hack to handle broken Android devices
                                        var timeUpdated = function () {
                                            if (!player.ready && !api.duration) { // No duration even though the video already plays
                                                arg.duration = 0;
                                                ClassList(root).add('is-live'); // Make UI believe it's live
                                                triggerEvent();
                                            }
                                            api.removeEventListener('timeupdate', timeUpdated);
                                        };
                                        api.addEventListener('timeupdate', timeUpdated);
                                        return;
                                    }

                                    break;

                                case "progress":
                                case "seek":

                                    var dur = player.video.duration;

                                    if (api.currentTime > 0 || player.live) {
                                        arg = Math.max(api.currentTime, 0);

                                    } else if (flow == 'progress') {
                                        return;
                                    }
                                    break;


                                case "speed":
                                    arg = round(api.playbackRate);
                                    break;

                                case "volume":
                                    arg = round(api.volume);
                                    break;

                                case "error":
                                    try {
                                        arg = (e.srcElement || e.originalTarget).error;
                                        arg.video = extend(video, {src: api.src, url: api.src});
                                    } catch (er) {
                                        // Most likely https://bugzilla.mozilla.org/show_bug.cgi?id=208427
                                        return;
                                    }
                            }

                            triggerEvent();


                        };
                        root.addEventListener(type, l, true);
                        if (!eventListeners[type]) eventListeners[type] = [];
                        eventListeners[type].push(l);

                    });
                    return eventListeners;

                }

            };


            engine.canPlay = function (type) {
                return flowplayer.support.video && canPlay(type);
            };

            engine.engineName = 'html5';

            flowplayer.engines.push(engine);

        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22, "extend-object": 26}],
        5: [function (_dereq_, module, exports) {
            'use strict';
            /* global _gat */
            var flowplayer = _dereq_('../flowplayer'),
                TYPE_RE = _dereq_('./resolve').TYPE_RE,
                scriptjs = _dereq_('scriptjs'),
                bean = _dereq_('bean');
            flowplayer(function (player, root) {

                var id = player.conf.analytics, time = 0, last = 0, timer;

                if (id) {

                    // load Analytics script if needed
                    if (typeof _gat == 'undefined') scriptjs("//google-analytics.com/ga.js");

                    var getTracker = function () {
                        var tracker = _gat._getTracker(id);
                        tracker._setAllowLinker(true);
                        return tracker;
                    };

                    var track = function track(e, api, video) {

                        video = video || player.video;

                        if (time && typeof _gat != 'undefined') {
                            var tracker = getTracker();


                            // http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html
                            tracker._trackEvent(
                                "Video / Seconds played",
                                player.engine.engineName + "/" + video.type,
                                video.title || root.getAttribute("title") || video.src.split("/").slice(-1)[0].replace(TYPE_RE, ''),
                                Math.round(time / 1000)
                            );
                            time = 0;
                            if (timer) {
                                clearTimeout(timer);
                                timer = null;
                            }
                        }

                    };

                    player.bind("load unload", track).bind("progress", function () {

                        if (!player.seeking) {
                            time += last ? (+new Date() - last) : 0;
                            last = +new Date();
                        }

                        if (!timer) {
                            timer = setTimeout(function () {
                                timer = null;
                                var tracker = getTracker();
                                tracker._trackEvent('Flowplayer heartbeat', 'Heartbeat', '', 0, true);
                            }, 10 * 60 * 1000); // heartbeat every 10 minutes
                        }

                    }).bind("pause", function () {
                        last = 0;
                    });

                    player.bind('shutdown', function () {
                        bean.off(window, 'unload', track);
                    });

                    bean.on(window, 'unload', track);

                }

            });

        }, {"../flowplayer": 18, "./resolve": 13, "bean": 20, "scriptjs": 29}],
        6: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                ClassList = _dereq_('class-list'),
                common = _dereq_('../common'),
                bean = _dereq_('bean');

            flowplayer(function (player, root) {

                var CUE_RE = / ?cue\d+ ?/;

                var lastTime = 0, cuepointsDisabled = false;

                function setClass(index) {
                    root.className = root.className.replace(CUE_RE, " ");
                    if (index >= 0) ClassList(root).add('cue' + index);
                }

                var segments = {}, lastFiredSegment = -0.125;

                var fire = function (cue) {
                    var idx = player.cuepoints.indexOf(cue);
                    if (!isNaN(cue)) cue = {time: cue};
                    cue.index = idx;
                    setClass(idx);
                    player.trigger('cuepoint', [player, cue]);
                };

                player.on("progress", function (e, api, time) {
                    if (cuepointsDisabled) return;
                    var segment = segmentForCue(time);
                    while (lastFiredSegment < segment) {
                        lastFiredSegment += 0.125;
                        if (!segments[lastFiredSegment]) continue;
                        segments[lastFiredSegment].forEach(fire);
                    }

                }).on("unload", setClass)
                    .on('beforeseek', function (ev) {
                        setTimeout(function () {
                            if (!ev.defaultPrevented) cuepointsDisabled = true;
                        });
                    }).on("seek", function (ev, api, time) {
                    setClass();
                    lastFiredSegment = segmentForCue(time || 0) - 0.125;
                    cuepointsDisabled = false;
                    if (!time && segments[0]) segments[0].forEach(fire);
                }).on('ready', function (e, api, video) {
                    lastFiredSegment = -0.125;
                    var cues = video.cuepoints || player.conf.cuepoints || [];
                    player.setCuepoints(cues);
                }).on('finish', function () {
                    lastFiredSegment = -0.125;
                });
                if (player.conf.generate_cuepoints) {

                    player.bind("load", function () {

                        // clean up cuepoint elements of previous playlist items
                        common.find('.fp-cuepoint', root).forEach(common.removeNode);

                    });
                }

                /**
                 * API
                 */
                player.setCuepoints = function (cues) {
                    player.cuepoints = [];
                    segments = {};
                    cues.forEach(player.addCuepoint);
                    return player;
                };
                player.addCuepoint = function (cue) {
                    if (!player.cuepoints) player.cuepoints = [];
                    var segment = segmentForCue(cue);
                    if (!segments[segment]) segments[segment] = [];
                    segments[segment].push(cue);
                    player.cuepoints.push(cue);

                    if (player.conf.generate_cuepoints && cue.visible !== false) {
                        var duration = player.video.duration,
                            timeline = common.find('.fp-timeline', root)[0];
                        common.css(timeline, "overflow", "visible");

                        var time = cue.time || cue;
                        if (time < 0) time = duration + time;

                        var el = common.createElement('a', {className: 'fp-cuepoint fp-cuepoint' + (player.cuepoints.length - 1)});
                        common.css(el, "left", (time / duration * 100) + "%");

                        timeline.appendChild(el);
                        bean.on(el, 'mousedown', function (e) {
                            e.preventDefault();
                            e.stopPropagation();
                            player.seek(time);
                        });
                    }
                    return player;
                };

                player.removeCuepoint = function (cue) {
                    var idx = player.cuepoints.indexOf(cue),
                        segment = segmentForCue(cue);
                    if (idx === -1) return;
                    player.cuepoints = player.cuepoints.slice(0, idx).concat(player.cuepoints.slice(idx + 1));

                    var sIdx = segments[segment].indexOf(cue);
                    if (sIdx === -1) return;
                    segments[segment] = segments[segment].slice(0, sIdx).concat(segments[segment].slice(sIdx + 1));
                    return player;
                };

                function segmentForCue(cue) {
                    var time = cue && !isNaN(cue.time) ? cue.time : cue;
                    if (time < 0) time = player.video.duration + time;
                    return Math.round(time / 0.125) * 0.125;
                }

            });

        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22}],
        7: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                bean = _dereq_('bean'),
                common = _dereq_('../common'),
                isObject = _dereq_('is-object'),
                extend = _dereq_('extend-object'),
                ClassList = _dereq_('class-list');


            flowplayer(function (player, root) {

                // no embedding
                if (player.conf.embed === false) return;

                var conf = player.conf,
                    ui = common.find('.fp-ui', root)[0],
                    trigger = common.createElement('a', {"class": "fp-embed", title: 'Copy to your site'}),
                    target = common.createElement('div', {'class': 'fp-embed-code'}, '<label>Paste this HTML code on your site to embed.</label><textarea></textarea>'),
                    area = common.find("textarea", target)[0];

                ui.appendChild(trigger);
                ui.appendChild(target);

                player.embedCode = function () {
                    var embedConf = player.conf.embed || {},
                        video = player.video;

                    if (embedConf.iframe) {
                        var src = player.conf.embed.iframe,
                            width = embedConf.width || video.width || common.width(root),
                            height = embedConf.height || video.height || common.height(root);
                        return '<iframe src="' + player.conf.embed.iframe + '" allowfullscreen style="width:' + width + ';height:' + height + ';border:none;"></iframe>';
                    }
                    var props = ['ratio', 'rtmp', 'live', 'bufferTime', 'origin', 'analytics', 'key', 'subscribe', 'swf', 'swfHls', 'embed', 'adaptiveRatio', 'logo'];
                    if (embedConf.playlist) props.push('playlist');
                    var c = common.pick(player.conf, props);
                    if (c.logo) c.logo = common.createElement('img', {src: c.logo}).src;
                    if (!embedConf.playlist || !player.conf.playlist.length) c.clip = extend({}, player.conf.clip, common.pick(player.video, ['sources']));
                    var script = "var w=window,d=document,e;w._fpes||(w._fpes=[],w.addEventListener(\"load\",function(){var s=d.createElement(\"script\");s.src=\"//embed.flowplayer.org/6.0.5/embed.min.js\",d.body.appendChild(s)})),e=[].slice.call(d.getElementsByTagName(\"script\"),-1)[0].parentNode,w._fpes.push({e:e,l:\"$library\",c:$conf});\n".replace('$conf', JSON.stringify(c)).replace('$library', embedConf.library || '');

                    return '<a href="$href">Watch video!\n<script>$script</script></a>'.replace('$href', player.conf.origin || window.location.href).replace('$script', script);

                };
                fptip(root, ".fp-embed", "is-embedding");

                bean.on(root, 'click', '.fp-embed-code textarea', function () {
                    area.select();
                });

                bean.on(root, 'click', '.fp-embed', function () {
                    area.textContent = player.embedCode().replace(/(\r\n|\n|\r)/gm, "");
                    area.focus();
                    area.select();
                });

            });

            var fptip = function (root, trigger, active) {

                function close() {
                    rootClasses.remove(active);
                    bean.off(document, '.st');
                }

                var rootClasses = ClassList(root);

                bean.on(root, 'click', trigger || 'a', function (e) {
                    e.preventDefault();

                    rootClasses.toggle(active);

                    if (rootClasses.contains(active)) {

                        bean.on(document, 'keydown.st', function (e) {
                            if (e.which == 27) close();
                        });
                        bean.on(document, 'click.st', function (e) {
                            if (!common.hasParent(e.target, '.' + active)) close();
                        });
                    }
                });
            };


        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22, "extend-object": 26, "is-object": 28}],
        8: [function (_dereq_, module, exports) {
            'use strict';
            /* global jQuery */
            /**
             * Mimimal jQuery-like event emitter implementation
             */
            module.exports = function (obj, elem) {
                if (!elem) elem = document.createElement('div'); //In this case we always want to trigger (Custom)Events on dom element
                var handlers = {}, eventArguments = {};

                var listenEvent = function (type, hndlr, disposable) {
                    var actualEvent = type.split('.')[0]; //Strip namespace
                    var internalHandler = function (ev) {
                        if (disposable) {
                            elem.removeEventListener(actualEvent, internalHandler);
                            handlers[type].splice(handlers[type].indexOf(internalHandler), 1);
                        }
                        var args = [ev].concat(eventArguments[ev.timeStamp + ev.type] || []);
                        if (hndlr) hndlr.apply(undefined, args);
                    };
                    elem.addEventListener(actualEvent, internalHandler);

                    //Store handlers for unbinding
                    if (!handlers[type]) handlers[type] = [];
                    handlers[type].push(internalHandler);
                };

                obj.on = obj.bind = function (typ, hndlr) {
                    var types = typ.split(' ');
                    types.forEach(function (type) {
                        listenEvent(type, hndlr);
                    });
                    return obj; //for chaining
                };

                obj.one = function (typ, hndlr) {
                    var types = typ.split(' ');
                    types.forEach(function (type) {
                        listenEvent(type, hndlr, true);
                    });
                    return obj;
                };

                // Function to check if all items in toBeContained array are in the containing array
                var containsAll = function (containing, toBeContained) {
                    return toBeContained.filter(function (i) {
                        return containing.indexOf(i) === -1;
                    }).length === 0;
                };


                obj.off = obj.unbind = function (typ) {
                    var types = typ.split(' ');
                    types.forEach(function (type) {
                        var typeNameSpaces = type.split('.').slice(1),
                            actualType = type.split('.')[0];
                        Object.keys(handlers).filter(function (t) {
                            var handlerNamespaces = t.split('.').slice(1);
                            return (!actualType || t.indexOf(actualType) === 0) && containsAll(handlerNamespaces, typeNameSpaces);
                        }).forEach(function (t) {
                            var registererHandlers = handlers[t],
                                actualEvent = t.split('.')[0];
                            registererHandlers.forEach(function (hndlr) {
                                elem.removeEventListener(actualEvent, hndlr);
                                registererHandlers.splice(registererHandlers.indexOf(hndlr), 1);
                            });
                        });
                    });
                    return obj;
                };

                obj.trigger = function (typ, args, returnEvent) {
                    if (!typ) return;
                    args = (args || []).length ? args || [] : [args];
                    var event = document.createEvent('Event'), typStr;
                    typStr = typ.type || typ;
                    event.initEvent(typStr, false, true);
                    if (Object.defineProperty) event.preventDefault = function () {
                        Object.defineProperty(this, 'defaultPrevented', {
                            get: function () {
                                return true;
                            }
                        });
                    };
                    eventArguments[event.timeStamp + event.type] = args;
                    elem.dispatchEvent(event);
                    return returnEvent ? event : obj;
                };
            };


            module.exports.EVENTS = [
                'beforeseek',
                'disable',
                'error',
                'finish',
                'fullscreen',
                'fullscreen-exit',
                'load',
                'mute',
                'pause',
                'progress',
                'ready',
                'resume',
                'seek',
                'speed',
                'stop',
                'unload',
                'volume',
                'boot',
                'shutdown'
            ];

        }, {}],
        9: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                bean = _dereq_('bean'),
                ClassList = _dereq_('class-list'),
                extend = _dereq_('extend-object'),
                common = _dereq_('../common'),
                VENDOR = flowplayer.support.browser.mozilla ? "moz" : "webkit",
                FS_ENTER = "fullscreen",
                FS_EXIT = "fullscreen-exit",
                FULL_PLAYER,
                FS_SUPPORT = flowplayer.support.fullscreen,
                FS_NATIVE_SUPPORT = typeof document.exitFullscreen == 'function',
                ua = navigator.userAgent.toLowerCase(),
                IS_SAFARI = /(safari)[ \/]([\w.]+)/.exec(ua) && !/(chrome)[ \/]([\w.]+)/.exec(ua);


// esc button
            bean.on(document, "fullscreenchange.ffscr webkitfullscreenchange.ffscr mozfullscreenchange.ffscr MSFullscreenChange.ffscr", function (e) {
                var el = document.webkitCurrentFullScreenElement || document.mozFullScreenElement || document.fullscreenElement || document.msFullscreenElement || e.target;
                if (!FULL_PLAYER && (!el.parentNode || !el.parentNode.getAttribute('data-flowplayer-instance-id'))) return;
                var player = FULL_PLAYER || flowplayer(el.parentNode);
                if (el && !FULL_PLAYER) {
                    FULL_PLAYER = player.trigger(FS_ENTER, [el]);
                } else {
                    FULL_PLAYER.trigger(FS_EXIT, [FULL_PLAYER]);
                    FULL_PLAYER = null;
                }
            });

            flowplayer(function (player, root) {

                var wrapper = common.createElement('div', {className: 'fp-player'});
                Array.prototype.map.call(root.children, common.identity).forEach(function (el) {
                    if (common.matches(el, '.fp-ratio,script')) return;
                    wrapper.appendChild(el);
                });
                root.appendChild(wrapper);

                if (!player.conf.fullscreen) return;

                var win = window,
                    scrollY,
                    scrollX,
                    rootClasses = ClassList(root);

                player.isFullscreen = false;

                player.fullscreen = function (flag) {

                    if (player.disabled) return;

                    if (flag === undefined) flag = !player.isFullscreen;

                    if (flag) {
                        scrollY = win.scrollY;
                        scrollX = win.scrollX;
                    }

                    if (FS_SUPPORT) {

                        if (flag) {
                            ['requestFullScreen', 'webkitRequestFullScreen', 'mozRequestFullScreen', 'msRequestFullscreen'].forEach(function (fName) {
                                if (typeof wrapper[fName] === 'function') {
                                    wrapper[fName](Element.ALLOW_KEYBOARD_INPUT);
                                    if (IS_SAFARI && !document.webkitCurrentFullScreenElement && !document.mozFullScreenElement) { // Element.ALLOW_KEYBOARD_INPUT not allowed
                                        wrapper[fName]();
                                    }
                                    return false;
                                }
                            });

                        } else {
                            ['exitFullscreen', 'webkitCancelFullScreen', 'mozCancelFullScreen', 'msExitFullscreen'].forEach(function (fName) {
                                if (typeof document[fName] === 'function') {
                                    document[fName]();
                                    return false;
                                }
                            });
                        }

                    } else {
                        player.trigger(flag ? FS_ENTER : FS_EXIT, [player]);
                    }

                    return player;
                };

                var lastClick;

                player.on("mousedown.fs", function () {
                    if (+new Date() - lastClick < 150 && player.ready) player.fullscreen();
                    lastClick = +new Date();
                });

                player.on(FS_ENTER, function (e) {
                    rootClasses.add("is-fullscreen");
                    if (!FS_SUPPORT) common.css(root, 'position', 'fixed');
                    player.isFullscreen = true;

                }).on(FS_EXIT, function (e) {
                    var oldOpacity;
                    if (!FS_SUPPORT && player.engine === "html5") {
                        oldOpacity = root.css('opacity') || '';
                        common.css(root, 'opacity', 0);
                    }
                    if (!FS_SUPPORT) common.css(root, 'position', '');
                    rootClasses.remove("is-fullscreen");
                    if (!FS_SUPPORT && player.engine === "html5") setTimeout(function () {
                        root.css('opacity', oldOpacity);
                    });
                    player.isFullscreen = false;
                    win.scrollTo(scrollX, scrollY);
                }).on('unload', function () {
                    if (player.isFullscreen) player.fullscreen();
                });

                player.on('shutdown', function () {
                    FULL_PLAYER = null;
                });

            });

        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22, "extend-object": 26}],
        10: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                bean = _dereq_('bean'),
                focused,
                focusedRoot,
                IS_HELP = "is-help",
                common = _dereq_('../common'),
                ClassList = _dereq_('class-list');

            // keyboard. single global listener
            bean.on(document, "keydown.fp", function (e) {

                var el = focused,
                    metaKeyPressed = e.ctrlKey || e.metaKey || e.altKey,
                    key = e.which,
                    conf = el && el.conf,
                    focusedRootClasses = focusedRoot && ClassList(focusedRoot);

                if (!el || !conf.keyboard || el.disabled) return;

                // help dialog (shift key not truly required)
                if ([63, 187, 191].indexOf(key) != -1) {
                    focusedRootClasses.toggle(IS_HELP);
                    return false;
                }

                // close help / unload
                if (key == 27 && focusedRootClasses.contains(IS_HELP)) {
                    focusedRootClasses.toggle(IS_HELP);
                    return false;
                }

                if (!metaKeyPressed && el.ready) {

                    e.preventDefault();

                    // slow motion / fast forward
                    if (e.shiftKey) {
                        if (key == 39) el.speed(true);
                        else if (key == 37) el.speed(false);
                        return;
                    }

                    // 1, 2, 3, 4 ..
                    if (key < 58 && key > 47) return el.seekTo(key - 48);

                    switch (key) {
                        case 38:
                        case 75:
                            el.volume(el.volumeLevel + 0.15);
                            break;        // volume up
                        case 40:
                        case 74:
                            el.volume(el.volumeLevel - 0.15);
                            break;        // volume down
                        case 39:
                        case 76:
                            el.seeking = true;
                            el.seek(true);
                            break;        // forward
                        case 37:
                        case 72:
                            el.seeking = true;
                            el.seek(false);
                            break;       // backward
                        case 190:
                            el.seekTo();
                            break;                                     // to last seek position
                        case 32:
                            el.toggle();
                            break;                                      // spacebar
                        case 70:
                            if (conf.fullscreen) el.fullscreen();
                            break;               // toggle fullscreen
                        case 77:
                            el.mute();
                            break;                                        // mute
                        case 81:
                            el.unload();
                            break;                                      // unload/stop
                    }

                }

            });

            flowplayer(function (api, root) {

                // no keyboard configured
                if (!api.conf.keyboard) return;

                // hover
                bean.on(root, "mouseenter mouseleave", function (e) {
                    focused = !api.disabled && e.type == 'mouseover' ? api : 0;
                    if (focused) focusedRoot = root;
                });

                var speedhelp = flowplayer.support.video && api.conf.engine !== "flash" &&
                !!document.createElement('video').playbackRate ?
                    '<p><em>shift</em> + <em>&#8592;</em><em>&#8594;</em>slower / faster</p>' : '';

                // TODO: add to player-layout.html
                root.appendChild(common.createElement('div', {className: 'fp-help'}, '\
         <a class="fp-close"></a>\
         <div class="fp-help-section fp-help-basics">\
            <p><em>space</em>play / pause</p>\
            <p><em>q</em>unload | stop</p>\
            <p><em>f</em>fullscreen</p>' + speedhelp + '\
         </div>\
         <div class="fp-help-section">\
            <p><em>&#8593;</em><em>&#8595;</em>volume</p>\
            <p><em>m</em>mute</p>\
         </div>\
         <div class="fp-help-section">\
            <p><em>&#8592;</em><em>&#8594;</em>seek</p>\
            <p><em>&nbsp;. </em>seek to previous\
            </p><p><em>1</em><em>2</em>&hellip; <em>6</em> seek to 10%, 20% &hellip; 60% </p>\
         </div>\
   '));

                if (api.conf.tooltip) {
                    var ui = common.find('.fp-ui', root)[0];
                    ui.setAttribute('title', 'Hit ? for help');
                    bean.one(root, "mouseout.tip", '.fp-ui', function () {
                        ui.removeAttribute('title');
                    });
                }

                bean.on(root, 'click', '.fp-close', function () {
                    ClassList(root).toggle(IS_HELP);
                });

                api.bind('shutdown', function () {
                    if (focusedRoot == root) focusedRoot = null;
                });

            });


        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22}],
        11: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                isIeMobile = /IEMobile/.test(window.navigator.userAgent),
                ClassList = _dereq_('class-list'),
                common = _dereq_('../common'),
                bean = _dereq_('bean'),
                format = _dereq_('./ui').format,
                UA = window.navigator.userAgent;
            if (flowplayer.support.touch || isIeMobile) {

                flowplayer(function (player, root) {
                    var isAndroid = /Android/.test(UA) && !/Firefox/.test(UA) && !/Opera/.test(UA),
                        isSilk = /Silk/.test(UA),
                        androidVer = isAndroid ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0,
                        rootClasses = ClassList(root);

                    // custom load for android
                    if (isAndroid && !isIeMobile) {
                        if (!/Chrome/.test(UA) && androidVer < 4) {
                            var originalLoad = player.load;
                            player.load = function (video, callback) {
                                var ret = originalLoad.apply(player, arguments);
                                player.trigger('ready', [player, player.video]);
                                return ret;
                            };
                        }
                        var timer, currentTime = 0;
                        var resumeTimer = function (api) {
                            timer = setInterval(function () {
                                api.video.time = ++currentTime;
                                api.trigger('progress', [api, currentTime]);
                            }, 1000);
                        };
                        player.bind('ready pause unload', function () {
                            if (timer) {
                                clearInterval(timer);
                                timer = null;
                            }
                        });
                        player.bind('ready', function () {
                            currentTime = 0;
                        });
                        player.bind('resume', function (ev, api) {
                            if (!api.live) return;
                            if (currentTime) {
                                return resumeTimer(api);
                            }
                            player.one('progress', function (ev, api, t) {
                                if (t === 0) { // https://github.com/flowplayer/flowplayer/issues/727
                                    resumeTimer(api);
                                }
                            });
                        });
                    }

                    // hide volume
                    if (!flowplayer.support.volume) {
                        rootClasses.add("no-volume");
                        rootClasses.add("no-mute");
                    }
                    rootClasses.add("is-touch");
                    if (player.sliders && player.sliders.timeline) player.sliders.timeline.disableAnimation();

                    if (!flowplayer.support.inlineVideo || player.conf.native_fullscreen) player.conf.nativesubtitles = true;

                    // fake mouseover effect with click
                    var hasMoved = false;
                    bean.on(root, 'touchmove', function () {
                        hasMoved = true;
                    });
                    bean.on(root, 'touchend click', function (e) {
                        if (hasMoved) { //not intentional, most likely scrolling
                            hasMoved = false;
                            return;
                        }

                        if (player.playing && !rootClasses.contains("is-mouseover")) {
                            rootClasses.add("is-mouseover");
                            rootClasses.remove("is-mouseout");
                            e.preventDefault();
                            e.stopPropagation();
                            return;
                        }

                        if (!player.playing && !player.splash && rootClasses.contains('is-mouseout') && !rootClasses.contains('is-mouseover')) {
                            setTimeout(function () {
                                if (!player.playing && !player.splash) {
                                    player.resume();
                                }
                            }, 400);
                        }


                    });

                    // native fullscreen
                    if (player.conf.native_fullscreen && typeof document.createElement('video').webkitEnterFullScreen === 'function') {
                        player.fullscreen = function () {
                            var video = common.find('video.fp-engine', root)[0];
                            video.webkitEnterFullScreen();
                            bean.one(video, 'webkitendfullscreen', function () {
                                common.prop(video, 'controls', true);
                                common.prop(video, 'controls', false);
                            });
                        };
                    }


                    // Android browser gives video.duration == 1 until second 'timeupdate' event
                    if (isAndroid || isSilk) player.bind("ready", function () {

                        var video = common.find('video.fp-engine', root)[0];
                        bean.one(video, 'canplay', function () {
                            video.play();
                        });
                        video.play();

                        player.bind("progress.dur", function () {

                            var duration = video.duration;

                            if (duration !== 1) {
                                player.video.duration = duration;
                                common.find(".fp-duration", root)[0].innerHTML = format(duration);
                                player.unbind("progress.dur");
                            }
                        });
                    });


                });

            }


        }, {"../common": 1, "../flowplayer": 18, "./ui": 17, "bean": 20, "class-list": 22}],
        12: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                extend = _dereq_('extend-object'),
                bean = _dereq_('bean'),
                ClassList = _dereq_('class-list'),
                common = _dereq_('../common'),
                Resolve = _dereq_('./resolve'),
                resolver = new Resolve(),
                $ = window.jQuery,
                externalRe = /^#/;
            flowplayer(function (player, root) {

                var conf = extend({active: 'is-active', advance: true, query: ".fp-playlist a"}, player.conf),
                    klass = conf.active, rootClasses = ClassList(root);

                // getters
                function els() {
                    return common.find(conf.query, queryRoot());
                }

                function queryRoot() {
                    if (externalRe.test(conf.query)) return;
                    return root;
                }

                function active() {
                    return common.find(conf.query + "." + klass, queryRoot());
                }


                player.play = function (i) {
                    if (i === undefined) return player.resume();
                    if (typeof i === 'number' && !player.conf.playlist[i]) return player;
                    else if (typeof i != 'number') return player.load.apply(null, arguments);
                    var arg = extend({index: i}, player.conf.playlist[i]);
                    if (i === player.video.index) return player.load(arg, function () {
                        player.resume();
                    });
                    player.off('resume.fromfirst'); // Don't start from beginning if clip explicitely chosen
                    player.load(arg, function () {
                        player.video.index = i;
                    });
                    return player;
                };

                player.next = function (e) {
                    if (e) e.preventDefault();
                    var current = player.video.index;
                    if (current != -1) {
                        current = current === player.conf.playlist.length - 1 ? 0 : current + 1;
                        player.play(current);
                    }
                    return player;
                };

                player.prev = function (e) {
                    if (e) e.preventDefault();
                    var current = player.video.index;
                    if (current != -1) {
                        current = current === 0 ? player.conf.playlist.length - 1 : current - 1;
                        player.play(current);
                    }
                    return player;
                };

                player.setPlaylist = function (items) {
                    player.conf.playlist = items;
                    delete player.video.index;
                    generatePlaylist();
                    return player;
                };

                player.addPlaylistItem = function (item) {
                    return player.setPlaylist(player.conf.playlist.concat([item]));
                };

                player.removePlaylistItem = function (idx) {
                    var pl = player.conf.playlist;
                    return player.setPlaylist(pl.slice(0, idx).concat(pl.slice(idx + 1)));
                };

                bean.on(root, 'click', '.fp-next', player.next);
                bean.on(root, 'click', '.fp-prev', player.prev);

                if (conf.advance) {
                    player.off("finish.pl").on("finish.pl", function (e, player) {
                        // clip looping
                        if (player.video.loop) return player.seek(0, function () {
                            player.resume();
                        });
                        // next clip is found or loop
                        var next = player.video.index >= 0 ? player.video.index + 1 : undefined;
                        if (next < player.conf.playlist.length || conf.loop) {
                            next = next === player.conf.playlist.length ? 0 : next;
                            rootClasses.remove('is-finished');
                            setTimeout(function () { // Let other finish callbacks fire first
                                player.play(next);
                            });

                            // stop to last clip, play button starts from 1:st clip
                        } else {

                            // If we have multiple items in playlist, start from first
                            if (player.conf.playlist.length > 1) player.one("resume.fromfirst", function () {
                                player.play(0);
                                return false;
                            });
                        }
                    });
                }

                function generatePlaylist() {
                    var plEl = common.find('.fp-playlist', root)[0];
                    if (!plEl) {
                        plEl = common.createElement('div', {className: 'fp-playlist'});
                        var cntrls = common.find('.fp-next,.fp-prev', root);
                        if (!cntrls.length) common.insertAfter(root, common.find('video', root)[0], plEl);
                        else cntrls[0].parentElement.insertBefore(plEl, cntrls[0]);
                    }
                    plEl.innerHTML = '';
                    if (player.conf.playlist[0].length) { // FP5 style playlist
                        player.conf.playlist = player.conf.playlist.map(function (itm) {
                            if (typeof itm === 'string') {
                                var type = itm.split(Resolve.TYPE_RE)[1];
                                return {
                                    sources: [{
                                        type: type.toLowerCase() === 'm3u8' ? 'application/x-mpegurl' : 'video/' + type,
                                        src: itm
                                    }]
                                };
                            }
                            return {
                                sources: itm.map(function (src) {
                                    var s = {};
                                    Object.keys(src).forEach(function (k) {
                                        s.type = /mpegurl/i.test(k) ? 'application/x-mpegurl' : 'video/' + k;
                                        s.src = src[k];
                                    });
                                    return s;
                                })
                            };
                        });
                    }
                    player.conf.playlist.forEach(function (item, i) {
                        var href = item.sources[0].src;
                        plEl.appendChild(common.createElement('a', {
                            href: href,
                            'data-index': i
                        }));
                    });
                }

                var playlistInitialized = false;
                if (player.conf.playlist.length) { // playlist configured by javascript, generate playlist
                    playlistInitialized = true;
                    generatePlaylist();
                    if (!player.conf.clip || !player.conf.clip.sources.length) {
                        player.conf.clip = player.conf.playlist[player.conf.startIndex || 0];
                    }
                }

                if (els().length && !playlistInitialized) { //generate playlist from existing elements
                    player.conf.playlist = [];
                    delete player.conf.startIndex;
                    els().forEach(function (el) {
                        var src = el.href;
                        el.setAttribute('data-index', player.conf.playlist.length);
                        var itm = resolver.resolve(src, player.conf.clip.sources);
                        if ($) {
                            extend(itm, $(el).data());
                        }
                        player.conf.playlist.push(itm);
                    });
                }

                /* click -> play */
                bean.on(externalRe.test(conf.query) ? document : root, "click", conf.query, function (e) {
                    e.preventDefault();
                    var el = e.currentTarget;
                    var toPlay = Number(el.getAttribute('data-index'));
                    if (toPlay != -1) {
                        player.play(toPlay);
                    }
                });

                // highlight
                function videoIndex(video) {
                    if (typeof video.index !== 'undefined') return video.index;
                    if (typeof player.video.index !== 'undefined') return player.video.index;
                    return player.conf.startIndex || 0;
                }

                player.on("load", function (e, api, video) {
                    if (!player.conf.playlist.length) return;
                    var prev = active()[0],
                        prevIndex = prev && prev.getAttribute('data-index'),
                        index = video.index = videoIndex(video),
                        el = common.find(conf.query + '[data-index="' + index + '"]', queryRoot())[0],
                        is_last = index == player.conf.playlist.length - 1;
                    if (prev) ClassList(prev).remove(klass);
                    if (el) ClassList(el).add(klass);
                    // index
                    rootClasses.remove("video" + prevIndex);
                    rootClasses.add("video" + index);
                    common.toggleClass(root, "last-video", is_last);

                    // video properties
                    video.index = api.video.index = index;
                    video.is_last = api.video.is_last = is_last;

                    // without namespace callback called only once. unknown rason.
                }).on("unload.pl", function () {
                    if (!player.conf.playlist.length) return;
                    active().forEach(function (el) {
                        ClassList(el).toggle(klass);
                    });
                    player.conf.playlist.forEach(function (itm, i) {
                        rootClasses.remove('video' + i);
                    });
                });

                if (player.conf.playlist.length) {
                    // disable single clip looping
                    player.conf.loop = false;
                }


            });

        }, {"../common": 1, "../flowplayer": 18, "./resolve": 13, "bean": 20, "class-list": 22, "extend-object": 26}],
        13: [function (_dereq_, module, exports) {
            'use strict';
            var TYPE_RE = /\.(\w{3,4})(\?.*)?$/i,
                extend = _dereq_('extend-object');

            function parseSource(el) {

                var src = el.attr("src"),
                    type = el.attr("type") || "",
                    suffix = src.split(TYPE_RE)[1];
                type = type.toLowerCase();
                return extend(el.data(), {src: src, suffix: suffix || type, type: type || suffix});
            }

            function getType(typ) {
                if (/mpegurl/i.test(typ)) return 'application/x-mpegurl';
                return 'video/' + typ;
            }

            /* Resolves video object from initial configuration and from load() method */
            module.exports = function URLResolver() {
                var self = this;

                self.sourcesFromVideoTag = function (videoTag, $) {
                    /* global $ */
                    var sources = [];
                    // initial sources
                    $("source", videoTag).each(function () {
                        sources.push(parseSource($(this)));
                    });

                    if (!sources.length && videoTag.length) sources.push(parseSource(videoTag));

                    return sources;
                };


                self.resolve = function (video, sources) {
                    if (!video) return {sources: sources};

                    if (typeof video == 'string') {
                        video = {src: video, sources: []};
                        video.sources = (sources || []).map(function (source) {
                            var suffix = source.src.split(TYPE_RE)[1];
                            return {type: source.type, src: video.src.replace(TYPE_RE, '.' + suffix + "$2")};
                        });
                    }

                    if (video instanceof Array) {
                        video = {
                            sources: video.map(function (src) {
                                if (src.type && src.src) return src;
                                return Object.keys(src).reduce(function (m, typ) {
                                    return extend(m, {
                                        type: getType(typ),
                                        src: src[typ]
                                    });
                                }, {});
                            })
                        };
                    }

                    return video;
                };
            };

            module.exports.TYPE_RE = TYPE_RE;

        }, {"extend-object": 26}],
        14: [function (_dereq_, module, exports) {
            'use strict';
// skip IE policies
// document.ondragstart = function () { return false; };
//
            var ClassList = _dereq_('class-list'),
                bean = _dereq_('bean'),
                common = _dereq_('../common');


// execute function every <delay> ms
            var throttle = function (fn, delay) {
                var locked;

                return function () {
                    if (!locked) {
                        fn.apply(this, arguments);
                        locked = 1;
                        setTimeout(function () {
                            locked = 0;
                        }, delay);
                    }
                };
            };


            var slider = function (root, rtl) {
                var IS_IPAD = /iPad/.test(navigator.userAgent) && !/CriOS/.test(navigator.userAgent);

                var progress = common.lastChild(root),
                    rootClasses = ClassList(root),
                    progressClasses = ClassList(progress),
                    disabled,
                    offset,
                    width,
                    height,
                    vertical,
                    size,
                    maxValue,
                    max,
                    skipAnimation = false,

                    /* private */
                    calc = function () {
                        offset = common.offset(root);
                        width = common.width(root);
                        height = common.height(root);

                        /* exit from fullscreen can mess this up.*/
                        // vertical = height > width;

                        size = vertical ? height : width;
                        max = toDelta(maxValue);
                    },

                    fire = function (value) {
                        if (!disabled && value != api.value && (!maxValue || value < maxValue)) {
                            bean.fire(root, 'slide', [value]);
                            api.value = value;
                        }
                    },

                    mousemove = function (e) {
                        var pageX = e.pageX || e.clientX;
                        if (!pageX && e.originalEvent && e.originalEvent.touches && e.originalEvent.touches.length) {
                            pageX = e.originalEvent.touches[0].pageX;
                        }
                        var delta = vertical ? e.pageY - offset.top : pageX - offset.left;
                        delta = Math.max(0, Math.min(max || size, delta));

                        var value = delta / size;
                        if (vertical) value = 1 - value;
                        if (rtl) value = 1 - value;
                        return move(value, 0, true);
                    },

                    move = function (value, speed) {
                        if (speed === undefined) {
                            speed = 0;
                        }
                        if (value > 1) value = 1;

                        var to = (Math.round(value * 1000) / 10) + "%";

                        if (!maxValue || value <= maxValue) {
                            progressClasses.remove('animated');
                            if (skipAnimation) {
                                progressClasses.remove('animated');
                            } else {
                                progressClasses.add('animated');
                                common.css(progress, 'transition-duration', (speed || 0) + 'ms');
                            }
                            common.css(progress, 'width', to);
                        }

                        return value;
                    },

                    toDelta = function (value) {
                        return Math.max(0, Math.min(size, vertical ? (1 - value) * height : value * width));
                    },

                    /* public */
                    api = {

                        max: function (value) {
                            maxValue = value;
                        },

                        disable: function (flag) {
                            disabled = flag;
                        },

                        slide: function (value, speed, fireEvent) {
                            calc();
                            if (fireEvent) fire(value);
                            move(value, speed);
                        },

                        // Should animation be handled via css
                        disableAnimation: function (value, alsoCssAnimations) {
                            skipAnimation = value !== false;
                            common.toggleClass(root, 'no-animation', !!alsoCssAnimations);
                        }

                    };

                calc();

                // bound dragging into document
                bean.on(root, 'mousedown.sld touchstart', function (e) {
                    e.preventDefault();

                    if (!disabled) {
                        // begin --> recalculate. allows dynamic resizing of the slider
                        var delayedFire = throttle(fire, 100);
                        calc();
                        api.dragging = true;
                        rootClasses.add('is-dragging');
                        fire(mousemove(e));

                        bean.on(document, 'mousemove.sld touchmove.sld', function (e) {
                            e.preventDefault();
                            delayedFire(mousemove(e));

                        });
                        bean.one(document, 'mouseup touchend', function () {
                            api.dragging = false;
                            rootClasses.remove('is-dragging');
                            bean.off(document, 'mousemove.sld touchmove.sld');
                        });

                    }

                });
                return api;
            };

            module.exports = slider;

        }, {"../common": 1, "bean": 20, "class-list": 22}],
        15: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                common = _dereq_('../common'),
                bean = _dereq_('bean'),
                ClassList = _dereq_('class-list');

            flowplayer.defaults.subtitleParser = function (txt) {
                var TIMECODE_RE = /^(([0-9]{2}:){1,2}[0-9]{2}[,.][0-9]{3}) --\> (([0-9]{2}:){1,2}[0-9]{2}[,.][0-9]{3})(.*)/;

                function seconds(timecode) {
                    var els = timecode.split(':');
                    if (els.length == 2) els.unshift(0);
                    return els[0] * 60 * 60 + els[1] * 60 + parseFloat(els[2].replace(',', '.'));
                }

                var entries = [];
                for (var i = 0, lines = txt.split("\n"), len = lines.length, entry = {}, title, timecode, text, cue; i < len; i++) {
                    timecode = TIMECODE_RE.exec(lines[i]);

                    if (timecode) {

                        // title
                        title = lines[i - 1];

                        // text
                        text = "<p>" + lines[++i] + "</p><br/>";
                        while (typeof lines[++i] === 'string' && lines[i].trim() && i < lines.length) text += "<p>" + lines[i] + "</p><br/>";

                        // entry
                        entry = {
                            title: title,
                            startTime: seconds(timecode[1]),
                            endTime: seconds(timecode[3]),
                            text: text
                        };
                        entries.push(entry);
                    }
                }
                return entries;
            };

            flowplayer(function (p, root) {
                var wrapClasses, currentPoint, wrap,
                    rootClasses = ClassList(root),
                    subtitleControl;

                var createSubtitleControl = function () {
                    subtitleControl = common.createElement('a', {className: 'fp-menu'});
                    var menu = common.createElement('ul', {className: 'fp-dropdown fp-dropup'});
                    menu.appendChild(common.createElement('li', {'data-subtitle-index': -1}, 'No subtitles'));
                    (p.video.subtitles || []).forEach(function (st, i) {
                        var srcLang = st.srclang || 'en',
                            label = st.label || 'Default (' + srcLang + ')';
                        var item = common.createElement('li', {'data-subtitle-index': i}, label);
                        menu.appendChild(item);
                    });
                    subtitleControl.appendChild(menu);
                    common.find('.fp-controls', root)[0].appendChild(subtitleControl);
                    return subtitleControl;
                };

                bean.on(root, 'click', '.fp-menu', function (ev) {
                    ClassList(subtitleControl).toggle('dropdown-open');
                });

                bean.on(root, 'click', '.fp-menu li[data-subtitle-index]', function (ev) {
                    var idx = ev.target.getAttribute('data-subtitle-index');
                    if (idx === '-1') return p.disableSubtitles();
                    p.loadSubtitles(idx);
                });

                var createUIElements = function () {
                    var playerEl = common.find('.fp-player', root)[0];
                    wrap = common.find('.fp-subtitle', root)[0];
                    wrap = wrap || common.appendTo(common.createElement('div', {'class': 'fp-subtitle'}), playerEl);
                    Array.prototype.forEach.call(wrap.children, common.removeNode);
                    wrapClasses = ClassList(wrap);
                    common.find('.fp-menu', root).forEach(common.removeNode);
                    createSubtitleControl();
                };


                p.on('ready', function (ev, player, video) {
                    var conf = player.conf;
                    if (flowplayer.support.subtitles && conf.nativesubtitles && player.engine.engineName == 'html5') {
                        var setMode = function (mode) {
                            var tracks = common.find('video', root)[0].textTracks;
                            if (!tracks.length) return;
                            tracks[0].mode = mode;
                        };
                        if (!video.subtitles || !video.subtitles.length) return;
                        var videoTag = common.find('video.fp-engine', root)[0];
                        if (video.subtitles.some(function (st) {
                                return !common.isSameDomain(st.src);
                            })) common.attr(videoTag, 'crossorigin', 'anonymous');
                        videoTag.textTracks.addEventListener('addtrack', function () {
                            setMode('disabled');
                            setMode('showing');
                        });
                        video.subtitles.forEach(function (st) {
                            videoTag.appendChild(common.createElement('track', {
                                kind: 'subtitles',
                                srclang: st.srclang || 'en',
                                label: st.label || 'en',
                                src: st.src,
                                'default': st['default']
                            }));
                        });
                        return;
                    }

                    player.subtitles = [];

                    createUIElements();

                    rootClasses.remove('has-menu');

                    p.disableSubtitles();

                    if (!video.subtitles || !video.subtitles.length) return;

                    rootClasses.add('has-menu');
                    var defaultSubtitle = video.subtitles.filter(function (one) {
                        return one['default'];
                    })[0];
                    if (defaultSubtitle) player.loadSubtitles(video.subtitles.indexOf(defaultSubtitle));
                });

                p.bind("cuepoint", function (e, api, cue) {
                    if (cue.subtitle) {
                        currentPoint = cue.index;
                        common.html(wrap, cue.subtitle.text);
                        wrapClasses.add('fp-active');
                    } else if (cue.subtitleEnd) {
                        wrapClasses.remove('fp-active');
                        currentPoint = cue.index;
                    }
                });

                p.bind("seek", function (e, api, time) {
                    // Clear future subtitles if seeking backwards
                    if (currentPoint && p.cuepoints[currentPoint] && p.cuepoints[currentPoint].time > time) {
                        wrapClasses.remove('fp-active');
                        currentPoint = null;
                    }
                    (p.cuepoints || []).forEach(function (cue) {
                        var entry = cue.subtitle;
                        //Trigger cuepoint if start time before seek position and end time nonexistent or in the future
                        if (entry && currentPoint != cue.index) {
                            if (time >= cue.time && (!entry.endTime || time <= entry.endTime)) p.trigger("cuepoint", [p, cue]);
                        } // Also handle cuepoints that act as the removal trigger
                        else if (cue.subtitleEnd && time >= cue.time && cue.index == currentPoint + 1) p.trigger("cuepoint", [p, cue]);
                    });

                });

                var setActiveSubtitleClass = function (idx) {
                    common.toggleClass(common.find('li.active', root)[0], 'active');
                    common.toggleClass(common.find('li[data-subtitle-index="' + idx + '"]', root)[0], 'active');
                };

                p.disableSubtitles = function () {
                    p.subtitles = [];
                    (p.cuepoints || []).forEach(function (c) {
                        if (c.subtitle || c.subtitleEnd) p.removeCuepoint(c);
                    });
                    if (wrap) Array.prototype.forEach.call(wrap.children, common.removeNode);
                    setActiveSubtitleClass(-1);
                    return p;
                };

                p.loadSubtitles = function (i) {
                    //First remove possible old subtitles
                    p.disableSubtitles();

                    var st = p.video.subtitles[i];

                    var url = st.src;
                    if (!url) return;
                    setActiveSubtitleClass(i);
                    common.xhrGet(url, function (txt) {
                        var entries = p.conf.subtitleParser(txt);
                        entries.forEach(function (entry) {
                            var cue = {time: entry.startTime, subtitle: entry, visible: false};
                            p.subtitles.push(entry);
                            p.addCuepoint(cue);
                            p.addCuepoint({time: entry.endTime, subtitleEnd: entry.title, visible: false});

                            // initial cuepoint
                            if (entry.startTime === 0 && !p.video.time) {
                                p.trigger("cuepoint", [p, cue]);
                            }
                        });
                    }, function () {
                        p.trigger("error", {code: 8, url: url});
                        return false;
                    });
                    return p;
                };
            });


        }, {"../common": 1, "../flowplayer": 18, "bean": 20, "class-list": 22}],
        16: [function (_dereq_, module, exports) {
            'use strict';
            /* global ActiveXObject */
            var flowplayer = _dereq_('../flowplayer'),
                extend = _dereq_('extend-object');
            (function () {

                var parseIpadVersion = function (UA) {
                    var e = /Version\/(\d\.\d)/.exec(UA);
                    if (e && e.length > 1) {
                        return parseFloat(e[1], 10);
                    }
                    return 0;
                };

                var createVideoTag = function () {
                    var videoTag = document.createElement('video');
                    videoTag.loop = true;
                    videoTag.autoplay = true;
                    videoTag.preload = true;
                    return videoTag;
                };

                var b = {},
                    ua = navigator.userAgent.toLowerCase(),
                    match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
                        /(safari)[ \/]([\w.]+)/.exec(ua) ||
                        /(webkit)[ \/]([\w.]+)/.exec(ua) ||
                        /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
                        /(msie) ([\w.]+)/.exec(ua) ||
                        ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];

                if (match[1]) {
                    b[match[1]] = true;
                    b.version = match[2] || "0";
                }

                var video = createVideoTag(),
                    UA = navigator.userAgent,
                    IS_IE = b.msie || /Trident\/7/.test(UA),
                    IS_IPAD = /iPad|MeeGo/.test(UA) && !/CriOS/.test(UA),
                    IS_IPAD_CHROME = /iPad/.test(UA) && /CriOS/.test(UA),
                    IS_IPHONE = /iP(hone|od)/i.test(UA) && !/iPad/.test(UA) && !/IEMobile/i.test(UA),
                    IS_ANDROID = /Android/.test(UA) && !/Firefox/.test(UA),
                    IS_ANDROID_FIREFOX = /Android/.test(UA) && /Firefox/.test(UA),
                    IS_SILK = /Silk/.test(UA),
                    IS_WP = /IEMobile/.test(UA),
                    WP_VER = IS_WP ? parseFloat(/Windows\ Phone\ (\d+\.\d+)/.exec(UA)[1], 10) : 0,
                    IE_MOBILE_VER = IS_WP ? parseFloat(/IEMobile\/(\d+\.\d+)/.exec(UA)[1], 10) : 0,
                    IPAD_VER = IS_IPAD ? parseIpadVersion(UA) : 0,
                    ANDROID_VER = IS_ANDROID ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0,
                    s = extend(flowplayer.support, {

                        browser: b,
                        subtitles: !!video.addTextTrack,
                        fullscreen: typeof document.webkitCancelFullScreen == 'function' && !/Mac OS X 10_5.+Version\/5\.0\.\d Safari/.test(UA) ||
                        document.mozFullScreenEnabled ||
                        typeof document.exitFullscreen == 'function' ||
                        typeof document.msExitFullscreen == 'function',
                        inlineBlock: !(IS_IE && b.version < 8),
                        touch: ('ontouchstart' in window),
                        dataload: !IS_IPAD && !IS_IPHONE && !IS_WP,
                        zeropreload: !IS_IE && !IS_ANDROID, // IE supports only preload=metadata
                        volume: !IS_IPAD && !IS_ANDROID && !IS_IPHONE && !IS_SILK && !IS_IPAD_CHROME,
                        cachedVideoTag: !IS_IPAD && !IS_IPHONE && !IS_IPAD_CHROME && !IS_WP,
                        firstframe: !IS_IPHONE && !IS_IPAD && !IS_ANDROID && !IS_SILK && !IS_IPAD_CHROME && !IS_WP && !IS_ANDROID_FIREFOX,
                        inlineVideo: !IS_IPHONE && (!IS_WP || (WP_VER >= 8.1 && IE_MOBILE_VER >= 11)) && (!IS_ANDROID || ANDROID_VER >= 3),
                        hlsDuration: !IS_ANDROID && (!b.safari || IS_IPAD || IS_IPHONE || IS_IPAD_CHROME),
                        seekable: !IS_IPAD && !IS_IPAD_CHROME
                    });

                // flashVideo
                try {
                    var plugin = navigator.plugins["Shockwave Flash"],
                        ver = IS_IE ? new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable('$version') : plugin.description;
                    if (!IS_IE && !plugin[0].enabledPlugin) s.flashVideo = false;
                    else {

                        ver = ver.split(/\D+/);
                        if (ver.length && !ver[0]) ver = ver.slice(1);

                        s.flashVideo = ver[0] > 9 || ver[0] == 9 && ver[3] >= 115;
                    }

                } catch (ignored) {
                }
                try {
                    s.video = !!video.canPlayType;
                    if (s.video) video.canPlayType('video/mp4');
                } catch (e) {
                    s.video = false;
                }

                // animation
                s.animation = (function () {
                    var vendors = ['', 'Webkit', 'Moz', 'O', 'ms', 'Khtml'], el = document.createElement('p');

                    for (var i = 0; i < vendors.length; i++) {
                        if (typeof el.style[vendors[i] + 'AnimationName'] !== 'undefined') return true;
                    }
                })();


            })();


        }, {"../flowplayer": 18, "extend-object": 26}],
        17: [function (_dereq_, module, exports) {
            'use strict';
            var flowplayer = _dereq_('../flowplayer'),
                common = _dereq_('../common'),
                ClassList = _dereq_('class-list'),
                bean = _dereq_('bean'),
                slider = _dereq_('./slider');

            function zeropad(val) {
                val = parseInt(val, 10);
                return val >= 10 ? val : "0" + val;
            }

// display seconds in hh:mm:ss format
            function format(sec) {

                sec = sec || 0;

                var h = Math.floor(sec / 3600),
                    min = Math.floor(sec / 60);

                sec = sec - (min * 60);

                if (h >= 1) {
                    min -= h * 60;
                    return h + ":" + zeropad(min) + ":" + zeropad(sec);
                }

                return zeropad(min) + ":" + zeropad(sec);
            }

            flowplayer(function (api, root) {

                var conf = api.conf,
                    support = flowplayer.support,
                    hovertimer,
                    rootClasses = ClassList(root);
                common.find('.fp-ratio,.fp-ui', root).forEach(common.removeNode);
                rootClasses.add('flowplayer');
                root.appendChild(common.createElement('div', {className: 'fp-ratio'}));
                var ui = common.createElement('div', {className: 'fp-ui'}, '\
         <div class="waiting"><em></em><em></em><em></em></div>\
         <a class="fullscreen"></a>\
         <a class="unload"></a>\
         <p class="speed"></p>\
         <div class="controls">\
            <a class="play"></a>\
            <div class="timeline">\
               <div class="buffer"></div>\
               <div class="progress"></div>\
            </div>\
            <div class="timeline-tooltip fp-tooltip"></div>\
            <div class="volume">\
               <a class="mute"></a>\
               <div class="volumeslider">\
                  <div class="volumelevel"></div>\
               </div>\
            </div>\
         </div>\
         <div class="time">\
            <em class="elapsed">00:00</em>\
            <em class="remaining"></em>\
            <em class="duration">00:00</em>\
         </div>\
         <div class="message"><h2></h2><p></p></div>'.replace(/class="/g, 'class="fp-'));
                root.appendChild(ui);

                function find(klass) {
                    return common.find(".fp-" + klass, root)[0];
                }

                // widgets
                var progress = find("progress"),
                    buffer = find("buffer"),
                    elapsed = find("elapsed"),
                    remaining = find("remaining"),
                    waiting = find("waiting"),
                    ratio = find("ratio"),
                    speed = find("speed"),
                    speedClasses = ClassList(speed),
                    durationEl = find("duration"),
                    controls = find('controls'),
                    timelineTooltip = find('timeline-tooltip'),
                    origRatio = common.css(ratio, 'padding-top'),

                    // sliders
                    timeline = find("timeline"),
                    timelineApi = slider(timeline, api.rtl),

                    volume = find("volume"),
                    fullscreen = find("fullscreen"),
                    volumeSlider = find("volumeslider"),
                    volumeApi = slider(volumeSlider, api.rtl),
                    noToggle = rootClasses.contains('fixed-controls') || rootClasses.contains('no-toggle');

                timelineApi.disableAnimation(rootClasses.contains('is-touch'));
                api.sliders = api.sliders || {};
                api.sliders.timeline = timelineApi;
                api.sliders.volume = volumeApi;

                // aspect ratio
                function setRatio(val) {
                    common.css(ratio, 'padding-top', val * 100 + "%");
                    if (!support.inlineBlock) common.height(common.find('object', root)[0], common.height(root));
                }

                function hover(flag) {
                    if (flag) {
                        rootClasses.add('is-mouseover');
                        rootClasses.remove('is-mouseout');
                    } else {
                        rootClasses.add('is-mouseout');
                        rootClasses.remove('is-mouseover');
                    }
                }

                // loading...
                if (!support.animation) common.html(waiting, "<p>loading &hellip;</p>");

                if (conf.ratio) setRatio(conf.ratio);

                // no fullscreen in IFRAME
                try {
                    if (!conf.fullscreen) common.removeNode(fullscreen);

                } catch (e) {
                    common.removeNode(fullscreen);
                }

                api.on("ready", function (ev, api, video) {

                    var duration = api.video.duration;

                    timelineApi.disable(api.disabled || !duration);

                    if (conf.adaptiveRatio && !isNaN(video.height / video.width)) setRatio(video.height / video.width, true);

                    // initial time & volume
                    common.html([durationEl, remaining], format(duration));

                    // do we need additional space for showing hour
                    common.toggleClass(root, 'is-long', duration >= 3600);
                    volumeApi.slide(api.volumeLevel);

                    if (api.engine.engineName === 'flash') timelineApi.disableAnimation(true, true);
                    else timelineApi.disableAnimation(false);
                    common.find('.fp-title', ui).forEach(common.removeNode);
                    if (video.title) {
                        common.prepend(ui, common.createElement('div', {
                            className: 'fp-title'
                        }, video.title));
                    }


                }).on("unload", function () {
                    if (!origRatio && !conf.splash) common.css(ratio, "paddingTop", "");
                    timelineApi.slide(0);

                    // buffer
                }).on("buffer", function () {
                    var video = api.video,
                        max = video.buffer / video.duration;

                    if (!video.seekable && support.seekable) timelineApi.max(max);
                    if (max < 1) common.css(buffer, "width", (max * 100) + "%");
                    else common.css(buffer, 'width', '100%');

                }).on("speed", function (e, api, val) {
                    common.text(speed, val + "x");
                    speedClasses.add('fp-hilite');
                    setTimeout(function () {
                        speedClasses.remove('fp-hilite');
                    }, 1000);

                }).on("buffered", function () {
                    common.css(buffer, 'width', '100%');
                    timelineApi.max(1);

                    // progress
                }).on("progress", function () {

                    var time = api.video.time,
                        duration = api.video.duration;

                    if (!timelineApi.dragging) {
                        timelineApi.slide(time / duration, api.seeking ? 0 : 250);
                    }

                    common.html(elapsed, format(time));
                    common.html(remaining, '-' + format(duration - time));

                }).on("finish resume seek", function (e) {
                    common.toggleClass(root, "is-finished", e.type == "finish");

                }).on("stop", function () {
                    common.html(elapsed, format(0));
                    timelineApi.slide(0, 100);

                }).on("finish", function () {
                    common.html(elapsed, format(api.video.duration));
                    timelineApi.slide(1, 100);
                    rootClasses.remove('is-seeking');

                    // misc
                }).on("beforeseek", function () {
                    //TODO FIXME
                    //progress.stop();

                }).on("volume", function () {
                    volumeApi.slide(api.volumeLevel);


                }).on("disable", function () {
                    var flag = api.disabled;
                    timelineApi.disable(flag);
                    volumeApi.disable(flag);
                    common.toggleClass(root, 'is-disabled', api.disabled);

                }).on("mute", function (e, api, flag) {
                    common.toggleClass(root, 'is-muted', flag);

                }).on("error", function (e, api, error) {
                    common.removeClass(root, 'is-loading');
                    common.removeClass(root, 'is-seeking');
                    common.addClass(root, 'is-error');
                    if (error) {
                        error.message = conf.errors[error.code];
                        api.error = true;

                        var el = common.find('.fp-message', root)[0],
                            video = error.video || api.video;
                        common.find('h2', el)[0].innerHTML = (api.engine && api.engine.engineName || 'html5') + ": " + error.message;
                        common.find('p', el)[0].innerHTML = error.url || video.url || video.src || conf.errorUrls[error.code];
                        api.off("mouseenter click");
                        rootClasses.remove('is-mouseover');
                    }


                    // hover
                });
                //Interaction events
                bean.on(root, "mouseenter mouseleave", function (e) {
                    if (noToggle) return;

                    var is_over = e.type == "mouseover",
                        lastMove;

                    // is-mouseover/out
                    hover(is_over);

                    if (is_over) {

                        var reg = function () {
                            hover(true);
                            lastMove = new Date();
                        };
                        api.on("pause.x volume.x", reg);
                        bean.on(root, 'mousemove.x', reg);

                        hovertimer = setInterval(function () {
                            if (new Date() - lastMove > conf.mouseoutTimeout) {
                                hover(false);
                                lastMove = new Date();
                            }
                        }, 100);

                    } else {
                        bean.off(root, 'mousemove.x');
                        api.off("pause.x volume.x");
                        clearInterval(hovertimer);
                    }


                    // allow dragging over the player edge
                });
                bean.on(root, "mouseleave", function () {

                    if (timelineApi.dragging || volumeApi.dragging) {
                        rootClasses.add('is-mouseover');
                        rootClasses.remove('is-mouseout');
                    }

                    // click
                });
                bean.on(root, "click.player", function (e) {
                    if (api.disabled) return;
                    var kls = ClassList(e.target);
                    if (kls.contains('fp-ui') || kls.contains('fp-engine') || e.flash) {
                        if (e.preventDefault) e.preventDefault();
                        return api.toggle();
                    }
                });

                bean.on(root, 'mousemove', '.fp-timeline', function (ev) {
                    var x = ev.pageX || ev.clientX,
                        delta = x - common.offset(timeline).left,
                        percentage = delta / common.width(timeline),
                        seconds = percentage * api.video.duration;
                    if (percentage < 0) return;
                    common.html(timelineTooltip, format(seconds));
                    common.css(timelineTooltip, 'left', (x - common.offset(controls).left - common.width(timelineTooltip) / 2) + 'px');
                });

                bean.on(root, 'contextmenu', function (ev) {
                    var o = common.offset(common.find('.fp-player', root)[0]),
                        w = window,
                        left = ev.clientX - (o.left + w.scrollX),
                        t = ev.clientY - (o.top + w.scrollY);
                    if (rootClasses.contains('is-flash-disabled')) return;
                    var menu = common.find('.fp-context-menu', root)[0];
                    if (!menu) return;
                    ev.preventDefault();
                    common.css(menu,
                        {
                            left: left + 'px',
                            top: t + 'px',
                            display: 'block'
                        });
                    bean.on(root, 'click', '.fp-context-menu', function (ev) {
                        ev.stopPropagation();
                    });
                    bean.on(document, 'click.outsidemenu', function (ev) {
                        common.css(menu, 'display', 'none');
                        bean.off(document, 'click.outsidemenu');
                    });
                });
                api.on('flashdisabled', function () {
                    rootClasses.add('is-flash-disabled');
                    api.one('ready progress', function () {
                        rootClasses.remove('is-flash-disabled');
                        common.find('.fp-flash-disabled', root).forEach(common.removeNode);
                    });
                    root.appendChild(common.createElement('div', {className: "fp-flash-disabled"}, 'Adobe Flash is disabled for this page, click player area to enable'));
                });

                // poster -> background image
                if (conf.poster) common.css(root, 'background-image', "url(" + conf.poster + ")");

                var bc = common.css(root, 'background-color'),
                    has_bg = common.css(root, 'background-image') != "none" || bc && bc != "rgba(0, 0, 0, 0)" && bc != "transparent";

                // is-poster class
                if (has_bg && !conf.splash) {
                    if (!conf.poster) conf.poster = true;

                    api.on("ready stop", function () {
                        rootClasses.add("is-poster");
                        api.poster = true;
                        api.one("progress", function () {
                            rootClasses.remove("is-poster");
                            api.poster = false;
                        });
                    });

                }

                if (typeof conf.splash === 'string') {
                    common.css(root, 'background-image', "url('" + conf.splash + "')");
                }

                // default background color if not present
                if (!has_bg && api.forcedSplash) {
                    common.css(root, "background-color", "#555");
                }

                bean.on(root, 'click', '.fp-toggle, .fp-play', function () {
                    if (api.disabled) return;
                    api.toggle();
                });

                /* controlbar elements */
                bean.on(root, 'click', '.fp-mute', function () {
                    api.mute();
                });
                bean.on(root, 'click', '.fp-fullscreen', function () {
                    api.fullscreen();
                });
                bean.on(root, 'click', '.fp-unload', function () {
                    api.unload();
                });

                bean.on(timeline, 'slide', function (val) {
                    api.seeking = true;
                    api.seek(val * api.video.duration);
                });

                bean.on(volumeSlider, 'slide', function (val) {
                    api.volume(val);
                });

                // times

                var time = find('time');
                bean.on(root, 'click', '.fp-time', function () {
                    ClassList(time).toggle('is-inverted');
                });

                hover(noToggle);

                api.on('shutdown', function () {
                    bean.off(timeline);
                    bean.off(volumeSlider);
                });

            });


            module.exports.format = format;

        }, {"../common": 1, "../flowplayer": 18, "./slider": 14, "bean": 20, "class-list": 22}],
        18: [function (_dereq_, module, exports) {
            'use strict';
            var extend = _dereq_('extend-object'),
                isFunction = _dereq_('is-function'),
                ClassList = _dereq_('class-list'),
                bean = _dereq_('bean'),
                common = _dereq_('./common'),
                events = _dereq_('./ext/events');

            var instances = [],
                extensions = [],
                UA = window.navigator.userAgent;


            var oldHandler = window.onbeforeunload;
            window.onbeforeunload = function (ev) {
                instances.forEach(function (api) {
                    if (api.conf.splash) {
                        api.unload();
                    } else {
                        api.bind("error", function () {
                            common.find('.flowplayer.is-error .fp-message').forEach(common.removeNode);
                        });
                    }
                });
                if (oldHandler) return oldHandler(ev);
            };

            var supportLocalStorage = false;
            try {
                if (typeof window.localStorage == "object") {
                    window.localStorage.flowplayerTestStorage = "test";
                    supportLocalStorage = true;
                }
            } catch (ignored) {
            }

            var isSafari = /Safari/.exec(navigator.userAgent) && !/Chrome/.exec(navigator.userAgent),
                m = /(\d+\.\d+) Safari/.exec(navigator.userAgent),
                safariVersion = m ? Number(m[1]) : 100;

            /* flowplayer()  */
            var flowplayer = module.exports = function (fn, opts, callback) {
                if (isFunction(fn)) return extensions.push(fn);
                if (typeof fn == 'number' || typeof fn === 'undefined') return instances[fn || 0];
                if (fn.nodeType) { // Is an element
                    if (fn.getAttribute('data-flowplayer-instance-id') !== null) { // Already flowplayer instance
                        return instances[fn.getAttribute('data-flowplayer-instance-id')];
                    }
                    if (!opts) return; // Can't initialize without data
                    return initializePlayer(fn, opts, callback);
                }
                if (fn.jquery) return flowplayer(fn[0], opts, callback);
                if (typeof fn === 'string') {
                    var el = common.find(fn)[0];
                    return el && flowplayer(el, opts, callback);
                }
            };

            extend(flowplayer, {

                version: '6.0.5',

                engines: [],

                conf: {},

                set: function (key, value) {
                    if (typeof key === 'string') flowplayer.conf[key] = value;
                    else extend(flowplayer.conf, key);
                },

                support: {},

                defaults: {

                    debug: supportLocalStorage ? !!localStorage.flowplayerDebug : false,

                    // true = forced playback
                    disabled: false,

                    fullscreen: window == window.top,

                    // keyboard shortcuts
                    keyboard: true,

                    // default aspect ratio
                    ratio: 9 / 16,

                    adaptiveRatio: false,

                    rtmp: 0,

                    proxy: 'best',

                    splash: false,

                    live: false,

                    swf: "//releases.flowplayer.org/6.0.5/flowplayer.swf",
                    swfHls: "//releases.flowplayer.org/6.0.5/flowplayerhls.swf",

                    speeds: [0.25, 0.5, 1, 1.5, 2],

                    tooltip: true,

                    mouseoutTimeout: 5000,

                    // initial volume level
                    volume: !supportLocalStorage ? 1 : localStorage.muted == "true" ? 0 : !isNaN(localStorage.volume) ? localStorage.volume || 1 : 1,

                    // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes
                    errors: [

                        // video exceptions
                        '',
                        'Video loading aborted',
                        'Network error',
                        'Video not properly encoded',
                        'Video file not found',

                        // player exceptions
                        'Unsupported video',
                        'Skin not found',
                        'SWF file not found',
                        'Subtitles not found',
                        'Invalid RTMP URL',
                        'Unsupported video format. Try installing Adobe Flash.'
                    ],
                    errorUrls: ['', '', '', '', '', '', '', '', '', '',
                        'http://get.adobe.com/flashplayer/'
                    ],
                    playlist: [],

                    hlsFix: isSafari && safariVersion < 8

                },
                // Expose utilities for plugins
                bean: bean,
                common: common,
                extend: extend


            });

// keep track of players
            var playerCount = 0;

            var URLResolver = _dereq_('./ext/resolve');


            if (typeof window.jQuery !== 'undefined') {
                var $ = window.jQuery;
                // auto-install (any video tag with parent .flowplayer)
                $(function () {
                    if (typeof $.fn.flowplayer == 'function') {
                        $('.flowplayer:has(video,script[type="application/json"])').flowplayer();
                    }
                });

                // jQuery plugin
                var videoTagConfig = function (videoTag) {
                    if (!videoTag.length) return {};
                    var clip = videoTag.data() || {}, conf = {};
                    $.each(['autoplay', 'loop', 'preload', 'poster'], function (i, key) {
                        var val = videoTag.attr(key);
                        if (val !== undefined && ['autoplay', 'poster'].indexOf(key) !== -1) conf[key] = val ? val : true;
                        else if (val !== undefined) clip[key] = val ? val : true;
                    });
                    clip.subtitles = videoTag.find('track').map(function () {
                        var tr = $(this);
                        return {
                            src: tr.attr('src'),
                            kind: tr.attr('kind'),
                            label: tr.attr('label'),
                            srclang: tr.attr('srclang'),
                            'default': tr.prop('default')
                        };
                    }).get();

                    clip.sources = (new URLResolver()).sourcesFromVideoTag(videoTag, $);
                    return extend(conf, {clip: clip});
                };
                $.fn.flowplayer = function (opts, callback) {
                    return this.each(function () {
                        if (typeof opts == 'string') opts = {swf: opts};
                        if (isFunction(opts)) {
                            callback = opts;
                            opts = {};
                        }
                        var root = $(this),
                            scriptConf = root.find('script[type="application/json"]'),
                            confObject = scriptConf.length ? JSON.parse(scriptConf.text()) : videoTagConfig(root.find('video')),
                            conf = $.extend({}, opts || {}, confObject, root.data());
                        var api = initializePlayer(this, conf, callback);
                        events.EVENTS.forEach(function (evName) {
                            api.on(evName + '.jquery', function (ev) {
                                root.trigger.call(root, ev.type, ev.detail && ev.detail.args);
                            });
                        });
                        root.data('flowplayer', api);
                    });
                };
            }

            function initializePlayer(element, opts, callback) {
                if (opts && opts.embed) opts.embed = extend({}, flowplayer.defaults.embed, opts.embed);

                var root = element,
                    rootClasses = ClassList(root),
                    conf = extend({}, flowplayer.defaults, flowplayer.conf, opts),
                    storage = {},
                    lastSeekPosition,
                    engine,
                    url,
                    urlResolver = new URLResolver();

                rootClasses.add('is-loading');

                try {
                    storage = supportLocalStorage ? window.localStorage : storage;
                } catch (e) {
                }

                var isRTL = (root.currentStyle && root.currentStyle.direction === 'rtl') ||
                    (window.getComputedStyle && window.getComputedStyle(root, null) !== null && window.getComputedStyle(root, null).getPropertyValue('direction') === 'rtl');

                if (isRTL) rootClasses.add('is-rtl');

                /*** API ***/
                var api = {

                    // properties
                    conf: conf,
                    currentSpeed: 1,
                    volumeLevel: conf.muted ? 0 : typeof conf.volume === "undefined" ? storage.volume * 1 : conf.volume,
                    video: {},

                    // states
                    disabled: false,
                    finished: false,
                    loading: false,
                    muted: storage.muted == "true" || conf.muted,
                    paused: false,
                    playing: false,
                    ready: false,
                    splash: false,
                    rtl: isRTL,

                    // methods
                    load: function (video, callback) {

                        if (api.error || api.loading) return;
                        api.video = {};

                        api.finished = false;

                        video = video || conf.clip;

                        // resolve URL
                        video = extend({}, urlResolver.resolve(video, conf.clip.sources));
                        if (api.playing || api.engine) video.autoplay = true;
                        var engineImpl = selectEngine(video);
                        if (!engineImpl) return api.trigger("error", [api, {code: flowplayer.support.flashVideo ? 5 : 10}]);
                        if (!engineImpl.engineName) throw new Error('engineName property of factory should be exposed');
                        if (!api.engine || engineImpl.engineName !== api.engine.engineName) {
                            api.ready = false;
                            if (api.engine) {
                                api.engine.unload();
                                api.conf.autoplay = true;
                            }
                            engine = api.engine = engineImpl(api, root);
                            api.one('ready', function () {
                                engine.volume(api.volumeLevel);
                            });
                        }

                        extend(video, engine.pick(video.sources.filter(function (source) { // Filter out sources explicitely configured for some other engine
                            if (!source.engine) return true;
                            return source.engine === engine.engineName;
                        })));

                        if (video.src) {
                            var e = api.trigger('load', [api, video, engine], true);
                            if (!e.defaultPrevented) {
                                engine.load(video);

                                // callback
                                if (isFunction(video)) callback = video;
                                if (callback) api.one("ready", callback);
                            } else {
                                api.loading = false;
                            }
                        }

                        return api;
                    },

                    pause: function (fn) {
                        if (api.ready && !api.seeking && !api.loading) {
                            engine.pause();
                            api.one("pause", fn);
                        }
                        return api;
                    },

                    resume: function () {

                        if (api.ready && api.paused) {
                            engine.resume();

                            // Firefox (+others?) does not fire "resume" after finish
                            if (api.finished) {
                                api.trigger("resume", [api]);
                                api.finished = false;
                            }
                        }

                        return api;
                    },

                    toggle: function () {
                        return api.ready ? api.paused ? api.resume() : api.pause() : api.load();
                    },

                    /*
            seek(1.4)   -> 1.4s time
            seek(true)  -> 10% forward
            seek(false) -> 10% backward
         */
                    seek: function (time, callback) {
                        if (api.ready && !api.live) {

                            if (typeof time == "boolean") {
                                var delta = api.video.duration * 0.1;
                                time = api.video.time + (time ? delta : -delta);
                            }
                            time = lastSeekPosition = Math.min(Math.max(time, 0), api.video.duration - 0.1).toFixed(1);
                            var ev = api.trigger('beforeseek', [api, time], true);
                            if (!ev.defaultPrevented) {
                                engine.seek(time);
                                if (isFunction(callback)) api.one("seek", callback);
                            } else {
                                api.seeking = false;
                                common.toggleClass(root, 'is-seeking', api.seeking); // remove loading indicator
                            }
                        }
                        return api;
                    },

                    /*
            seekTo(1) -> 10%
            seekTo(2) -> 20%
            seekTo(3) -> 30%
            ...
            seekTo()  -> last position
         */
                    seekTo: function (position, fn) {
                        var time = position === undefined ? lastSeekPosition : api.video.duration * 0.1 * position;
                        return api.seek(time, fn);
                    },

                    mute: function (flag, skipStore) {
                        if (flag === undefined) flag = !api.muted;
                        if (!skipStore) {
                            storage.muted = api.muted = flag;
                            storage.volume = !isNaN(storage.volume) ? storage.volume : conf.volume; // make sure storage has volume
                        }
                        api.volume(flag ? 0 : storage.volume, true);
                        api.trigger("mute", [api, flag]);
                        return api;
                    },

                    volume: function (level, skipStore) {
                        if (api.ready) {
                            level = Math.min(Math.max(level, 0), 1);
                            if (!skipStore) storage.volume = level;
                            engine.volume(level);
                        }

                        return api;
                    },

                    speed: function (val, callback) {

                        if (api.ready) {

                            // increase / decrease
                            if (typeof val == "boolean") {
                                val = conf.speeds[conf.speeds.indexOf(api.currentSpeed) + (val ? 1 : -1)] || api.currentSpeed;
                            }

                            engine.speed(val);
                            if (callback) root.one("speed", callback);
                        }

                        return api;
                    },


                    stop: function () {
                        if (api.ready) {
                            api.pause();
                            api.seek(0, function () {
                                api.trigger("stop", [api]);
                            });
                        }
                        return api;
                    },

                    unload: function () {
                        if (!rootClasses.contains("is-embedding")) {

                            if (conf.splash) {
                                api.trigger("unload", [api]);
                                if (engine) {
                                    engine.unload();
                                    api.engine = engine = 0;
                                }
                            } else {
                                api.stop();
                            }
                        }
                        return api;
                    },

                    shutdown: function () {
                        api.unload();
                        api.trigger('shutdown', [api]);
                        bean.off(root);
                        delete instances[root.getAttribute('data-flowplayer-instance-id')];
                        root.removeAttribute('data-flowplayer-instance-id');
                    },

                    disable: function (flag) {
                        if (flag === undefined) flag = !api.disabled;

                        if (flag != api.disabled) {
                            api.disabled = flag;
                            api.trigger("disable", flag);
                        }
                        return api;
                    }

                };

                api.conf = extend(api.conf, conf);

                /* event binding / unbinding */
                events(api);

                var selectEngine = function (clip) {
                    var engine;
                    var engines = flowplayer.engines;
                    if (conf.engine) {
                        var eng = engines.filter(function (e) {
                            return e.engineName === conf.engine;
                        })[0];
                        if (eng && clip.sources.some(function (source) {
                                if (source.engine && source.engine !== eng.engineName) return false;
                                return eng.canPlay(source.type, api.conf);
                            })) return eng;
                    }
                    if (conf.enginePreference) engines = flowplayer.engines.filter(function (one) {
                        return conf.enginePreference.indexOf(one.engineName) > -1;
                    }).sort(function (a, b) {
                        return conf.enginePreference.indexOf(a.engineName) - conf.enginePreference.indexOf(b.engineName);
                    });
                    clip.sources.some(function (source) {
                        var eng = engines.filter(function (engine) {
                            if (source.engine && source.engine !== engine.engineName) return false;
                            return engine.canPlay(source.type, api.conf);
                        }).shift();
                        if (eng) engine = eng;
                        return !!eng;
                    });
                    return engine;
                };

                /*** Behaviour ***/
                if (!root.getAttribute('data-flowplayer-instance-id')) { // Only bind once
                    root.setAttribute('data-flowplayer-instance-id', playerCount++);


                    api.on('boot', function () {

                        // splash
                        if (conf.splash || rootClasses.contains("is-splash") || !flowplayer.support.firstframe) {
                            api.forcedSplash = !conf.splash && !rootClasses.contains("is-splash");
                            api.splash = conf.autoplay = true;
                            if (!conf.splash) conf.splash = true;
                            rootClasses.add("is-splash");
                        }

                        if (conf.splash) common.find('video', root).forEach(common.removeNode);

                        if (conf.live || rootClasses.contains('is-live')) {
                            api.live = conf.live = true;
                            rootClasses.add('is-live');
                        }

                        // extensions
                        extensions.forEach(function (e) {
                            e(api, root);
                        });

                        // instances
                        instances.push(api);

                        // start
                        if (conf.splash) api.unload(); else api.load();

                        // disabled
                        if (conf.disabled) api.disable();

                        // initial callback
                        api.one("ready", callback);


                    }).on("load", function (e, api, video) {

                        // unload others
                        if (conf.splash) {
                            common.find('.flowplayer.is-ready,.flowplayer.is-loading').forEach(function (el) {
                                var playerId = el.getAttribute('data-flowplayer-instance-id');
                                if (playerId === root.getAttribute('data-flowplayer-instance-id')) return;
                                var a = instances[Number(playerId)];
                                if (a && a.conf.splash) a.unload();
                            });

                        }

                        // loading
                        rootClasses.add("is-loading");
                        api.loading = true;

                        if (typeof video.live !== 'undefined') {
                            common.toggleClass(root, 'is-live', video.live);
                            api.live = video.live;
                        }


                    }).on("ready", function (e, api, video) {
                        video.time = 0;
                        api.video = video;

                        rootClasses.remove("is-loading");
                        api.loading = false;

                        // saved state
                        if (api.muted) api.mute(true, true);
                        else api.volume(api.volumeLevel);

                        // see https://github.com/flowplayer/flowplayer/issues/479

                        var hlsFix = api.conf.hlsFix && /mpegurl/i.exec(video.type);
                        common.toggleClass(root, 'hls-fix', !!hlsFix);

                    }).on("unload", function (e) {
                        rootClasses.remove("is-loading");
                        api.loading = false;


                    }).on("ready unload", function (e) {
                        var is_ready = e.type == "ready";
                        common.toggleClass(root, 'is-splash', !is_ready);
                        common.toggleClass(root, 'is-ready', is_ready);
                        api.ready = is_ready;
                        api.splash = !is_ready;


                    }).on("progress", function (e, api, time) {
                        api.video.time = time;


                    }).on("speed", function (e, api, val) {
                        api.currentSpeed = val;

                    }).on("volume", function (e, api, level) {
                        api.volumeLevel = Math.round(level * 100) / 100;
                        if (!api.muted) storage.volume = level;
                        else if (level) api.mute(false);


                    }).on("beforeseek seek", function (e) {
                        api.seeking = e.type == "beforeseek";
                        common.toggleClass(root, 'is-seeking', api.seeking);

                    }).on("ready pause resume unload finish stop", function (e, _api, video) {

                        // PAUSED: pause / finish
                        api.paused = /pause|finish|unload|stop/.test(e.type);
                        api.paused = api.paused || e.type === 'ready' && !conf.autoplay && !api.playing;

                        // the opposite
                        api.playing = !api.paused;

                        // CSS classes
                        common.toggleClass(root, 'is-paused', api.paused);
                        common.toggleClass(root, 'is-playing', api.playing);

                        // sanity check
                        if (!api.load.ed) api.pause();

                    }).on("finish", function (e) {
                        api.finished = true;

                    }).on("error", function () {
                    });
                }

                // boot
                api.trigger('boot', [api, root]);
                return api;
            }

        }, {"./common": 1, "./ext/events": 8, "./ext/resolve": 13, "bean": 20, "class-list": 22, "extend-object": 26, "is-function": 27}],
        19: [function (_dereq_, module, exports) {
//Flowplayer with extensions

            _dereq_('es5-shim');

            var flowplayer = module.exports = _dereq_('./flowplayer');
//

//Support needed before engines
            _dereq_('./ext/support');

//Engines
            _dereq_('./engine/embed');
            _dereq_('./engine/html5');
            _dereq_('./engine/flash');

//Extensions
//require('./ext/slider'); //TODO enable
            _dereq_('./ext/ui');
            _dereq_('./ext/keyboard');
            _dereq_('./ext/playlist');
            _dereq_('./ext/cuepoint');
            _dereq_('./ext/subtitle');
            _dereq_('./ext/analytics');
            _dereq_('./ext/embed');
//Have to add fullscreen last
            _dereq_('./ext/fullscreen');

            _dereq_('./ext/mobile');
            flowplayer(function (e, o) {
                function a(e) {
                    var o = document.createElement("a");
                    return o.href = e, t.hostname(o.hostname)
                }

                var n = function (e, o) {
                        var a = e.className.split(" ");
                        -1 === a.indexOf(o) && (e.className += " " + o)
                    }, r = function (e) {
                        return "none" !== window.getComputedStyle(e).display
                    }, l = e.conf, t = flowplayer.common, i = t.createElement, d = l.swf.indexOf("flowplayer.org") && l.e && o.getAttribute("data-origin"), p = d ? a(d) : t.hostname(),
                    s = (document, l.key);
                "file:" == location.protocol && (p = "localhost"), e.load.ed = 1, l.hostname = p, l.origin = d || location.href, d && n(o, "is-embedded"), "string" == typeof s && (s = s.split(/,\s*/));
                var f = function (e, a) {
                    var n = i("a", {href: a, className: "fp-brand"});
                    n.innerHTML = e, t.find(".fp-controls", o)[0].appendChild(n)
                };
                if (s && "function" == typeof key_check && key_check(s, p)) {
                    if (l.logo) {
                        var c = t.find(".fp-player", o)[0], h = i("a", {className: "fp-logo"});
                        d && (h.href = d), l.embed && l.embed.popup && (h.target = "_blank");
                        var y = i("img", {src: l.logo});
                        h.appendChild(y), (c || o).appendChild(h)
                    }
                    l.brand && d || l.brand && l.brand.showOnOrigin ? f(l.brand.text || l.brand, d || location.href) : t.addClass(o, "no-brand")
                } else {
                    f("flowplayer", "http://flowplayer.org");
                    var h = i("a", {href: "http://flowplayer.org"});
                    o.appendChild(h);
                    var u = i("div", {className: "fp-context-menu"}, '<ul><li class="copyright">&copy; 2015</li><li><a href="http://flowplayer.org">About Flowplayer</a></li><li><a href="http://flowplayer.org/license">GPL based license</a></li></ul>'),
                        g = window.location.href.indexOf("localhost"), c = t.find(".fp-player", o)[0];
                    7 !== g && (c || o).appendChild(u), e.on("pause resume finish unload ready", function (e, a) {
                        t.removeClass(o, "no-brand");
                        var n = -1;
                        if (a.video.src) for (var l = [["org", "flowplayer", "drive"], ["org", "flowplayer", "my"], ["org", "flowplayer", "cdn"]], i = 0; i < l.length && (n = a.video.src.indexOf("://" + l[i].reverse().join(".")), -1 === n); i++) ;
                        if ((4 === n || 5 === n) && t.addClass(o, "no-brand"), /pause|resume/.test(e.type) && "flash" != a.engine.engineName && 4 != n && 5 != n) {
                            var d = {
                                display: "block",
                                position: "absolute",
                                left: "16px",
                                bottom: "46px",
                                zIndex: 99999,
                                width: "100px",
                                height: "20px",
                                backgroundImage: "url(" + [".png", "logo", "/", ".net", ".cloudfront", "d32wqyuo10o653", "//"].reverse().join("") + ")"
                            };
                            for (var p in d) d.hasOwnProperty(p) && (h.style[p] = d[p]);
                            a.load.ed = r(h) && (7 === g || u.parentNode == o || u.parentNode == c) && !t.hasClass(o, "no-brand"), a.load.ed || a.pause()
                        } else h.style.display = "none"
                    })
                }
            });


        }, {
            "./engine/embed": 2,
            "./engine/flash": 3,
            "./engine/html5": 4,
            "./ext/analytics": 5,
            "./ext/cuepoint": 6,
            "./ext/embed": 7,
            "./ext/fullscreen": 9,
            "./ext/keyboard": 10,
            "./ext/mobile": 11,
            "./ext/playlist": 12,
            "./ext/subtitle": 15,
            "./ext/support": 16,
            "./ext/ui": 17,
            "./flowplayer": 18,
            "es5-shim": 25
        }],
        20: [function (_dereq_, module, exports) {
            /*!
  * Bean - copyright (c) Jacob Thornton 2011-2012
  * https://github.com/fat/bean
  * MIT license
  */
            (function (name, context, definition) {
                if (typeof module != 'undefined' && module.exports) module.exports = definition()
                else if (typeof define == 'function' && define.amd) define(definition)
                else context[name] = definition()
            })('bean', this, function (name, context) {
                name = name || 'bean'
                context = context || this

                var win = window
                    , old = context[name]
                    , namespaceRegex = /[^\.]*(?=\..*)\.|.*/
                    , nameRegex = /\..*/
                    , addEvent = 'addEventListener'
                    , removeEvent = 'removeEventListener'
                    , doc = document || {}
                    , root = doc.documentElement || {}
                    , W3C_MODEL = root[addEvent]
                    , eventSupport = W3C_MODEL ? addEvent : 'attachEvent'
                    , ONE = {} // singleton for quick matching making add() do one()

                    , slice = Array.prototype.slice
                    , str2arr = function (s, d) {
                        return s.split(d || ' ')
                    }
                    , isString = function (o) {
                        return typeof o == 'string'
                    }
                    , isFunction = function (o) {
                        return typeof o == 'function'
                    }

                    // events that we consider to be 'native', anything not in this list will
                    // be treated as a custom event
                    , standardNativeEvents =
                    'click dblclick mouseup mousedown contextmenu ' + // mouse buttons
                    'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel
                    'mouseover mouseout mousemove selectstart selectend ' + // mouse movement
                    'keydown keypress keyup ' + // keyboard
                    'orientationchange ' + // mobile
                    'focus blur change reset select submit ' + // form elements
                    'load unload beforeunload resize move DOMContentLoaded ' + // window
                    'readystatechange message ' + // window
                    'error abort scroll '                                              // misc
                    // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
                    // that doesn't actually exist, so make sure we only do these on newer browsers
                    , w3cNativeEvents =
                    'show ' + // mouse buttons
                    'input invalid ' + // form elements
                    'touchstart touchmove touchend touchcancel ' + // touch
                    'gesturestart gesturechange gestureend ' + // gesture
                    'textinput ' + // TextEvent
                    'readystatechange pageshow pagehide popstate ' + // window
                    'hashchange offline online ' + // window
                    'afterprint beforeprint ' + // printing
                    'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd
                    'loadstart progress suspend emptied stalled loadmetadata ' + // media
                    'loadeddata canplay canplaythrough playing waiting seeking ' + // media
                    'seeked ended durationchange timeupdate play pause ratechange ' + // media
                    'volumechange cuechange ' + // media
                    'checking noupdate downloading cached updateready obsolete '       // appcache

                    // convert to a hash for quick lookups
                    , nativeEvents = (function (hash, events, i) {
                        for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1)
                        return hash
                    }({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : ''))))

                    // custom events are events that we *fake*, they are not provided natively but
                    // we can use native events to generate them
                    , customEvents = (function () {
                        var isAncestor = 'compareDocumentPosition' in root
                            ? function (element, container) {
                                return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16
                            }
                            : 'contains' in root
                                ? function (element, container) {
                                    container = container.nodeType === 9 || container === window ? root : container
                                    return container !== element && container.contains(element)
                                }
                                : function (element, container) {
                                    while (element = element.parentNode) if (element === container) return 1
                                    return 0
                                }
                            , check = function (event) {
                            var related = event.relatedTarget
                            return !related
                                ? related == null
                                : (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString())
                                    && !isAncestor(related, this))
                        }

                        return {
                            mouseenter: {base: 'mouseover', condition: check}
                            , mouseleave: {base: 'mouseout', condition: check}
                            , mousewheel: {base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel'}
                        }
                    }())

                    // we provide a consistent Event object across browsers by taking the actual DOM
                    // event object and generating a new one from its properties.
                    , Event = (function () {
                        // a whitelist of properties (for different event types) tells us what to check for and copy
                        var commonProps = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' +
                            'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey ' +
                            'srcElement target timeStamp type view which propertyName')
                            , mouseProps = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer ' +
                            'fromElement offsetX offsetY pageX pageY screenX screenY toElement'))
                            , mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' +
                            'axis')) // 'axis' is FF specific
                            , keyProps = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier ' +
                            'keyLocation location'))
                            , textProps = commonProps.concat(str2arr('data'))
                            , touchProps = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation'))
                            , messageProps = commonProps.concat(str2arr('data origin source'))
                            , stateProps = commonProps.concat(str2arr('state'))
                            , overOutRegex = /over|out/
                            // some event types need special handling and some need special properties, do that all here
                            , typeFixers = [
                                { // key events
                                    reg: /key/i
                                    , fix: function (event, newEvent) {
                                    newEvent.keyCode = event.keyCode || event.which
                                    return keyProps
                                }
                                }
                                , { // mouse events
                                    reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i
                                    , fix: function (event, newEvent, type) {
                                        newEvent.rightClick = event.which === 3 || event.button === 2
                                        newEvent.pos = {x: 0, y: 0}
                                        if (event.pageX || event.pageY) {
                                            newEvent.clientX = event.pageX
                                            newEvent.clientY = event.pageY
                                        } else if (event.clientX || event.clientY) {
                                            newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
                                            newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
                                        }
                                        if (overOutRegex.test(type)) {
                                            newEvent.relatedTarget = event.relatedTarget
                                                || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']
                                        }
                                        return mouseProps
                                    }
                                }
                                , { // mouse wheel events
                                    reg: /mouse.*(wheel|scroll)/i
                                    , fix: function () {
                                        return mouseWheelProps
                                    }
                                }
                                , { // TextEvent
                                    reg: /^text/i
                                    , fix: function () {
                                        return textProps
                                    }
                                }
                                , { // touch and gesture events
                                    reg: /^touch|^gesture/i
                                    , fix: function () {
                                        return touchProps
                                    }
                                }
                                , { // message events
                                    reg: /^message$/i
                                    , fix: function () {
                                        return messageProps
                                    }
                                }
                                , { // popstate events
                                    reg: /^popstate$/i
                                    , fix: function () {
                                        return stateProps
                                    }
                                }
                                , { // everything else
                                    reg: /.*/
                                    , fix: function () {
                                        return commonProps
                                    }
                                }
                            ]
                            , typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism

                            , Event = function (event, element, isNative) {
                                if (!arguments.length) return
                                event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event
                                this.originalEvent = event
                                this.isNative = isNative
                                this.isBean = true

                                if (!event) return

                                var type = event.type
                                    , target = event.target || event.srcElement
                                    , i, l, p, props, fixer

                                this.target = target && target.nodeType === 3 ? target.parentNode : target

                                if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless
                                    fixer = typeFixerMap[type]
                                    if (!fixer) { // haven't encountered this event type before, map a fixer function for it
                                        for (i = 0, l = typeFixers.length; i < l; i++) {
                                            if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .*
                                                typeFixerMap[type] = fixer = typeFixers[i].fix
                                                break
                                            }
                                        }
                                    }

                                    props = fixer(event, this, type)
                                    for (i = props.length; i--;) {
                                        if (!((p = props[i]) in this) && p in event) this[p] = event[p]
                                    }
                                }
                            }

                        // preventDefault() and stopPropagation() are a consistent interface to those functions
                        // on the DOM, stop() is an alias for both of them together
                        Event.prototype.preventDefault = function () {
                            if (this.originalEvent.preventDefault) this.originalEvent.preventDefault()
                            else this.originalEvent.returnValue = false
                        }
                        Event.prototype.stopPropagation = function () {
                            if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation()
                            else this.originalEvent.cancelBubble = true
                        }
                        Event.prototype.stop = function () {
                            this.preventDefault()
                            this.stopPropagation()
                            this.stopped = true
                        }
                        // stopImmediatePropagation() has to be handled internally because we manage the event list for
                        // each element
                        // note that originalElement may be a Bean#Event object in some situations
                        Event.prototype.stopImmediatePropagation = function () {
                            if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation()
                            this.isImmediatePropagationStopped = function () {
                                return true
                            }
                        }
                        Event.prototype.isImmediatePropagationStopped = function () {
                            return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped()
                        }
                        Event.prototype.clone = function (currentTarget) {
                            //TODO: this is ripe for optimisation, new events are *expensive*
                            // improving this will speed up delegated events
                            var ne = new Event(this, this.element, this.isNative)
                            ne.currentTarget = currentTarget
                            return ne
                        }

                        return Event
                    }())

                    // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
                    , targetElement = function (element, isNative) {
                        return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
                    }

                    /**
                     * Bean maintains an internal registry for event listeners. We don't touch elements, objects
                     * or functions to identify them, instead we store everything in the registry.
                     * Each event listener has a RegEntry object, we have one 'registry' for the whole instance.
                     */
                    , RegEntry = (function () {
                        // each handler is wrapped so we can handle delegation and custom events
                        var wrappedHandler = function (element, fn, condition, args) {
                            var call = function (event, eargs) {
                                return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs)
                            }
                                , findTarget = function (event, eventElement) {
                                return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement
                            }
                                , handler = condition
                                ? function (event) {
                                    var target = findTarget(event, this) // deleated event
                                    if (condition.apply(target, arguments)) {
                                        if (event) event.currentTarget = target
                                        return call(event, arguments)
                                    }
                                }
                                : function (event) {
                                    if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix
                                    return call(event, arguments)
                                }
                            handler.__beanDel = fn.__beanDel
                            return handler
                        }

                            , RegEntry = function (element, type, handler, original, namespaces, args, root) {
                            var customType = customEvents[type]
                                , isNative

                            if (type == 'unload') {
                                // self clean-up
                                handler = once(removeListener, element, type, handler, original)
                            }

                            if (customType) {
                                if (customType.condition) {
                                    handler = wrappedHandler(element, handler, customType.condition, args)
                                }
                                type = customType.base || type
                            }

                            this.isNative = isNative = nativeEvents[type] && !!element[eventSupport]
                            this.customType = !W3C_MODEL && !isNative && type
                            this.element = element
                            this.type = type
                            this.original = original
                            this.namespaces = namespaces
                            this.eventType = W3C_MODEL || isNative ? type : 'propertychange'
                            this.target = targetElement(element, isNative)
                            this[eventSupport] = !!this.target[eventSupport]
                            this.root = root
                            this.handler = wrappedHandler(element, handler, null, args)
                        }

                        // given a list of namespaces, is our entry in any of them?
                        RegEntry.prototype.inNamespaces = function (checkNamespaces) {
                            var i, j, c = 0
                            if (!checkNamespaces) return true
                            if (!this.namespaces) return false
                            for (i = checkNamespaces.length; i--;) {
                                for (j = this.namespaces.length; j--;) {
                                    if (checkNamespaces[i] == this.namespaces[j]) c++
                                }
                            }
                            return checkNamespaces.length === c
                        }

                        // match by element, original fn (opt), handler fn (opt)
                        RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) {
                            return this.element === checkElement &&
                                (!checkOriginal || this.original === checkOriginal) &&
                                (!checkHandler || this.handler === checkHandler)
                        }

                        return RegEntry
                    }())

                    , registry = (function () {
                        // our map stores arrays by event type, just because it's better than storing
                        // everything in a single array.
                        // uses '$' as a prefix for the keys for safety and 'r' as a special prefix for
                        // rootListeners so we can look them up fast
                        var map = {}

                            // generic functional search of our registry for matching listeners,
                            // `fn` returns false to break out of the loop
                            , forAll = function (element, type, original, handler, root, fn) {
                                var pfx = root ? 'r' : '$'
                                if (!type || type == '*') {
                                    // search the whole registry
                                    for (var t in map) {
                                        if (t.charAt(0) == pfx) {
                                            forAll(element, t.substr(1), original, handler, root, fn)
                                        }
                                    }
                                } else {
                                    var i = 0, l, list = map[pfx + type], all = element == '*'
                                    if (!list) return
                                    for (l = list.length; i < l; i++) {
                                        if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return
                                    }
                                }
                            }

                            , has = function (element, type, original, root) {
                                // we're not using forAll here simply because it's a bit slower and this
                                // needs to be fast
                                var i, list = map[(root ? 'r' : '$') + type]
                                if (list) {
                                    for (i = list.length; i--;) {
                                        if (!list[i].root && list[i].matches(element, original, null)) return true
                                    }
                                }
                                return false
                            }

                            , get = function (element, type, original, root) {
                                var entries = []
                                forAll(element, type, original, null, root, function (entry) {
                                    return entries.push(entry)
                                })
                                return entries
                            }

                            , put = function (entry) {
                                var has = !entry.root && !this.has(entry.element, entry.type, null, false)
                                    , key = (entry.root ? 'r' : '$') + entry.type
                                ;(map[key] || (map[key] = [])).push(entry)
                                return has
                            }

                            , del = function (entry) {
                                forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) {
                                    list.splice(i, 1)
                                    entry.removed = true
                                    if (list.length === 0) delete map[(entry.root ? 'r' : '$') + entry.type]
                                    return false
                                })
                            }

                            // dump all entries, used for onunload
                            , entries = function () {
                                var t, entries = []
                                for (t in map) {
                                    if (t.charAt(0) == '$') entries = entries.concat(map[t])
                                }
                                return entries
                            }

                        return {has: has, get: get, put: put, del: del, entries: entries}
                    }())

                    // we need a selector engine for delegated events, use querySelectorAll if it exists
                    // but for older browsers we need Qwery, Sizzle or similar
                    , selectorEngine
                    , setSelectorEngine = function (e) {
                        if (!arguments.length) {
                            selectorEngine = doc.querySelectorAll
                                ? function (s, r) {
                                    return r.querySelectorAll(s)
                                }
                                : function () {
                                    throw new Error('Bean: No selector engine installed') // eeek
                                }
                        } else {
                            selectorEngine = e
                        }
                    }

                    // we attach this listener to each DOM event that we need to listen to, only once
                    // per event type per DOM element
                    , rootListener = function (event, type) {
                        if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return

                        var listeners = registry.get(this, type || event.type, null, false)
                            , l = listeners.length
                            , i = 0

                        event = new Event(event, this, true)
                        if (type) event.type = type

                        // iterate through all handlers registered for this type, calling them unless they have
                        // been removed by a previous handler or stopImmediatePropagation() has been called
                        for (; i < l && !event.isImmediatePropagationStopped(); i++) {
                            if (!listeners[i].removed) listeners[i].handler.call(this, event)
                        }
                    }

                    // add and remove listeners to DOM elements
                    , listener = W3C_MODEL
                    ? function (element, type, add) {
                        // new browsers
                        element[add ? addEvent : removeEvent](type, rootListener, false)
                    }
                    : function (element, type, add, custom) {
                        // IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events
                        // to simulate event bubbling etc.
                        var entry
                        if (add) {
                            registry.put(entry = new RegEntry(
                                element
                                , custom || type
                                , function (event) { // handler
                                    rootListener.call(element, event, custom)
                                }
                                , rootListener
                                , null
                                , null
                                , true // is root
                            ))
                            if (custom && element['_on' + custom] == null) element['_on' + custom] = 0
                            entry.target.attachEvent('on' + entry.eventType, entry.handler)
                        } else {
                            entry = registry.get(element, custom || type, rootListener, true)[0]
                            if (entry) {
                                entry.target.detachEvent('on' + entry.eventType, entry.handler)
                                registry.del(entry)
                            }
                        }
                    }

                    , once = function (rm, element, type, fn, originalFn) {
                        // wrap the handler in a handler that does a remove as well
                        return function () {
                            fn.apply(this, arguments)
                            rm(element, type, originalFn)
                        }
                    }

                    , removeListener = function (element, orgType, handler, namespaces) {
                        var type = orgType && orgType.replace(nameRegex, '')
                            , handlers = registry.get(element, type, null, false)
                            , removed = {}
                            , i, l

                        for (i = 0, l = handlers.length; i < l; i++) {
                            if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) {
                                // TODO: this is problematic, we have a registry.get() and registry.del() that
                                // both do registry searches so we waste cycles doing this. Needs to be rolled into
                                // a single registry.forAll(fn) that removes while finding, but the catch is that
                                // we'll be splicing the arrays that we're iterating over. Needs extra tests to
                                // make sure we don't screw it up. @rvagg
                                registry.del(handlers[i])
                                if (!removed[handlers[i].eventType] && handlers[i][eventSupport])
                                    removed[handlers[i].eventType] = {t: handlers[i].eventType, c: handlers[i].type}
                            }
                        }
                        // check each type/element for removed listeners and remove the rootListener where it's no longer needed
                        for (i in removed) {
                            if (!registry.has(element, removed[i].t, null, false)) {
                                // last listener of this type, remove the rootListener
                                listener(element, removed[i].t, false, removed[i].c)
                            }
                        }
                    }

                    // set up a delegate helper using the given selector, wrap the handler function
                    , delegate = function (selector, fn) {
                        //TODO: findTarget (therefore $) is called twice, once for match and once for
                        // setting e.currentTarget, fix this so it's only needed once
                        var findTarget = function (target, root) {
                            var i, array = isString(selector) ? selectorEngine(selector, root) : selector
                            for (; target && target !== root; target = target.parentNode) {
                                for (i = array.length; i--;) {
                                    if (array[i] === target) return target
                                }
                            }
                        }
                            , handler = function (e) {
                            var match = findTarget(e.target, this)
                            if (match) fn.apply(match, arguments)
                        }

                        // __beanDel isn't pleasant but it's a private function, not exposed outside of Bean
                        handler.__beanDel = {
                            ft: findTarget // attach it here for customEvents to use too
                            , selector: selector
                        }
                        return handler
                    }

                    , fireListener = W3C_MODEL ? function (isNative, type, element) {
                        // modern browsers, do a proper dispatchEvent()
                        var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
                        evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
                        element.dispatchEvent(evt)
                    } : function (isNative, type, element) {
                        // old browser use onpropertychange, just increment a custom property to trigger the event
                        element = targetElement(element, isNative)
                        isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
                    }

                    /**
                     * Public API: off(), on(), add(), (remove()), one(), fire(), clone()
                     */

                    /**
                     * off(element[, eventType(s)[, handler ]])
                     */
                    , off = function (element, typeSpec, fn) {
                        var isTypeStr = isString(typeSpec)
                            , k, type, namespaces, i

                        if (isTypeStr && typeSpec.indexOf(' ') > 0) {
                            // off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3')
                            typeSpec = str2arr(typeSpec)
                            for (i = typeSpec.length; i--;)
                                off(element, typeSpec[i], fn)
                            return element
                        }

                        type = isTypeStr && typeSpec.replace(nameRegex, '')
                        if (type && customEvents[type]) type = customEvents[type].base

                        if (!typeSpec || isTypeStr) {
                            // off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3)
                            if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.')
                            removeListener(element, type, fn, namespaces)
                        } else if (isFunction(typeSpec)) {
                            // off(el, fn)
                            removeListener(element, null, typeSpec)
                        } else {
                            // off(el, { t1: fn1, t2, fn2 })
                            for (k in typeSpec) {
                                if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k])
                            }
                        }

                        return element
                    }

                    /**
                     * on(element, eventType(s)[, selector], handler[, args ])
                     */
                    , on = function (element, events, selector, fn) {
                        var originalFn, type, types, i, args, entry, first

                        //TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps?
                        if (selector === undefined && typeof events == 'object') {
                            //TODO: this can't handle delegated events
                            for (type in events) {
                                if (events.hasOwnProperty(type)) {
                                    on.call(this, element, type, events[type])
                                }
                            }
                            return
                        }

                        if (!isFunction(selector)) {
                            // delegated event
                            originalFn = fn
                            args = slice.call(arguments, 4)
                            fn = delegate(selector, originalFn, selectorEngine)
                        } else {
                            args = slice.call(arguments, 3)
                            fn = originalFn = selector
                        }

                        types = str2arr(events)

                        // special case for one(), wrap in a self-removing handler
                        if (this === ONE) {
                            fn = once(off, element, events, fn, originalFn)
                        }

                        for (i = types.length; i--;) {
                            // add new handler to the registry and check if it's the first for this element/type
                            first = registry.put(entry = new RegEntry(
                                element
                                , types[i].replace(nameRegex, '') // event type
                                , fn
                                , originalFn
                                , str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces
                                , args
                                , false // not root
                            ))
                            if (entry[eventSupport] && first) {
                                // first event of this type on this element, add root listener
                                listener(element, entry.eventType, true, entry.customType)
                            }
                        }

                        return element
                    }

                    /**
                     * add(element[, selector], eventType(s), handler[, args ])
                     *
                     * Deprecated: kept (for now) for backward-compatibility
                     */
                    , add = function (element, events, fn, delfn) {
                        return on.apply(
                            null
                            , !isString(fn)
                                ? slice.call(arguments)
                                : [element, fn, events, delfn].concat(arguments.length > 3 ? slice.call(arguments, 5) : [])
                        )
                    }

                    /**
                     * one(element, eventType(s)[, selector], handler[, args ])
                     */
                    , one = function () {
                        return on.apply(ONE, arguments)
                    }

                    /**
                     * fire(element, eventType(s)[, args ])
                     *
                     * The optional 'args' argument must be an array, if no 'args' argument is provided
                     * then we can use the browser's DOM event system, otherwise we trigger handlers manually
                     */
                    , fire = function (element, type, args) {
                        var types = str2arr(type)
                            , i, j, l, names, handlers

                        for (i = types.length; i--;) {
                            type = types[i].replace(nameRegex, '')
                            if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.')
                            if (!names && !args && element[eventSupport]) {
                                fireListener(nativeEvents[type], type, element)
                            } else {
                                // non-native event, either because of a namespace, arguments or a non DOM element
                                // iterate over all listeners and manually 'fire'
                                handlers = registry.get(element, type, null, false)
                                args = [false].concat(args)
                                for (j = 0, l = handlers.length; j < l; j++) {
                                    if (handlers[j].inNamespaces(names)) {
                                        handlers[j].handler.apply(element, args)
                                    }
                                }
                            }
                        }
                        return element
                    }

                    /**
                     * clone(dstElement, srcElement[, eventType ])
                     *
                     * TODO: perhaps for consistency we should allow the same flexibility in type specifiers?
                     */
                    , clone = function (element, from, type) {
                        var handlers = registry.get(from, type, null, false)
                            , l = handlers.length
                            , i = 0
                            , args, beanDel

                        for (; i < l; i++) {
                            if (handlers[i].original) {
                                args = [element, handlers[i].type]
                                if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector)
                                args.push(handlers[i].original)
                                on.apply(null, args)
                            }
                        }
                        return element
                    }

                    , bean = {
                        'on': on
                        , 'add': add
                        , 'one': one
                        , 'off': off
                        , 'remove': off
                        , 'clone': clone
                        , 'fire': fire
                        , 'Event': Event
                        , 'setSelectorEngine': setSelectorEngine
                        , 'noConflict': function () {
                            context[name] = old
                            return this
                        }
                    }

                // for IE, clean up on unload to avoid leaks
                if (win.attachEvent) {
                    var cleanup = function () {
                        var i, entries = registry.entries()
                        for (i in entries) {
                            if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type)
                        }
                        win.detachEvent('onunload', cleanup)
                        win.CollectGarbage && win.CollectGarbage()
                    }
                    win.attachEvent('onunload', cleanup)
                }

                // initialize selector engine to internal default (qSA or throw Error)
                setSelectorEngine()

                return bean
            });

        }, {}],
        21: [function (_dereq_, module, exports) {
            (function (global) {
                /*! http://mths.be/punycode v1.2.4 by @mathias */
                ;(function (root) {

                    /** Detect free variables */
                    var freeExports = typeof exports == 'object' && exports;
                    var freeModule = typeof module == 'object' && module &&
                        module.exports == freeExports && module;
                    var freeGlobal = typeof global == 'object' && global;
                    if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
                        root = freeGlobal;
                    }

                    /**
                     * The `punycode` object.
                     * @name punycode
                     * @type Object
                     */
                    var punycode,

                        /** Highest positive signed 32-bit float value */
                        maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1

                        /** Bootstring parameters */
                        base = 36,
                        tMin = 1,
                        tMax = 26,
                        skew = 38,
                        damp = 700,
                        initialBias = 72,
                        initialN = 128, // 0x80
                        delimiter = '-', // '\x2D'

                        /** Regular expressions */
                        regexPunycode = /^xn--/,
                        regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
                        regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators

                        /** Error messages */
                        errors = {
                            'overflow': 'Overflow: input needs wider integers to process',
                            'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
                            'invalid-input': 'Invalid input'
                        },

                        /** Convenience shortcuts */
                        baseMinusTMin = base - tMin,
                        floor = Math.floor,
                        stringFromCharCode = String.fromCharCode,

                        /** Temporary variable */
                        key;

                    /*--------------------------------------------------------------------------*/

                    /**
                     * A generic error utility function.
                     * @private
                     * @param {String} type The error type.
                     * @returns {Error} Throws a `RangeError` with the applicable error message.
                     */
                    function error(type) {
                        throw RangeError(errors[type]);
                    }

                    /**
                     * A generic `Array#map` utility function.
                     * @private
                     * @param {Array} array The array to iterate over.
                     * @param {Function} callback The function that gets called for every array
                     * item.
                     * @returns {Array} A new array of values returned by the callback function.
                     */
                    function map(array, fn) {
                        var length = array.length;
                        while (length--) {
                            array[length] = fn(array[length]);
                        }
                        return array;
                    }

                    /**
                     * A simple `Array#map`-like wrapper to work with domain name strings.
                     * @private
                     * @param {String} domain The domain name.
                     * @param {Function} callback The function that gets called for every
                     * character.
                     * @returns {Array} A new string of characters returned by the callback
                     * function.
                     */
                    function mapDomain(string, fn) {
                        return map(string.split(regexSeparators), fn).join('.');
                    }

                    /**
                     * Creates an array containing the numeric code points of each Unicode
                     * character in the string. While JavaScript uses UCS-2 internally,
                     * this function will convert a pair of surrogate halves (each of which
                     * UCS-2 exposes as separate characters) into a single code point,
                     * matching UTF-16.
                     * @see `punycode.ucs2.encode`
                     * @see <http://mathiasbynens.be/notes/javascript-encoding>
                     * @memberOf punycode.ucs2
                     * @name decode
                     * @param {String} string The Unicode input string (UCS-2).
                     * @returns {Array} The new array of code points.
                     */
                    function ucs2decode(string) {
                        var output = [],
                            counter = 0,
                            length = string.length,
                            value,
                            extra;
                        while (counter < length) {
                            value = string.charCodeAt(counter++);
                            if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
                                // high surrogate, and there is a next character
                                extra = string.charCodeAt(counter++);
                                if ((extra & 0xFC00) == 0xDC00) { // low surrogate
                                    output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
                                } else {
                                    // unmatched surrogate; only append this code unit, in case the next
                                    // code unit is the high surrogate of a surrogate pair
                                    output.push(value);
                                    counter--;
                                }
                            } else {
                                output.push(value);
                            }
                        }
                        return output;
                    }

                    /**
                     * Creates a string based on an array of numeric code points.
                     * @see `punycode.ucs2.decode`
                     * @memberOf punycode.ucs2
                     * @name encode
                     * @param {Array} codePoints The array of numeric code points.
                     * @returns {String} The new Unicode string (UCS-2).
                     */
                    function ucs2encode(array) {
                        return map(array, function (value) {
                            var output = '';
                            if (value > 0xFFFF) {
                                value -= 0x10000;
                                output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
                                value = 0xDC00 | value & 0x3FF;
                            }
                            output += stringFromCharCode(value);
                            return output;
                        }).join('');
                    }

                    /**
                     * Converts a basic code point into a digit/integer.
                     * @see `digitToBasic()`
                     * @private
                     * @param {Number} codePoint The basic numeric code point value.
                     * @returns {Number} The numeric value of a basic code point (for use in
                     * representing integers) in the range `0` to `base - 1`, or `base` if
                     * the code point does not represent a value.
                     */
                    function basicToDigit(codePoint) {
                        if (codePoint - 48 < 10) {
                            return codePoint - 22;
                        }
                        if (codePoint - 65 < 26) {
                            return codePoint - 65;
                        }
                        if (codePoint - 97 < 26) {
                            return codePoint - 97;
                        }
                        return base;
                    }

                    /**
                     * Converts a digit/integer into a basic code point.
                     * @see `basicToDigit()`
                     * @private
                     * @param {Number} digit The numeric value of a basic code point.
                     * @returns {Number} The basic code point whose value (when used for
                     * representing integers) is `digit`, which needs to be in the range
                     * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
                     * used; else, the lowercase form is used. The behavior is undefined
                     * if `flag` is non-zero and `digit` has no uppercase form.
                     */
                    function digitToBasic(digit, flag) {
                        //  0..25 map to ASCII a..z or A..Z
                        // 26..35 map to ASCII 0..9
                        return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
                    }

                    /**
                     * Bias adaptation function as per section 3.4 of RFC 3492.
                     * http://tools.ietf.org/html/rfc3492#section-3.4
                     * @private
                     */
                    function adapt(delta, numPoints, firstTime) {
                        var k = 0;
                        delta = firstTime ? floor(delta / damp) : delta >> 1;
                        delta += floor(delta / numPoints);
                        for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
                            delta = floor(delta / baseMinusTMin);
                        }
                        return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
                    }

                    /**
                     * Converts a Punycode string of ASCII-only symbols to a string of Unicode
                     * symbols.
                     * @memberOf punycode
                     * @param {String} input The Punycode string of ASCII-only symbols.
                     * @returns {String} The resulting string of Unicode symbols.
                     */
                    function decode(input) {
                        // Don't use UCS-2
                        var output = [],
                            inputLength = input.length,
                            out,
                            i = 0,
                            n = initialN,
                            bias = initialBias,
                            basic,
                            j,
                            index,
                            oldi,
                            w,
                            k,
                            digit,
                            t,
                            /** Cached calculation results */
                            baseMinusT;

                        // Handle the basic code points: let `basic` be the number of input code
                        // points before the last delimiter, or `0` if there is none, then copy
                        // the first basic code points to the output.

                        basic = input.lastIndexOf(delimiter);
                        if (basic < 0) {
                            basic = 0;
                        }

                        for (j = 0; j < basic; ++j) {
                            // if it's not a basic code point
                            if (input.charCodeAt(j) >= 0x80) {
                                error('not-basic');
                            }
                            output.push(input.charCodeAt(j));
                        }

                        // Main decoding loop: start just after the last delimiter if any basic code
                        // points were copied; start at the beginning otherwise.

                        for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {

                            // `index` is the index of the next character to be consumed.
                            // Decode a generalized variable-length integer into `delta`,
                            // which gets added to `i`. The overflow checking is easier
                            // if we increase `i` as we go, then subtract off its starting
                            // value at the end to obtain `delta`.
                            for (oldi = i, w = 1, k = base; /* no condition */; k += base) {

                                if (index >= inputLength) {
                                    error('invalid-input');
                                }

                                digit = basicToDigit(input.charCodeAt(index++));

                                if (digit >= base || digit > floor((maxInt - i) / w)) {
                                    error('overflow');
                                }

                                i += digit * w;
                                t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);

                                if (digit < t) {
                                    break;
                                }

                                baseMinusT = base - t;
                                if (w > floor(maxInt / baseMinusT)) {
                                    error('overflow');
                                }

                                w *= baseMinusT;

                            }

                            out = output.length + 1;
                            bias = adapt(i - oldi, out, oldi == 0);

                            // `i` was supposed to wrap around from `out` to `0`,
                            // incrementing `n` each time, so we'll fix that now:
                            if (floor(i / out) > maxInt - n) {
                                error('overflow');
                            }

                            n += floor(i / out);
                            i %= out;

                            // Insert `n` at position `i` of the output
                            output.splice(i++, 0, n);

                        }

                        return ucs2encode(output);
                    }

                    /**
                     * Converts a string of Unicode symbols to a Punycode string of ASCII-only
                     * symbols.
                     * @memberOf punycode
                     * @param {String} input The string of Unicode symbols.
                     * @returns {String} The resulting Punycode string of ASCII-only symbols.
                     */
                    function encode(input) {
                        var n,
                            delta,
                            handledCPCount,
                            basicLength,
                            bias,
                            j,
                            m,
                            q,
                            k,
                            t,
                            currentValue,
                            output = [],
                            /** `inputLength` will hold the number of code points in `input`. */
                            inputLength,
                            /** Cached calculation results */
                            handledCPCountPlusOne,
                            baseMinusT,
                            qMinusT;

                        // Convert the input in UCS-2 to Unicode
                        input = ucs2decode(input);

                        // Cache the length
                        inputLength = input.length;

                        // Initialize the state
                        n = initialN;
                        delta = 0;
                        bias = initialBias;

                        // Handle the basic code points
                        for (j = 0; j < inputLength; ++j) {
                            currentValue = input[j];
                            if (currentValue < 0x80) {
                                output.push(stringFromCharCode(currentValue));
                            }
                        }

                        handledCPCount = basicLength = output.length;

                        // `handledCPCount` is the number of code points that have been handled;
                        // `basicLength` is the number of basic code points.

                        // Finish the basic string - if it is not empty - with a delimiter
                        if (basicLength) {
                            output.push(delimiter);
                        }

                        // Main encoding loop:
                        while (handledCPCount < inputLength) {

                            // All non-basic code points < n have been handled already. Find the next
                            // larger one:
                            for (m = maxInt, j = 0; j < inputLength; ++j) {
                                currentValue = input[j];
                                if (currentValue >= n && currentValue < m) {
                                    m = currentValue;
                                }
                            }

                            // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
                            // but guard against overflow
                            handledCPCountPlusOne = handledCPCount + 1;
                            if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
                                error('overflow');
                            }

                            delta += (m - n) * handledCPCountPlusOne;
                            n = m;

                            for (j = 0; j < inputLength; ++j) {
                                currentValue = input[j];

                                if (currentValue < n && ++delta > maxInt) {
                                    error('overflow');
                                }

                                if (currentValue == n) {
                                    // Represent delta as a generalized variable-length integer
                                    for (q = delta, k = base; /* no condition */; k += base) {
                                        t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
                                        if (q < t) {
                                            break;
                                        }
                                        qMinusT = q - t;
                                        baseMinusT = base - t;
                                        output.push(
                                            stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
                                        );
                                        q = floor(qMinusT / baseMinusT);
                                    }

                                    output.push(stringFromCharCode(digitToBasic(q, 0)));
                                    bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
                                    delta = 0;
                                    ++handledCPCount;
                                }
                            }

                            ++delta;
                            ++n;

                        }
                        return output.join('');
                    }

                    /**
                     * Converts a Punycode string representing a domain name to Unicode. Only the
                     * Punycoded parts of the domain name will be converted, i.e. it doesn't
                     * matter if you call it on a string that has already been converted to
                     * Unicode.
                     * @memberOf punycode
                     * @param {String} domain The Punycode domain name to convert to Unicode.
                     * @returns {String} The Unicode representation of the given Punycode
                     * string.
                     */
                    function toUnicode(domain) {
                        return mapDomain(domain, function (string) {
                            return regexPunycode.test(string)
                                ? decode(string.slice(4).toLowerCase())
                                : string;
                        });
                    }

                    /**
                     * Converts a Unicode string representing a domain name to Punycode. Only the
                     * non-ASCII parts of the domain name will be converted, i.e. it doesn't
                     * matter if you call it with a domain that's already in ASCII.
                     * @memberOf punycode
                     * @param {String} domain The domain name to convert, as a Unicode string.
                     * @returns {String} The Punycode representation of the given domain name.
                     */
                    function toASCII(domain) {
                        return mapDomain(domain, function (string) {
                            return regexNonASCII.test(string)
                                ? 'xn--' + encode(string)
                                : string;
                        });
                    }

                    /*--------------------------------------------------------------------------*/

                    /** Define the public API */
                    punycode = {
                        /**
                         * A string representing the current Punycode.js version number.
                         * @memberOf punycode
                         * @type String
                         */
                        'version': '1.2.4',
                        /**
                         * An object of methods to convert from JavaScript's internal character
                         * representation (UCS-2) to Unicode code points, and back.
                         * @see <http://mathiasbynens.be/notes/javascript-encoding>
                         * @memberOf punycode
                         * @type Object
                         */
                        'ucs2': {
                            'decode': ucs2decode,
                            'encode': ucs2encode
                        },
                        'decode': decode,
                        'encode': encode,
                        'toASCII': toASCII,
                        'toUnicode': toUnicode
                    };

                    /** Expose `punycode` */
                    // Some AMD build optimizers, like r.js, check for specific condition patterns
                    // like the following:
                    if (
                        typeof define == 'function' &&
                        typeof define.amd == 'object' &&
                        define.amd
                    ) {
                        define('punycode', function () {
                            return punycode;
                        });
                    } else if (freeExports && !freeExports.nodeType) {
                        if (freeModule) { // in Node.js or RingoJS v0.8.0+
                            freeModule.exports = punycode;
                        } else { // in Narwhal or RingoJS v0.7.0-
                            for (key in punycode) {
                                punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
                            }
                        }
                    } else { // in Rhino or a web browser
                        root.punycode = punycode;
                    }

                }(this));

            }).call(this, typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
        }, {}],
        22: [function (_dereq_, module, exports) {
// contains, add, remove, toggle
            var indexof = _dereq_('indexof')

            module.exports = ClassList

            function ClassList(elem) {
                var cl = elem.classList

                if (cl) {
                    return cl
                }

                var classList = {
                    add: add
                    , remove: remove
                    , contains: contains
                    , toggle: toggle
                    , toString: $toString
                    , length: 0
                    , item: item
                }

                return classList

                function add(token) {
                    var list = getTokens()
                    if (indexof(list, token) > -1) {
                        return
                    }
                    list.push(token)
                    setTokens(list)
                }

                function remove(token) {
                    var list = getTokens()
                        , index = indexof(list, token)

                    if (index === -1) {
                        return
                    }

                    list.splice(index, 1)
                    setTokens(list)
                }

                function contains(token) {
                    return indexof(getTokens(), token) > -1
                }

                function toggle(token) {
                    if (contains(token)) {
                        remove(token)
                        return false
                    } else {
                        add(token)
                        return true
                    }
                }

                function $toString() {
                    return elem.className
                }

                function item(index) {
                    var tokens = getTokens()
                    return tokens[index] || null
                }

                function getTokens() {
                    var className = elem.className

                    return filter(className.split(" "), isTruthy)
                }

                function setTokens(list) {
                    var length = list.length

                    elem.className = list.join(" ")
                    classList.length = length

                    for (var i = 0; i < list.length; i++) {
                        classList[i] = list[i]
                    }

                    delete list[length]
                }
            }

            function filter(arr, fn) {
                var ret = []
                for (var i = 0; i < arr.length; i++) {
                    if (fn(arr[i])) ret.push(arr[i])
                }
                return ret
            }

            function isTruthy(value) {
                return !!value
            }

        }, {"indexof": 23}],
        23: [function (_dereq_, module, exports) {

            var indexOf = [].indexOf;

            module.exports = function (arr, obj) {
                if (indexOf) return arr.indexOf(obj);
                for (var i = 0; i < arr.length; ++i) {
                    if (arr[i] === obj) return i;
                }
                return -1;
            };
        }, {}],
        24: [function (_dereq_, module, exports) {
// DEV: We don't use var but favor parameters since these play nicer with minification
            function computedStyle(el, prop, getComputedStyle, style) {
                getComputedStyle = window.getComputedStyle;
                style =
                    // If we have getComputedStyle
                    getComputedStyle ?
                        // Query it
                        // TODO: From CSS-Query notes, we might need (node, null) for FF
                        getComputedStyle(el) :

                        // Otherwise, we are in IE and use currentStyle
                        el.currentStyle;
                if (style) {
                    return style
                        [
                        // Switch to camelCase for CSSOM
                        // DEV: Grabbed from jQuery
                        // https://github.com/jquery/jquery/blob/1.9-stable/src/css.js#L191-L194
                        // https://github.com/jquery/jquery/blob/1.9-stable/src/core.js#L593-L597
                        prop.replace(/-(\w)/gi, function (word, letter) {
                            return letter.toUpperCase();
                        })
                        ];
                }
            }

            module.exports = computedStyle;

        }, {}],
        25: [function (_dereq_, module, exports) {
            /*!
 * https://github.com/es-shims/es5-shim
 * @license es5-shim Copyright 2009-2015 by contributors, MIT License
 * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
 */

// vim: ts=4 sts=4 sw=4 expandtab

// Add semicolon to prevent IIFE from being passed as argument to concatenated code.
            ;

// UMD (Universal Module Definition)
// see https://github.com/umdjs/umd/blob/master/templates/returnExports.js
            (function (root, factory) {
                'use strict';

                /* global define, exports, module */
                if (typeof define === 'function' && define.amd) {
                    // AMD. Register as an anonymous module.
                    define(factory);
                } else if (typeof exports === 'object') {
                    // Node. Does not work with strict CommonJS, but
                    // only CommonJS-like enviroments that support module.exports,
                    // like Node.
                    module.exports = factory();
                } else {
                    // Browser globals (root is window)
                    root.returnExports = factory();
                }
            }(this, function () {

                /**
                 * Brings an environment as close to ECMAScript 5 compliance
                 * as is possible with the facilities of erstwhile engines.
                 *
                 * Annotated ES5: http://es5.github.com/ (specific links below)
                 * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
                 * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
                 */

// Shortcut to an often accessed properties, in order to avoid multiple
// dereference that costs universally. This also holds a reference to known-good
// functions.
                var $Array = Array;
                var ArrayPrototype = $Array.prototype;
                var $Object = Object;
                var ObjectPrototype = $Object.prototype;
                var FunctionPrototype = Function.prototype;
                var $String = String;
                var StringPrototype = $String.prototype;
                var $Number = Number;
                var NumberPrototype = $Number.prototype;
                var array_slice = ArrayPrototype.slice;
                var array_splice = ArrayPrototype.splice;
                var array_push = ArrayPrototype.push;
                var array_unshift = ArrayPrototype.unshift;
                var array_concat = ArrayPrototype.concat;
                var call = FunctionPrototype.call;
                var apply = FunctionPrototype.apply;
                var max = Math.max;
                var min = Math.min;

// Having a toString local variable name breaks in Opera so use to_string.
                var to_string = ObjectPrototype.toString;

                var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
                var isCallable;
                /* inlined from https://npmjs.com/is-callable */
                var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) {
                    try {
                        fnToStr.call(value);
                        return true;
                    } catch (e) {
                        return false;
                    }
                }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]';
                isCallable = function isCallable(value) {
                    if (typeof value !== 'function') {
                        return false;
                    }
                    if (hasToStringTag) {
                        return tryFunctionObject(value);
                    }
                    var strClass = to_string.call(value);
                    return strClass === fnClass || strClass === genClass;
                };
                var isRegex;
                /* inlined from https://npmjs.com/is-regex */
                var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) {
                    try {
                        regexExec.call(value);
                        return true;
                    } catch (e) {
                        return false;
                    }
                }, regexClass = '[object RegExp]';
                isRegex = function isRegex(value) {
                    if (typeof value !== 'object') {
                        return false;
                    }
                    return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass;
                };
                var isString;
                /* inlined from https://npmjs.com/is-string */
                var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) {
                    try {
                        strValue.call(value);
                        return true;
                    } catch (e) {
                        return false;
                    }
                }, stringClass = '[object String]';
                isString = function isString(value) {
                    if (typeof value === 'string') {
                        return true;
                    }
                    if (typeof value !== 'object') {
                        return false;
                    }
                    return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass;
                };

                /* inlined from http://npmjs.com/define-properties */
                var supportsDescriptors = $Object.defineProperty && (function () {
                    try {
                        var obj = {};
                        $Object.defineProperty(obj, 'x', {enumerable: false, value: obj});
                        for (var _ in obj) {
                            return false;
                        }
                        return obj.x === obj;
                    } catch (e) { /* this is ES3 */
                        return false;
                    }
                }());
                var defineProperties = (function (has) {
                    // Define configurable, writable, and non-enumerable props
                    // if they don't exist.
                    var defineProperty;
                    if (supportsDescriptors) {
                        defineProperty = function (object, name, method, forceAssign) {
                            if (!forceAssign && (name in object)) {
                                return;
                            }
                            $Object.defineProperty(object, name, {
                                configurable: true,
                                enumerable: false,
                                writable: true,
                                value: method
                            });
                        };
                    } else {
                        defineProperty = function (object, name, method, forceAssign) {
                            if (!forceAssign && (name in object)) {
                                return;
                            }
                            object[name] = method;
                        };
                    }
                    return function defineProperties(object, map, forceAssign) {
                        for (var name in map) {
                            if (has.call(map, name)) {
                                defineProperty(object, name, map[name], forceAssign);
                            }
                        }
                    };
                }(ObjectPrototype.hasOwnProperty));

//
// Util
// ======
//

                /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */
                var isPrimitive = function isPrimitive(input) {
                    var type = typeof input;
                    return input === null || (type !== 'object' && type !== 'function');
                };

                var isActualNaN = $Number.isNaN || function (x) {
                    return x !== x;
                };

                var ES = {
                    // ES5 9.4
                    // http://es5.github.com/#x9.4
                    // http://jsperf.com/to-integer
                    /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */
                    ToInteger: function ToInteger(num) {
                        var n = +num;
                        if (isActualNaN(n)) {
                            n = 0;
                        } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
                            n = (n > 0 || -1) * Math.floor(Math.abs(n));
                        }
                        return n;
                    },

                    /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */
                    ToPrimitive: function ToPrimitive(input) {
                        var val, valueOf, toStr;
                        if (isPrimitive(input)) {
                            return input;
                        }
                        valueOf = input.valueOf;
                        if (isCallable(valueOf)) {
                            val = valueOf.call(input);
                            if (isPrimitive(val)) {
                                return val;
                            }
                        }
                        toStr = input.toString;
                        if (isCallable(toStr)) {
                            val = toStr.call(input);
                            if (isPrimitive(val)) {
                                return val;
                            }
                        }
                        throw new TypeError();
                    },

                    // ES5 9.9
                    // http://es5.github.com/#x9.9
                    /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */
                    ToObject: function (o) {
                        if (o == null) { // this matches both null and undefined
                            throw new TypeError("can't convert " + o + ' to object');
                        }
                        return $Object(o);
                    },

                    /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */
                    ToUint32: function ToUint32(x) {
                        return x >>> 0;
                    }
                };

//
// Function
// ========
//

// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5

                var Empty = function Empty() {
                };

                defineProperties(FunctionPrototype, {
                    bind: function bind(that) { // .length is 1
                        // 1. Let Target be the this value.
                        var target = this;
                        // 2. If IsCallable(Target) is false, throw a TypeError exception.
                        if (!isCallable(target)) {
                            throw new TypeError('Function.prototype.bind called on incompatible ' + target);
                        }
                        // 3. Let A be a new (possibly empty) internal list of all of the
                        //   argument values provided after thisArg (arg1, arg2 etc), in order.
                        // XXX slicedArgs will stand in for "A" if used
                        var args = array_slice.call(arguments, 1); // for normal call
                        // 4. Let F be a new native ECMAScript object.
                        // 11. Set the [[Prototype]] internal property of F to the standard
                        //   built-in Function prototype object as specified in 15.3.3.1.
                        // 12. Set the [[Call]] internal property of F as described in
                        //   15.3.4.5.1.
                        // 13. Set the [[Construct]] internal property of F as described in
                        //   15.3.4.5.2.
                        // 14. Set the [[HasInstance]] internal property of F as described in
                        //   15.3.4.5.3.
                        var bound;
                        var binder = function () {

                            if (this instanceof bound) {
                                // 15.3.4.5.2 [[Construct]]
                                // When the [[Construct]] internal method of a function object,
                                // F that was created using the bind function is called with a
                                // list of arguments ExtraArgs, the following steps are taken:
                                // 1. Let target be the value of F's [[TargetFunction]]
                                //   internal property.
                                // 2. If target has no [[Construct]] internal method, a
                                //   TypeError exception is thrown.
                                // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
                                //   property.
                                // 4. Let args be a new list containing the same values as the
                                //   list boundArgs in the same order followed by the same
                                //   values as the list ExtraArgs in the same order.
                                // 5. Return the result of calling the [[Construct]] internal
                                //   method of target providing args as the arguments.

                                var result = target.apply(
                                    this,
                                    array_concat.call(args, array_slice.call(arguments))
                                );
                                if ($Object(result) === result) {
                                    return result;
                                }
                                return this;

                            } else {
                                // 15.3.4.5.1 [[Call]]
                                // When the [[Call]] internal method of a function object, F,
                                // which was created using the bind function is called with a
                                // this value and a list of arguments ExtraArgs, the following
                                // steps are taken:
                                // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
                                //   property.
                                // 2. Let boundThis be the value of F's [[BoundThis]] internal
                                //   property.
                                // 3. Let target be the value of F's [[TargetFunction]] internal
                                //   property.
                                // 4. Let args be a new list containing the same values as the
                                //   list boundArgs in the same order followed by the same
                                //   values as the list ExtraArgs in the same order.
                                // 5. Return the result of calling the [[Call]] internal method
                                //   of target providing boundThis as the this value and
                                //   providing args as the arguments.

                                // equiv: target.call(this, ...boundArgs, ...args)
                                return target.apply(
                                    that,
                                    array_concat.call(args, array_slice.call(arguments))
                                );

                            }

                        };

                        // 15. If the [[Class]] internal property of Target is "Function", then
                        //     a. Let L be the length property of Target minus the length of A.
                        //     b. Set the length own property of F to either 0 or L, whichever is
                        //       larger.
                        // 16. Else set the length own property of F to 0.

                        var boundLength = max(0, target.length - args.length);

                        // 17. Set the attributes of the length own property of F to the values
                        //   specified in 15.3.5.1.
                        var boundArgs = [];
                        for (var i = 0; i < boundLength; i++) {
                            array_push.call(boundArgs, '$' + i);
                        }

                        // XXX Build a dynamic function with desired amount of arguments is the only
                        // way to set the length property of a function.
                        // In environments where Content Security Policies enabled (Chrome extensions,
                        // for ex.) all use of eval or Function costructor throws an exception.
                        // However in all of these environments Function.prototype.bind exists
                        // and so this code will never be executed.
                        bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);

                        if (target.prototype) {
                            Empty.prototype = target.prototype;
                            bound.prototype = new Empty();
                            // Clean up dangling references.
                            Empty.prototype = null;
                        }

                        // TODO
                        // 18. Set the [[Extensible]] internal property of F to true.

                        // TODO
                        // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
                        // 20. Call the [[DefineOwnProperty]] internal method of F with
                        //   arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
                        //   thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
                        //   false.
                        // 21. Call the [[DefineOwnProperty]] internal method of F with
                        //   arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
                        //   [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
                        //   and false.

                        // TODO
                        // NOTE Function objects created using Function.prototype.bind do not
                        // have a prototype property or the [[Code]], [[FormalParameters]], and
                        // [[Scope]] internal properties.
                        // XXX can't delete prototype in pure-js.

                        // 22. Return F.
                        return bound;
                    }
                });

// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
// use it in defining shortcuts.
                var owns = call.bind(ObjectPrototype.hasOwnProperty);
                var toStr = call.bind(ObjectPrototype.toString);
                var arraySlice = call.bind(array_slice);
                var arraySliceApply = apply.bind(array_slice);
                var strSlice = call.bind(StringPrototype.slice);
                var strSplit = call.bind(StringPrototype.split);
                var strIndexOf = call.bind(StringPrototype.indexOf);
                var push = call.bind(array_push);
                var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable);
                var arraySort = call.bind(ArrayPrototype.sort);

//
// Array
// =====
//

                var isArray = $Array.isArray || function isArray(obj) {
                    return toStr(obj) === '[object Array]';
                };

// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.13
// Return len+argCount.
// [bugfix, ielt8]
// IE < 8 bug: [].unshift(0) === undefined but should be "1"
                var hasUnshiftReturnValueBug = [].unshift(0) !== 1;
                defineProperties(ArrayPrototype, {
                    unshift: function () {
                        array_unshift.apply(this, arguments);
                        return this.length;
                    }
                }, hasUnshiftReturnValueBug);

// ES5 15.4.3.2
// http://es5.github.com/#x15.4.3.2
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
                defineProperties($Array, {isArray: isArray});

// The IsCallable() check in the Array functions
// has been replaced with a strict check on the
// internal class of the object to trap cases where
// the provided function was actually a regular
// expression literal, which in V8 and
// JavaScriptCore is a typeof "function".  Only in
// V8 are regular expression literals permitted as
// reduce parameters, so it is desirable in the
// general case for the shim to match the more
// strict and common behavior of rejecting regular
// expressions.

// ES5 15.4.4.18
// http://es5.github.com/#x15.4.4.18
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach

// Check failure of by-index access of string characters (IE < 9)
// and failure of `0 in boxedString` (Rhino)
                var boxedString = $Object('a');
                var splitString = boxedString[0] !== 'a' || !(0 in boxedString);

                var properlyBoxesContext = function properlyBoxed(method) {
                    // Check node 0.6.21 bug where third parameter is not boxed
                    var properlyBoxesNonStrict = true;
                    var properlyBoxesStrict = true;
                    if (method) {
                        method.call('foo', function (_, __, context) {
                            if (typeof context !== 'object') {
                                properlyBoxesNonStrict = false;
                            }
                        });

                        method.call([1], function () {
                            'use strict';

                            properlyBoxesStrict = typeof this === 'string';
                        }, 'x');
                    }
                    return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
                };

                defineProperties(ArrayPrototype, {
                    forEach: function forEach(callbackfn/*, thisArg*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var i = -1;
                        var length = ES.ToUint32(self.length);
                        var T;
                        if (arguments.length > 1) {
                            T = arguments[1];
                        }

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.forEach callback must be a function');
                        }

                        while (++i < length) {
                            if (i in self) {
                                // Invoke the callback function with call, passing arguments:
                                // context, property value, property key, thisArg object
                                if (typeof T === 'undefined') {
                                    callbackfn(self[i], i, object);
                                } else {
                                    callbackfn.call(T, self[i], i, object);
                                }
                            }
                        }
                    }
                }, !properlyBoxesContext(ArrayPrototype.forEach));

// ES5 15.4.4.19
// http://es5.github.com/#x15.4.4.19
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
                defineProperties(ArrayPrototype, {
                    map: function map(callbackfn/*, thisArg*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);
                        var result = $Array(length);
                        var T;
                        if (arguments.length > 1) {
                            T = arguments[1];
                        }

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.map callback must be a function');
                        }

                        for (var i = 0; i < length; i++) {
                            if (i in self) {
                                if (typeof T === 'undefined') {
                                    result[i] = callbackfn(self[i], i, object);
                                } else {
                                    result[i] = callbackfn.call(T, self[i], i, object);
                                }
                            }
                        }
                        return result;
                    }
                }, !properlyBoxesContext(ArrayPrototype.map));

// ES5 15.4.4.20
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
                defineProperties(ArrayPrototype, {
                    filter: function filter(callbackfn/*, thisArg*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);
                        var result = [];
                        var value;
                        var T;
                        if (arguments.length > 1) {
                            T = arguments[1];
                        }

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.filter callback must be a function');
                        }

                        for (var i = 0; i < length; i++) {
                            if (i in self) {
                                value = self[i];
                                if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) {
                                    push(result, value);
                                }
                            }
                        }
                        return result;
                    }
                }, !properlyBoxesContext(ArrayPrototype.filter));

// ES5 15.4.4.16
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
                defineProperties(ArrayPrototype, {
                    every: function every(callbackfn/*, thisArg*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);
                        var T;
                        if (arguments.length > 1) {
                            T = arguments[1];
                        }

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.every callback must be a function');
                        }

                        for (var i = 0; i < length; i++) {
                            if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) {
                                return false;
                            }
                        }
                        return true;
                    }
                }, !properlyBoxesContext(ArrayPrototype.every));

// ES5 15.4.4.17
// http://es5.github.com/#x15.4.4.17
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
                defineProperties(ArrayPrototype, {
                    some: function some(callbackfn/*, thisArg */) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);
                        var T;
                        if (arguments.length > 1) {
                            T = arguments[1];
                        }

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.some callback must be a function');
                        }

                        for (var i = 0; i < length; i++) {
                            if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) {
                                return true;
                            }
                        }
                        return false;
                    }
                }, !properlyBoxesContext(ArrayPrototype.some));

// ES5 15.4.4.21
// http://es5.github.com/#x15.4.4.21
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
                var reduceCoercesToObject = false;
                if (ArrayPrototype.reduce) {
                    reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) {
                        return list;
                    }) === 'object';
                }
                defineProperties(ArrayPrototype, {
                    reduce: function reduce(callbackfn/*, initialValue*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.reduce callback must be a function');
                        }

                        // no value to return if no initial value and an empty array
                        if (length === 0 && arguments.length === 1) {
                            throw new TypeError('reduce of empty array with no initial value');
                        }

                        var i = 0;
                        var result;
                        if (arguments.length >= 2) {
                            result = arguments[1];
                        } else {
                            do {
                                if (i in self) {
                                    result = self[i++];
                                    break;
                                }

                                // if array contains no values, no initial value to return
                                if (++i >= length) {
                                    throw new TypeError('reduce of empty array with no initial value');
                                }
                            } while (true);
                        }

                        for (; i < length; i++) {
                            if (i in self) {
                                result = callbackfn(result, self[i], i, object);
                            }
                        }

                        return result;
                    }
                }, !reduceCoercesToObject);

// ES5 15.4.4.22
// http://es5.github.com/#x15.4.4.22
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
                var reduceRightCoercesToObject = false;
                if (ArrayPrototype.reduceRight) {
                    reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) {
                        return list;
                    }) === 'object';
                }
                defineProperties(ArrayPrototype, {
                    reduceRight: function reduceRight(callbackfn/*, initial*/) {
                        var object = ES.ToObject(this);
                        var self = splitString && isString(this) ? strSplit(this, '') : object;
                        var length = ES.ToUint32(self.length);

                        // If no callback function or if callback is not a callable function
                        if (!isCallable(callbackfn)) {
                            throw new TypeError('Array.prototype.reduceRight callback must be a function');
                        }

                        // no value to return if no initial value, empty array
                        if (length === 0 && arguments.length === 1) {
                            throw new TypeError('reduceRight of empty array with no initial value');
                        }

                        var result;
                        var i = length - 1;
                        if (arguments.length >= 2) {
                            result = arguments[1];
                        } else {
                            do {
                                if (i in self) {
                                    result = self[i--];
                                    break;
                                }

                                // if array contains no values, no initial value to return
                                if (--i < 0) {
                                    throw new TypeError('reduceRight of empty array with no initial value');
                                }
                            } while (true);
                        }

                        if (i < 0) {
                            return result;
                        }

                        do {
                            if (i in self) {
                                result = callbackfn(result, self[i], i, object);
                            }
                        } while (i--);

                        return result;
                    }
                }, !reduceRightCoercesToObject);

// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
                var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
                defineProperties(ArrayPrototype, {
                    indexOf: function indexOf(searchElement/*, fromIndex */) {
                        var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this);
                        var length = ES.ToUint32(self.length);

                        if (length === 0) {
                            return -1;
                        }

                        var i = 0;
                        if (arguments.length > 1) {
                            i = ES.ToInteger(arguments[1]);
                        }

                        // handle negative indices
                        i = i >= 0 ? i : max(0, length + i);
                        for (; i < length; i++) {
                            if (i in self && self[i] === searchElement) {
                                return i;
                            }
                        }
                        return -1;
                    }
                }, hasFirefox2IndexOfBug);

// ES5 15.4.4.15
// http://es5.github.com/#x15.4.4.15
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
                var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
                defineProperties(ArrayPrototype, {
                    lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) {
                        var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this);
                        var length = ES.ToUint32(self.length);

                        if (length === 0) {
                            return -1;
                        }
                        var i = length - 1;
                        if (arguments.length > 1) {
                            i = min(i, ES.ToInteger(arguments[1]));
                        }
                        // handle negative indices
                        i = i >= 0 ? i : length - Math.abs(i);
                        for (; i >= 0; i--) {
                            if (i in self && searchElement === self[i]) {
                                return i;
                            }
                        }
                        return -1;
                    }
                }, hasFirefox2LastIndexOfBug);

// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.12
                var spliceNoopReturnsEmptyArray = (function () {
                    var a = [1, 2];
                    var result = a.splice();
                    return a.length === 2 && isArray(result) && result.length === 0;
                }());
                defineProperties(ArrayPrototype, {
                    // Safari 5.0 bug where .splice() returns undefined
                    splice: function splice(start, deleteCount) {
                        if (arguments.length === 0) {
                            return [];
                        } else {
                            return array_splice.apply(this, arguments);
                        }
                    }
                }, !spliceNoopReturnsEmptyArray);

                var spliceWorksWithEmptyObject = (function () {
                    var obj = {};
                    ArrayPrototype.splice.call(obj, 0, 0, 1);
                    return obj.length === 1;
                }());
                defineProperties(ArrayPrototype, {
                    splice: function splice(start, deleteCount) {
                        if (arguments.length === 0) {
                            return [];
                        }
                        var args = arguments;
                        this.length = max(ES.ToInteger(this.length), 0);
                        if (arguments.length > 0 && typeof deleteCount !== 'number') {
                            args = arraySlice(arguments);
                            if (args.length < 2) {
                                push(args, this.length - start);
                            } else {
                                args[1] = ES.ToInteger(deleteCount);
                            }
                        }
                        return array_splice.apply(this, args);
                    }
                }, !spliceWorksWithEmptyObject);
                var spliceWorksWithLargeSparseArrays = (function () {
                    // Per https://github.com/es-shims/es5-shim/issues/295
                    // Safari 7/8 breaks with sparse arrays of size 1e5 or greater
                    var arr = new $Array(1e5);
                    // note: the index MUST be 8 or larger or the test will false pass
                    arr[8] = 'x';
                    arr.splice(1, 1);
                    // note: this test must be defined *after* the indexOf shim
                    // per https://github.com/es-shims/es5-shim/issues/313
                    return arr.indexOf('x') === 7;
                }());
                var spliceWorksWithSmallSparseArrays = (function () {
                    // Per https://github.com/es-shims/es5-shim/issues/295
                    // Opera 12.15 breaks on this, no idea why.
                    var n = 256;
                    var arr = [];
                    arr[n] = 'a';
                    arr.splice(n + 1, 0, 'b');
                    return arr[n] === 'a';
                }());
                defineProperties(ArrayPrototype, {
                    splice: function splice(start, deleteCount) {
                        var O = ES.ToObject(this);
                        var A = [];
                        var len = ES.ToUint32(O.length);
                        var relativeStart = ES.ToInteger(start);
                        var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len);
                        var actualDeleteCount = min(max(ES.ToInteger(deleteCount), 0), len - actualStart);

                        var k = 0;
                        var from;
                        while (k < actualDeleteCount) {
                            from = $String(actualStart + k);
                            if (owns(O, from)) {
                                A[k] = O[from];
                            }
                            k += 1;
                        }

                        var items = arraySlice(arguments, 2);
                        var itemCount = items.length;
                        var to;
                        if (itemCount < actualDeleteCount) {
                            k = actualStart;
                            while (k < (len - actualDeleteCount)) {
                                from = $String(k + actualDeleteCount);
                                to = $String(k + itemCount);
                                if (owns(O, from)) {
                                    O[to] = O[from];
                                } else {
                                    delete O[to];
                                }
                                k += 1;
                            }
                            k = len;
                            while (k > (len - actualDeleteCount + itemCount)) {
                                delete O[k - 1];
                                k -= 1;
                            }
                        } else if (itemCount > actualDeleteCount) {
                            k = len - actualDeleteCount;
                            while (k > actualStart) {
                                from = $String(k + actualDeleteCount - 1);
                                to = $String(k + itemCount - 1);
                                if (owns(O, from)) {
                                    O[to] = O[from];
                                } else {
                                    delete O[to];
                                }
                                k -= 1;
                            }
                        }
                        k = actualStart;
                        for (var i = 0; i < items.length; ++i) {
                            O[k] = items[i];
                            k += 1;
                        }
                        O.length = len - actualDeleteCount + itemCount;

                        return A;
                    }
                }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays);

                var originalJoin = ArrayPrototype.join;
                var hasStringJoinBug;
                try {
                    hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3';
                } catch (e) {
                    hasStringJoinBug = true;
                }
                if (hasStringJoinBug) {
                    defineProperties(ArrayPrototype, {
                        join: function join(separator) {
                            var sep = typeof separator === 'undefined' ? ',' : separator;
                            return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep);
                        }
                    }, hasStringJoinBug);
                }

                var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2';
                if (hasJoinUndefinedBug) {
                    defineProperties(ArrayPrototype, {
                        join: function join(separator) {
                            var sep = typeof separator === 'undefined' ? ',' : separator;
                            return originalJoin.call(this, sep);
                        }
                    }, hasJoinUndefinedBug);
                }

                var pushShim = function push(item) {
                    var O = ES.ToObject(this);
                    var n = ES.ToUint32(O.length);
                    var i = 0;
                    while (i < arguments.length) {
                        O[n + i] = arguments[i];
                        i += 1;
                    }
                    O.length = n + i;
                    return n + i;
                };

                var pushIsNotGeneric = (function () {
                    var obj = {};
                    var result = Array.prototype.push.call(obj, undefined);
                    return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0);
                }());
                defineProperties(ArrayPrototype, {
                    push: function push(item) {
                        if (isArray(this)) {
                            return array_push.apply(this, arguments);
                        }
                        return pushShim.apply(this, arguments);
                    }
                }, pushIsNotGeneric);

// This fixes a very weird bug in Opera 10.6 when pushing `undefined
                var pushUndefinedIsWeird = (function () {
                    var arr = [];
                    var result = arr.push(undefined);
                    return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0);
                }());
                defineProperties(ArrayPrototype, {push: pushShim}, pushUndefinedIsWeird);

// ES5 15.2.3.14
// http://es5.github.io/#x15.4.4.10
// Fix boxed string bug
                defineProperties(ArrayPrototype, {
                    slice: function (start, end) {
                        var arr = isString(this) ? strSplit(this, '') : this;
                        return arraySliceApply(arr, arguments);
                    }
                }, splitString);

                var sortIgnoresNonFunctions = (function () {
                    try {
                        [1, 2].sort(null);
                        [1, 2].sort({});
                        return true;
                    } catch (e) { /**/
                    }
                    return false;
                }());
                var sortThrowsOnRegex = (function () {
                    // this is a problem in Firefox 4, in which `typeof /a/ === 'function'`
                    try {
                        [1, 2].sort(/a/);
                        return false;
                    } catch (e) { /**/
                    }
                    return true;
                }());
                var sortIgnoresUndefined = (function () {
                    // applies in IE 8, for one.
                    try {
                        [1, 2].sort(undefined);
                        return true;
                    } catch (e) { /**/
                    }
                    return false;
                }());
                defineProperties(ArrayPrototype, {
                    sort: function sort(compareFn) {
                        if (typeof compareFn === 'undefined') {
                            return arraySort(this);
                        }
                        if (!isCallable(compareFn)) {
                            throw new TypeError('Array.prototype.sort callback must be a function');
                        }
                        return arraySort(this, compareFn);
                    }
                }, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex);

//
// Object
// ======
//

// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14

// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
                var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString');
                var hasProtoEnumBug = function () {
                }.propertyIsEnumerable('prototype');
                var hasStringEnumBug = !owns('x', '0');
                var equalsConstructorPrototype = function (o) {
                    var ctor = o.constructor;
                    return ctor && ctor.prototype === o;
                };
                var blacklistedKeys = {
                    $window: true,
                    $console: true,
                    $parent: true,
                    $self: true,
                    $frame: true,
                    $frames: true,
                    $frameElement: true,
                    $webkitIndexedDB: true,
                    $webkitStorageInfo: true,
                    $external: true
                };
                var hasAutomationEqualityBug = (function () {
                    /* globals window */
                    if (typeof window === 'undefined') {
                        return false;
                    }
                    for (var k in window) {
                        try {
                            if (!blacklistedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') {
                                equalsConstructorPrototype(window[k]);
                            }
                        } catch (e) {
                            return true;
                        }
                    }
                    return false;
                }());
                var equalsConstructorPrototypeIfNotBuggy = function (object) {
                    if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
                        return equalsConstructorPrototype(object);
                    }
                    try {
                        return equalsConstructorPrototype(object);
                    } catch (e) {
                        return false;
                    }
                };
                var dontEnums = [
                    'toString',
                    'toLocaleString',
                    'valueOf',
                    'hasOwnProperty',
                    'isPrototypeOf',
                    'propertyIsEnumerable',
                    'constructor'
                ];
                var dontEnumsLength = dontEnums.length;

// taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js
// can be replaced with require('is-arguments') if we ever use a build process instead
                var isStandardArguments = function isArguments(value) {
                    return toStr(value) === '[object Arguments]';
                };
                var isLegacyArguments = function isArguments(value) {
                    return value !== null &&
                        typeof value === 'object' &&
                        typeof value.length === 'number' &&
                        value.length >= 0 &&
                        !isArray(value) &&
                        isCallable(value.callee);
                };
                var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments;

                defineProperties($Object, {
                    keys: function keys(object) {
                        var isFn = isCallable(object);
                        var isArgs = isArguments(object);
                        var isObject = object !== null && typeof object === 'object';
                        var isStr = isObject && isString(object);

                        if (!isObject && !isFn && !isArgs) {
                            throw new TypeError('Object.keys called on a non-object');
                        }

                        var theKeys = [];
                        var skipProto = hasProtoEnumBug && isFn;
                        if ((isStr && hasStringEnumBug) || isArgs) {
                            for (var i = 0; i < object.length; ++i) {
                                push(theKeys, $String(i));
                            }
                        }

                        if (!isArgs) {
                            for (var name in object) {
                                if (!(skipProto && name === 'prototype') && owns(object, name)) {
                                    push(theKeys, $String(name));
                                }
                            }
                        }

                        if (hasDontEnumBug) {
                            var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
                            for (var j = 0; j < dontEnumsLength; j++) {
                                var dontEnum = dontEnums[j];
                                if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
                                    push(theKeys, dontEnum);
                                }
                            }
                        }
                        return theKeys;
                    }
                });

                var keysWorksWithArguments = $Object.keys && (function () {
                    // Safari 5.0 bug
                    return $Object.keys(arguments).length === 2;
                }(1, 2));
                var keysHasArgumentsLengthBug = $Object.keys && (function () {
                    var argKeys = $Object.keys(arguments);
                    return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1;
                }(1));
                var originalKeys = $Object.keys;
                defineProperties($Object, {
                    keys: function keys(object) {
                        if (isArguments(object)) {
                            return originalKeys(arraySlice(object));
                        } else {
                            return originalKeys(object);
                        }
                    }
                }, !keysWorksWithArguments || keysHasArgumentsLengthBug);

//
// Date
// ====
//

// ES5 15.9.5.43
// http://es5.github.com/#x15.9.5.43
// This function returns a String value represent the instance in time
// represented by this Date object. The format of the String is the Date Time
// string format defined in 15.9.1.15. All fields are present in the String.
// The time zone is always UTC, denoted by the suffix Z. If the time value of
// this object is not a finite Number a RangeError exception is thrown.
                var negativeDate = -62198755200000;
                var negativeYearString = '-000001';
                var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;
                var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z';

                defineProperties(Date.prototype, {
                    toISOString: function toISOString() {
                        var result, length, value, year, month;
                        if (!isFinite(this)) {
                            throw new RangeError('Date.prototype.toISOString called on non-finite value.');
                        }

                        year = this.getUTCFullYear();

                        month = this.getUTCMonth();
                        // see https://github.com/es-shims/es5-shim/issues/111
                        year += Math.floor(month / 12);
                        month = (month % 12 + 12) % 12;

                        // the date time string format is specified in 15.9.1.15.
                        result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
                        year = (
                            (year < 0 ? '-' : (year > 9999 ? '+' : '')) +
                            strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6)
                        );

                        length = result.length;
                        while (length--) {
                            value = result[length];
                            // pad months, days, hours, minutes, and seconds to have two
                            // digits.
                            if (value < 10) {
                                result[length] = '0' + value;
                            }
                        }
                        // pad milliseconds to have three digits.
                        return (
                            year + '-' + arraySlice(result, 0, 2).join('-') +
                            'T' + arraySlice(result, 2).join(':') + '.' +
                            strSlice('000' + this.getUTCMilliseconds(), -3) + 'Z'
                        );
                    }
                }, hasNegativeDateBug || hasSafari51DateBug);

// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// This function provides a String representation of a Date object for use by
// JSON.stringify (15.12.3).
                var dateToJSONIsSupported = (function () {
                    try {
                        return Date.prototype.toJSON &&
                            new Date(NaN).toJSON() === null &&
                            new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
                            Date.prototype.toJSON.call({ // generic
                                toISOString: function () {
                                    return true;
                                }
                            });
                    } catch (e) {
                        return false;
                    }
                }());
                if (!dateToJSONIsSupported) {
                    Date.prototype.toJSON = function toJSON(key) {
                        // When the toJSON method is called with argument key, the following
                        // steps are taken:

                        // 1.  Let O be the result of calling ToObject, giving it the this
                        // value as its argument.
                        // 2. Let tv be ES.ToPrimitive(O, hint Number).
                        var O = $Object(this);
                        var tv = ES.ToPrimitive(O);
                        // 3. If tv is a Number and is not finite, return null.
                        if (typeof tv === 'number' && !isFinite(tv)) {
                            return null;
                        }
                        // 4. Let toISO be the result of calling the [[Get]] internal method of
                        // O with argument "toISOString".
                        var toISO = O.toISOString;
                        // 5. If IsCallable(toISO) is false, throw a TypeError exception.
                        if (!isCallable(toISO)) {
                            throw new TypeError('toISOString property is not callable');
                        }
                        // 6. Return the result of calling the [[Call]] internal method of
                        //  toISO with O as the this value and an empty argument list.
                        return toISO.call(O);

                        // NOTE 1 The argument is ignored.

                        // NOTE 2 The toJSON function is intentionally generic; it does not
                        // require that its this value be a Date object. Therefore, it can be
                        // transferred to other kinds of objects for use as a method. However,
                        // it does require that any such object have a toISOString method. An
                        // object is free to use the argument key to filter its
                        // stringification.
                    };
                }

// ES5 15.9.4.2
// http://es5.github.com/#x15.9.4.2
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
                var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
                var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z'));
                var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z'));
                if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
                    // XXX global assignment won't work in embeddings that use
                    // an alternate object for the context.
                    /* global Date: true */
                    /* eslint-disable no-undef */
                    var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1;
                    var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime());
                    Date = (function (NativeDate) {
                        /* eslint-enable no-undef */
                        // Date.length === 7
                        var DateShim = function Date(Y, M, D, h, m, s, ms) {
                            var length = arguments.length;
                            var date;
                            if (this instanceof NativeDate) {
                                var seconds = s;
                                var millis = ms;
                                if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) {
                                    // work around a Safari 8/9 bug where it treats the seconds as signed
                                    var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit;
                                    var sToShift = Math.floor(msToShift / 1e3);
                                    seconds += sToShift;
                                    millis -= sToShift * 1e3;
                                }
                                date = length === 1 && $String(Y) === Y ? // isString(Y)
                                    // We explicitly pass it through parse:
                                    new NativeDate(DateShim.parse(Y)) :
                                    // We have to manually make calls depending on argument
                                    // length here
                                    length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) :
                                        length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) :
                                            length >= 5 ? new NativeDate(Y, M, D, h, m) :
                                                length >= 4 ? new NativeDate(Y, M, D, h) :
                                                    length >= 3 ? new NativeDate(Y, M, D) :
                                                        length >= 2 ? new NativeDate(Y, M) :
                                                            length >= 1 ? new NativeDate(Y) :
                                                                new NativeDate();
                            } else {
                                date = NativeDate.apply(this, arguments);
                            }
                            if (!isPrimitive(date)) {
                                // Prevent mixups with unfixed Date object
                                defineProperties(date, {constructor: DateShim}, true);
                            }
                            return date;
                        };

                        // 15.9.1.15 Date Time String Format.
                        var isoDateExpression = new RegExp('^' +
                            '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign +
                            // 6-digit extended year
                            '(?:-(\\d{2})' + // optional month capture
                            '(?:-(\\d{2})' + // optional day capture
                            '(?:' + // capture hours:minutes:seconds.milliseconds
                            'T(\\d{2})' + // hours capture
                            ':(\\d{2})' + // minutes capture
                            '(?:' + // optional :seconds.milliseconds
                            ':(\\d{2})' + // seconds capture
                            '(?:(\\.\\d{1,}))?' + // milliseconds capture
                            ')?' +
                            '(' + // capture UTC offset component
                            'Z|' + // UTC capture
                            '(?:' + // offset specifier +/-hours:minutes
                            '([-+])' + // sign capture
                            '(\\d{2})' + // hours offset capture
                            ':(\\d{2})' + // minutes offset capture
                            ')' +
                            ')?)?)?)?' +
                            '$');

                        var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];

                        var dayFromMonth = function dayFromMonth(year, month) {
                            var t = month > 1 ? 1 : 0;
                            return (
                                months[month] +
                                Math.floor((year - 1969 + t) / 4) -
                                Math.floor((year - 1901 + t) / 100) +
                                Math.floor((year - 1601 + t) / 400) +
                                365 * (year - 1970)
                            );
                        };

                        var toUTC = function toUTC(t) {
                            var s = 0;
                            var ms = t;
                            if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) {
                                // work around a Safari 8/9 bug where it treats the seconds as signed
                                var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit;
                                var sToShift = Math.floor(msToShift / 1e3);
                                s += sToShift;
                                ms -= sToShift * 1e3;
                            }
                            return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms));
                        };

                        // Copy any custom methods a 3rd party library may have added
                        for (var key in NativeDate) {
                            if (owns(NativeDate, key)) {
                                DateShim[key] = NativeDate[key];
                            }
                        }

                        // Copy "native" methods explicitly; they may be non-enumerable
                        defineProperties(DateShim, {
                            now: NativeDate.now,
                            UTC: NativeDate.UTC
                        }, true);
                        DateShim.prototype = NativeDate.prototype;
                        defineProperties(DateShim.prototype, {
                            constructor: DateShim
                        }, true);

                        // Upgrade Date.parse to handle simplified ISO 8601 strings
                        var parseShim = function parse(string) {
                            var match = isoDateExpression.exec(string);
                            if (match) {
                                // parse months, days, hours, minutes, seconds, and milliseconds
                                // provide default values if necessary
                                // parse the UTC offset component
                                var year = $Number(match[1]),
                                    month = $Number(match[2] || 1) - 1,
                                    day = $Number(match[3] || 1) - 1,
                                    hour = $Number(match[4] || 0),
                                    minute = $Number(match[5] || 0),
                                    second = $Number(match[6] || 0),
                                    millisecond = Math.floor($Number(match[7] || 0) * 1000),
                                    // When time zone is missed, local offset should be used
                                    // (ES 5.1 bug)
                                    // see https://bugs.ecmascript.org/show_bug.cgi?id=112
                                    isLocalTime = Boolean(match[4] && !match[8]),
                                    signOffset = match[9] === '-' ? 1 : -1,
                                    hourOffset = $Number(match[10] || 0),
                                    minuteOffset = $Number(match[11] || 0),
                                    result;
                                var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0;
                                if (
                                    hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) &&
                                    minute < 60 && second < 60 && millisecond < 1000 &&
                                    month > -1 && month < 12 && hourOffset < 24 &&
                                    minuteOffset < 60 && // detect invalid offsets
                                    day > -1 &&
                                    day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month))
                                ) {
                                    result = (
                                        (dayFromMonth(year, month) + day) * 24 +
                                        hour +
                                        hourOffset * signOffset
                                    ) * 60;
                                    result = (
                                        (result + minute + minuteOffset * signOffset) * 60 +
                                        second
                                    ) * 1000 + millisecond;
                                    if (isLocalTime) {
                                        result = toUTC(result);
                                    }
                                    if (-8.64e15 <= result && result <= 8.64e15) {
                                        return result;
                                    }
                                }
                                return NaN;
                            }
                            return NativeDate.parse.apply(this, arguments);
                        };
                        defineProperties(DateShim, {parse: parseShim});

                        return DateShim;
                    }(Date));
                    /* global Date: false */
                }

// ES5 15.9.4.4
// http://es5.github.com/#x15.9.4.4
                if (!Date.now) {
                    Date.now = function now() {
                        return new Date().getTime();
                    };
                }

//
// Number
// ======
//

// ES5.1 15.7.4.5
// http://es5.github.com/#x15.7.4.5
                var hasToFixedBugs = NumberPrototype.toFixed && (
                    (0.00008).toFixed(3) !== '0.000' ||
                    (0.9).toFixed(0) !== '1' ||
                    (1.255).toFixed(2) !== '1.25' ||
                    (1000000000000000128).toFixed(0) !== '1000000000000000128'
                );

                var toFixedHelpers = {
                    base: 1e7,
                    size: 6,
                    data: [0, 0, 0, 0, 0, 0],
                    multiply: function multiply(n, c) {
                        var i = -1;
                        var c2 = c;
                        while (++i < toFixedHelpers.size) {
                            c2 += n * toFixedHelpers.data[i];
                            toFixedHelpers.data[i] = c2 % toFixedHelpers.base;
                            c2 = Math.floor(c2 / toFixedHelpers.base);
                        }
                    },
                    divide: function divide(n) {
                        var i = toFixedHelpers.size, c = 0;
                        while (--i >= 0) {
                            c += toFixedHelpers.data[i];
                            toFixedHelpers.data[i] = Math.floor(c / n);
                            c = (c % n) * toFixedHelpers.base;
                        }
                    },
                    numToString: function numToString() {
                        var i = toFixedHelpers.size;
                        var s = '';
                        while (--i >= 0) {
                            if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) {
                                var t = $String(toFixedHelpers.data[i]);
                                if (s === '') {
                                    s = t;
                                } else {
                                    s += strSlice('0000000', 0, 7 - t.length) + t;
                                }
                            }
                        }
                        return s;
                    },
                    pow: function pow(x, n, acc) {
                        return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc)));
                    },
                    log: function log(x) {
                        var n = 0;
                        var x2 = x;
                        while (x2 >= 4096) {
                            n += 12;
                            x2 /= 4096;
                        }
                        while (x2 >= 2) {
                            n += 1;
                            x2 /= 2;
                        }
                        return n;
                    }
                };

                var toFixedShim = function toFixed(fractionDigits) {
                    var f, x, s, m, e, z, j, k;

                    // Test for NaN and round fractionDigits down
                    f = $Number(fractionDigits);
                    f = isActualNaN(f) ? 0 : Math.floor(f);

                    if (f < 0 || f > 20) {
                        throw new RangeError('Number.toFixed called with invalid number of decimals');
                    }

                    x = $Number(this);

                    if (isActualNaN(x)) {
                        return 'NaN';
                    }

                    // If it is too big or small, return the string value of the number
                    if (x <= -1e21 || x >= 1e21) {
                        return $String(x);
                    }

                    s = '';

                    if (x < 0) {
                        s = '-';
                        x = -x;
                    }

                    m = '0';

                    if (x > 1e-21) {
                        // 1e-21 < x < 1e21
                        // -70 < log2(x) < 70
                        e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69;
                        z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1));
                        z *= 0x10000000000000; // Math.pow(2, 52);
                        e = 52 - e;

                        // -18 < e < 122
                        // x = z / 2 ^ e
                        if (e > 0) {
                            toFixedHelpers.multiply(0, z);
                            j = f;

                            while (j >= 7) {
                                toFixedHelpers.multiply(1e7, 0);
                                j -= 7;
                            }

                            toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0);
                            j = e - 1;

                            while (j >= 23) {
                                toFixedHelpers.divide(1 << 23);
                                j -= 23;
                            }

                            toFixedHelpers.divide(1 << j);
                            toFixedHelpers.multiply(1, 1);
                            toFixedHelpers.divide(2);
                            m = toFixedHelpers.numToString();
                        } else {
                            toFixedHelpers.multiply(0, z);
                            toFixedHelpers.multiply(1 << (-e), 0);
                            m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f);
                        }
                    }

                    if (f > 0) {
                        k = m.length;

                        if (k <= f) {
                            m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m;
                        } else {
                            m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f);
                        }
                    } else {
                        m = s + m;
                    }

                    return m;
                };
                defineProperties(NumberPrototype, {toFixed: toFixedShim}, hasToFixedBugs);

                var hasToPrecisionUndefinedBug = (function () {
                    try {
                        return 1.0.toPrecision(undefined) === '1';
                    } catch (e) {
                        return true;
                    }
                }());
                var originalToPrecision = NumberPrototype.toPrecision;
                defineProperties(NumberPrototype, {
                    toPrecision: function toPrecision(precision) {
                        return typeof precision === 'undefined' ? originalToPrecision.call(this) : originalToPrecision.call(this, precision);
                    }
                }, hasToPrecisionUndefinedBug);

//
// String
// ======
//

// ES5 15.5.4.14
// http://es5.github.com/#x15.5.4.14

// [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
// Many browsers do not split properly with regular expressions or they
// do not perform the split correctly under obscure conditions.
// See http://blog.stevenlevithan.com/archives/cross-browser-split
// I've tested in many browsers and this seems to cover the deviant ones:
//    'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
//    '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
//    'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
//       [undefined, "t", undefined, "e", ...]
//    ''.split(/.?/) should be [], not [""]
//    '.'.split(/()()/) should be ["."], not ["", "", "."]

                if (
                    'ab'.split(/(?:ab)*/).length !== 2 ||
                    '.'.split(/(.?)(.?)/).length !== 4 ||
                    'tesst'.split(/(s)*/)[1] === 't' ||
                    'test'.split(/(?:)/, -1).length !== 4 ||
                    ''.split(/.?/).length ||
                    '.'.split(/()()/).length > 1
                ) {
                    (function () {
                        var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group
                        var maxSafe32BitInt = Math.pow(2, 32) - 1;

                        StringPrototype.split = function (separator, limit) {
                            var string = String(this);
                            if (typeof separator === 'undefined' && limit === 0) {
                                return [];
                            }

                            // If `separator` is not a regex, use native split
                            if (!isRegex(separator)) {
                                return strSplit(this, separator, limit);
                            }

                            var output = [];
                            var flags = (separator.ignoreCase ? 'i' : '') +
                                (separator.multiline ? 'm' : '') +
                                (separator.unicode ? 'u' : '') + // in ES6
                                (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6
                                lastLastIndex = 0,
                                // Make `global` and avoid `lastIndex` issues by working with a copy
                                separator2, match, lastIndex, lastLength;
                            var separatorCopy = new RegExp(separator.source, flags + 'g');
                            if (!compliantExecNpcg) {
                                // Doesn't need flags gy, but they don't hurt
                                separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags);
                            }
                            /* Values for `limit`, per the spec:
             * If undefined: 4294967295 // maxSafe32BitInt
             * If 0, Infinity, or NaN: 0
             * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
             * If negative number: 4294967296 - Math.floor(Math.abs(limit))
             * If other: Type-convert, then use the above rules
             */
                            var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit);
                            match = separatorCopy.exec(string);
                            while (match) {
                                // `separatorCopy.lastIndex` is not reliable cross-browser
                                lastIndex = match.index + match[0].length;
                                if (lastIndex > lastLastIndex) {
                                    push(output, strSlice(string, lastLastIndex, match.index));
                                    // Fix browsers whose `exec` methods don't consistently return `undefined` for
                                    // nonparticipating capturing groups
                                    if (!compliantExecNpcg && match.length > 1) {
                                        /* eslint-disable no-loop-func */
                                        match[0].replace(separator2, function () {
                                            for (var i = 1; i < arguments.length - 2; i++) {
                                                if (typeof arguments[i] === 'undefined') {
                                                    match[i] = void 0;
                                                }
                                            }
                                        });
                                        /* eslint-enable no-loop-func */
                                    }
                                    if (match.length > 1 && match.index < string.length) {
                                        array_push.apply(output, arraySlice(match, 1));
                                    }
                                    lastLength = match[0].length;
                                    lastLastIndex = lastIndex;
                                    if (output.length >= splitLimit) {
                                        break;
                                    }
                                }
                                if (separatorCopy.lastIndex === match.index) {
                                    separatorCopy.lastIndex++; // Avoid an infinite loop
                                }
                                match = separatorCopy.exec(string);
                            }
                            if (lastLastIndex === string.length) {
                                if (lastLength || !separatorCopy.test('')) {
                                    push(output, '');
                                }
                            } else {
                                push(output, strSlice(string, lastLastIndex));
                            }
                            return output.length > splitLimit ? strSlice(output, 0, splitLimit) : output;
                        };
                    }());

// [bugfix, chrome]
// If separator is undefined, then the result array contains just one String,
// which is the this value (converted to a String). If limit is not undefined,
// then the output array is truncated so that it contains no more than limit
// elements.
// "0".split(undefined, 0) -> []
                } else if ('0'.split(void 0, 0).length) {
                    StringPrototype.split = function split(separator, limit) {
                        if (typeof separator === 'undefined' && limit === 0) {
                            return [];
                        }
                        return strSplit(this, separator, limit);
                    };
                }

                var str_replace = StringPrototype.replace;
                var replaceReportsGroupsCorrectly = (function () {
                    var groups = [];
                    'x'.replace(/x(.)?/g, function (match, group) {
                        push(groups, group);
                    });
                    return groups.length === 1 && typeof groups[0] === 'undefined';
                }());

                if (!replaceReportsGroupsCorrectly) {
                    StringPrototype.replace = function replace(searchValue, replaceValue) {
                        var isFn = isCallable(replaceValue);
                        var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
                        if (!isFn || !hasCapturingGroups) {
                            return str_replace.call(this, searchValue, replaceValue);
                        } else {
                            var wrappedReplaceValue = function (match) {
                                var length = arguments.length;
                                var originalLastIndex = searchValue.lastIndex;
                                searchValue.lastIndex = 0;
                                var args = searchValue.exec(match) || [];
                                searchValue.lastIndex = originalLastIndex;
                                push(args, arguments[length - 2], arguments[length - 1]);
                                return replaceValue.apply(this, args);
                            };
                            return str_replace.call(this, searchValue, wrappedReplaceValue);
                        }
                    };
                }

// ECMA-262, 3rd B.2.3
// Not an ECMAScript standard, although ECMAScript 3rd Edition has a
// non-normative section suggesting uniform semantics and it should be
// normalized across all browsers
// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
                var string_substr = StringPrototype.substr;
                var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b';
                defineProperties(StringPrototype, {
                    substr: function substr(start, length) {
                        var normalizedStart = start;
                        if (start < 0) {
                            normalizedStart = max(this.length + start, 0);
                        }
                        return string_substr.call(this, normalizedStart, length);
                    }
                }, hasNegativeSubstrBug);

// ES5 15.5.4.20
// whitespace from: http://es5.github.io/#x15.5.4.20
                var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
                    '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' +
                    '\u2029\uFEFF';
                var zeroWidth = '\u200b';
                var wsRegexChars = '[' + ws + ']';
                var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*');
                var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$');
                var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
                defineProperties(StringPrototype, {
                    // http://blog.stevenlevithan.com/archives/faster-trim-javascript
                    // http://perfectionkills.com/whitespace-deviations/
                    trim: function trim() {
                        if (typeof this === 'undefined' || this === null) {
                            throw new TypeError("can't convert " + this + ' to object');
                        }
                        return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
                    }
                }, hasTrimWhitespaceBug);

                var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1;
                defineProperties(StringPrototype, {
                    lastIndexOf: function lastIndexOf(searchString) {
                        if (typeof this === 'undefined' || this === null) {
                            throw new TypeError("can't convert " + this + ' to object');
                        }
                        var S = $String(this);
                        var searchStr = $String(searchString);
                        var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN;
                        var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos);
                        var start = min(max(pos, 0), S.length);
                        var searchLen = searchStr.length;
                        var k = start + searchLen;
                        while (k > 0) {
                            k = max(0, k - searchLen);
                            var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr);
                            if (index !== -1) {
                                return k + index;
                            }
                        }
                        return -1;
                    }
                }, hasLastIndexBug);

                var originalLastIndexOf = StringPrototype.lastIndexOf;
                defineProperties(StringPrototype, {
                    lastIndexOf: function lastIndexOf(searchString) {
                        return originalLastIndexOf.apply(this, arguments);
                    }
                }, StringPrototype.lastIndexOf.length !== 1);

// ES-5 15.1.2.2
                /* eslint-disable radix */
                if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
                    /* eslint-enable radix */
                    /* global parseInt: true */
                    parseInt = (function (origParseInt) {
                        var hexRegex = /^[\-+]?0[xX]/;
                        return function parseInt(str, radix) {
                            var string = $String(str).trim();
                            var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10);
                            return origParseInt(string, defaultedRadix);
                        };
                    }(parseInt));
                }

                if (String(new RangeError('test')) !== 'RangeError: test') {
                    var errorToStringShim = function toString() {
                        if (typeof this === 'undefined' || this === null) {
                            throw new TypeError("can't convert " + this + ' to object');
                        }
                        var name = this.name;
                        if (typeof name === 'undefined') {
                            name = 'Error';
                        } else if (typeof name !== 'string') {
                            name = $String(name);
                        }
                        var msg = this.message;
                        if (typeof msg === 'undefined') {
                            msg = '';
                        } else if (typeof msg !== 'string') {
                            msg = $String(msg);
                        }
                        if (!name) {
                            return msg;
                        }
                        if (!msg) {
                            return name;
                        }
                        return name + ': ' + msg;
                    };
                    // can't use defineProperties here because of toString enumeration issue in IE <= 8
                    Error.prototype.toString = errorToStringShim;
                }

                if (supportsDescriptors) {
                    var ensureNonEnumerable = function (obj, prop) {
                        if (isEnum(obj, prop)) {
                            var desc = Object.getOwnPropertyDescriptor(obj, prop);
                            desc.enumerable = false;
                            Object.defineProperty(obj, prop, desc);
                        }
                    };
                    ensureNonEnumerable(Error.prototype, 'message');
                    if (Error.prototype.message !== '') {
                        Error.prototype.message = '';
                    }
                    ensureNonEnumerable(Error.prototype, 'name');
                }

                if (String(/a/mig) !== '/a/gim') {
                    var regexToString = function toString() {
                        var str = '/' + this.source + '/';
                        if (this.global) {
                            str += 'g';
                        }
                        if (this.ignoreCase) {
                            str += 'i';
                        }
                        if (this.multiline) {
                            str += 'm';
                        }
                        return str;
                    };
                    // can't use defineProperties here because of toString enumeration issue in IE <= 8
                    RegExp.prototype.toString = regexToString;
                }

            }));

        }, {}],
        26: [function (_dereq_, module, exports) {
            var arr = [];
            var each = arr.forEach;
            var slice = arr.slice;


            module.exports = function (obj) {
                each.call(slice.call(arguments, 1), function (source) {
                    if (source) {
                        for (var prop in source) {
                            obj[prop] = source[prop];
                        }
                    }
                });
                return obj;
            };

        }, {}],
        27: [function (_dereq_, module, exports) {
            module.exports = isFunction

            var toString = Object.prototype.toString

            function isFunction(fn) {
                var string = toString.call(fn)
                return string === '[object Function]' ||
                    (typeof fn === 'function' && string !== '[object RegExp]') ||
                    (typeof window !== 'undefined' &&
                        // IE8 and below
                        (fn === window.setTimeout ||
                            fn === window.alert ||
                            fn === window.confirm ||
                            fn === window.prompt))
            };

        }, {}],
        28: [function (_dereq_, module, exports) {
            "use strict";

            module.exports = function isObject(x) {
                return typeof x === "object" && x !== null;
            };

        }, {}],
        29: [function (_dereq_, module, exports) {
            /*!
  * $script.js JS loader & dependency manager
  * https://github.com/ded/script.js
  * (c) Dustin Diaz 2014 | License MIT
  */

            (function (name, definition) {
                if (typeof module != 'undefined' && module.exports) module.exports = definition()
                else if (typeof define == 'function' && define.amd) define(definition)
                else this[name] = definition()
            })('$script', function () {
                var doc = document
                    , head = doc.getElementsByTagName('head')[0]
                    , s = 'string'
                    , f = false
                    , push = 'push'
                    , readyState = 'readyState'
                    , onreadystatechange = 'onreadystatechange'
                    , list = {}
                    , ids = {}
                    , delay = {}
                    , scripts = {}
                    , scriptpath
                    , urlArgs

                function every(ar, fn) {
                    for (var i = 0, j = ar.length; i < j; ++i) if (!fn(ar[i])) return f
                    return 1
                }

                function each(ar, fn) {
                    every(ar, function (el) {
                        return !fn(el)
                    })
                }

                function $script(paths, idOrDone, optDone) {
                    paths = paths[push] ? paths : [paths]
                    var idOrDoneIsDone = idOrDone && idOrDone.call
                        , done = idOrDoneIsDone ? idOrDone : optDone
                        , id = idOrDoneIsDone ? paths.join('') : idOrDone
                        , queue = paths.length

                    function loopFn(item) {
                        return item.call ? item() : list[item]
                    }

                    function callback() {
                        if (!--queue) {
                            list[id] = 1
                            done && done()
                            for (var dset in delay) {
                                every(dset.split('|'), loopFn) && !each(delay[dset], loopFn) && (delay[dset] = [])
                            }
                        }
                    }

                    setTimeout(function () {
                        each(paths, function loading(path, force) {
                            if (path === null) return callback()

                            if (!force && !/^https?:\/\//.test(path) && scriptpath) {
                                path = (path.indexOf('.js') === -1) ? scriptpath + path + '.js' : scriptpath + path;
                            }

                            if (scripts[path]) {
                                if (id) ids[id] = 1
                                return (scripts[path] == 2) ? callback() : setTimeout(function () {
                                    loading(path, true)
                                }, 0)
                            }

                            scripts[path] = 1
                            if (id) ids[id] = 1
                            create(path, callback)
                        })
                    }, 0)
                    return $script
                }

                function create(path, fn) {
                    var el = doc.createElement('script'), loaded
                    el.onload = el.onerror = el[onreadystatechange] = function () {
                        if ((el[readyState] && !(/^c|loade/.test(el[readyState]))) || loaded) return;
                        el.onload = el[onreadystatechange] = null
                        loaded = 1
                        scripts[path] = 2
                        fn()
                    }
                    el.async = 1
                    el.src = urlArgs ? path + (path.indexOf('?') === -1 ? '?' : '&') + urlArgs : path;
                    head.insertBefore(el, head.lastChild)
                }

                $script.get = create

                $script.order = function (scripts, id, done) {
                    (function callback(s) {
                        s = scripts.shift()
                        !scripts.length ? $script(s, id, done) : $script(s, callback)
                    }())
                }

                $script.path = function (p) {
                    scriptpath = p
                }
                $script.urlArgs = function (str) {
                    urlArgs = str;
                }
                $script.ready = function (deps, ready, req) {
                    deps = deps[push] ? deps : [deps]
                    var missing = [];
                    !each(deps, function (dep) {
                        list[dep] || missing[push](dep);
                    }) && every(deps, function (dep) {
                        return list[dep]
                    }) ?
                        ready() : !function (key) {
                            delay[key] = delay[key] || []
                            delay[key][push](ready)
                            req && req(missing)
                        }(deps.join('|'))
                    return $script
                }

                $script.done = function (idOrDone) {
                    $script([null], idOrDone)
                }

                return $script
            });

        }, {}]
    }, {}, [19])(19)
});
