diff -r 000000000000 -r fd39db613f8b src/pyams_media/skin/resources/flowplayer/flowplayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_media/skin/resources/flowplayer/flowplayer.js Wed Sep 02 15:31:55 2015 +0200 @@ -0,0 +1,6697 @@ +/*! + + Flowplayer v6.0.3 (Thursday, 23. July 2015 09:32PM) | flowplayer.org/license + +*/ +/*! (C) WebReflection Mit Style License */ +(function(e){function m(e,t,n,r){for(var i,s=n.slice(),o=b(t,e),u=0,a=s.length;u' + innerHTML + '').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){ +/* global __flash_unloadHandler:true,__flash_savedUnloadHandler:true */ +'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 = ' -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 += ''; + }); + + tag += ""; + var el = common.createElement('div', {}, tag); + return common.find('object', el); + +}; + + +// Flash is buggy allover +if (window.attachEvent) { + window.attachEvent("onbeforeunload", function() { + __flash_savedUnloadHandler = __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) { + + 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 + } + }, + + load: function(video) { + loadVideo = video; + + function escapeURL(url) { + return url.replace(/&/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D'); + } + + var html5Tag = common.findDirect('video', root)[0] || common.find('.fp-player > video', root)[0], + url = escapeURL(video.src), + is_absolute = /^https?:/.test(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); + + 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); + } + + // issue #733 + var 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); + + 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 (name == 'seek' && player.video.time && !player.paused) { + player.trigger("beforeseek"); + } + + 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); + +},{"../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; + 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) { + 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]; + } + } + }, + + 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; + + 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); + api = 0; + } + + }; + + 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); + }); + + Object.keys(EVENTS).forEach(function(type) { + var flow = EVENTS[type]; + if (!flow) return; + root.addEventListener(type, 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 = !conf.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 (!conf.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(); + + + }, true); + + }); + + } + +}; + + +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() { + 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 + cue; + + 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(); + player.seek(time); + + // preventDefault() doesn't work + return false; + }); + } + 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'}, ''), + 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 ''; + } + 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.3/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 'Watch video!\n'.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); + 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() { + bean.off(document, '.ffscr'); + 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 ? + '

shift + slower / faster

' : ''; + + // TODO: add to player-layout.html + root.appendChild(common.createElement('div', { className: 'fp-help' }, '\ + \ +
\ +

spaceplay / pause

\ +

qunload | stop

\ +

ffullscreen

' + speedhelp + '\ +
\ +
\ +

volume

\ +

mmute

\ +
\ +
\ +

seek

\ +

 . seek to previous\ +

126 seek to 10%, 20% … 60%

\ +
\ + ')); + + 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[0]; + } + + if (els().length && !playlistInitialized) { //generate playlist from existing elements + player.conf.playlist = []; + 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 + 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 = video.index || player.video.index || 0, + 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 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 = "

" + lines[++i] + "


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

" + lines[i] + "


"; + + // 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]; + 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'] + })); + }); + setMode('disabled'); + setMode('showing'); + 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'}, '\ +
\ + \ + \ +

\ +
\ + \ +
\ +
\ +
\ +
\ +
\ +
\ + \ +
\ +
\ +
\ +
\ +
\ +
\ + 00:00\ + \ + 00:00\ +
\ +

'.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, "

loading …

"); + + 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) 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.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, + t = ev.clientY - (o.top + w.scrollY); + 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', 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 && !conf.autoplay) { + + api.on("ready stop", function() { + rootClasses.add("is-poster"); + api.one("progress", function() { + rootClasses.remove("is-poster"); + }); + }); + + } + + 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.3', + + 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.3/flowplayer.swf", + swfHls: "//releases.flowplayer.org/6.0.3/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) { + video.src = common.createElement('a', {href: video.src}).href; + 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).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"); + }); + } + return api; + }, + + unload: function() { + if (!rootClasses.contains("is-embedding")) { + + if (conf.splash) { + api.trigger("unload", [api]); + if (engine) engine.unload(); + } else { + api.stop(); + } + } + return api; + }, + + shutdown: function() { + api.unload(); + api.trigger('shutdown', [api]); + bean.off(root); + delete instances[root.getAttribute('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"),s=d?a(d):t.hostname(),p=(document,l.key);"file:"==location.protocol&&(s="localhost"),e.load.ed=1,l.hostname=s,l.origin=d||location.href,d&&n(o,"is-embedded"),"string"==typeof p&&(p=p.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(p&&"function"==typeof key_check&&key_check(p,s)){if(l.logo){var c=i("a",{href:d,className:"fp-logo"});l.embed&&l.embed.popup&&(c.target="_blank");var h=i("img",{src:l.logo});c.appendChild(h),o.appendChild(c)}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 c=i("a",{href:"http://flowplayer.org"});o.appendChild(c);var y=i("div",{className:"fp-context-menu"},''),u=window.location.href.indexOf("localhost"),m=t.find(".fp-player",o)[0];7!==u&&(m||o).appendChild(y),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"]],i=0;i 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 + * @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 state to , + // 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 + * @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/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 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 defineProperties = (function (has) { + 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; + } + }()); + + // 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 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 (n !== n) { // isNaN + 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) { + /* jshint eqnull: true */ + 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 +// us it in defining shortcuts. +var owns = call.bind(ObjectPrototype.hasOwnProperty); +var toStr = call.bind(ObjectPrototype.toString); +var strSlice = call.bind(StringPrototype.slice); +var strSplit = call.bind(StringPrototype.split); + +// +// 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 = self.length >>> 0; + 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.call(T, self[i], i, object); + } else { + callbackfn(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 = self.length >>> 0; + 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.call(T, self[i], i, object); + } else { + result[i] = callbackfn(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 = self.length >>> 0; + 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)) { + array_push.call(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 = self.length >>> 0; + 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 = self.length >>> 0; + 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 = self.length >>> 0; + + // 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 = self.length >>> 0; + + // 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 = self.length >>> 0; + + 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 = self.length >>> 0; + + 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 = array_slice.call(arguments); + if (args.length < 2) { + array_push.call(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 = array_slice.call(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); + +// +// 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, + $frames: true, + $frameElement: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true +}; +var hasAutomationEqualityBug = (function () { + /* globals window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + if (!blacklistedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + 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; + +var isArguments = function isArguments(value) { + var str = toStr(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = !isArray(value) && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + isCallable(value.callee); + } + return isArgs; +}; + +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) { + array_push.call(theKeys, $String(i)); + } + } + + if (!isArgs) { + for (var name in object) { + if (!(skipProto && name === 'prototype') && owns(object, name)) { + array_push.call(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)) { + array_push.call(theKeys, dontEnum); + } + } + } + return theKeys; + } +}); + +var keysWorksWithArguments = $Object.keys && (function () { + // Safari 5.0 bug + return $Object.keys(arguments).length === 2; +}(1, 2)); +var originalKeys = $Object.keys; +defineProperties($Object, { + keys: function keys(object) { + if (isArguments(object)) { + return originalKeys(array_slice.call(object)); + } else { + return originalKeys(object); + } + } +}, !keysWorksWithArguments); + +// +// 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 + '-' + array_slice.call(result, 0, 2).join('-') + + 'T' + array_slice.call(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 (!Date.parse || 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 */ + 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) { + 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, s, ms) : + length >= 6 ? new NativeDate(Y, M, D, h, m, s) : + 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); + } + // 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) { + return $Number(new NativeDate(1970, 0, 1, 0, 0, 0, t)); + }; + + // 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; + if ( + hour < ( + minute > 0 || second > 0 || millisecond > 0 ? + 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; + } +}; + +defineProperties(NumberPrototype, { + toFixed: function toFixed(fractionDigits) { + var f, x, s, m, e, z, j, k; + + // Test for NaN and round fractionDigits down + f = $Number(fractionDigits); + f = f !== f ? 0 : Math.floor(f); + + if (f < 0 || f > 20) { + throw new RangeError('Number.toFixed called with invalid number of decimals'); + } + + x = $Number(this); + + // Test for NaN + if (x !== 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; + } +}, hasToFixedBugs); + +// +// 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 + + StringPrototype.split = function (separator, limit) { + var 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'); + string += ''; // Type-convert + 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 // Math.pow(2, 32) - 1 + * 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' ? + -1 >>> 0 : // Math.pow(2, 32) - 1 + 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) { + array_push.call(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, array_slice.call(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('')) { + array_push.call(output, ''); + } + } else { + array_push.call(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) { + array_push.call(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; + array_push.call(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); + +// ES-5 15.1.2.2 +if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { + /* 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)); +} + +})); + +},{}],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() + path = !force && path.indexOf('.js') === -1 && !/^https?:\/\//.test(path) && scriptpath ? scriptpath + path + '.js' : 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) +});