/*!
 *
 * MediaElement.js
 * HTML5 <video> and <audio> shim and player
 * http://mediaelementjs.com/
 *
 * Creates a JavaScript object that mimics HTML5 MediaElement API
 * for browsers that don't understand HTML5 or can't play the provided codec
 * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
 *
 * Copyright 2010-2014, John Dyer (http://j.hn)
 * License: MIT
 *
 */
// Namespace
var mejs = mejs || {};

// version number
mejs.version = '2.22.0';


// player number (for missing, same id attr)
mejs.meIndex = 0;

// media types accepted by plugins
mejs.plugins = {
    silverlight: [
        {version: [3, 0], types: ['video/mp4', 'video/m4v', 'video/mov', 'video/wmv', 'audio/wma', 'audio/m4a', 'audio/mp3', 'audio/wav', 'audio/mpeg']}
    ],
    flash: [
        {
            version: [9, 0, 124],
            types: ['video/mp4', 'video/m4v', 'video/mov', 'video/flv', 'video/rtmp', 'video/x-flv', 'audio/flv', 'audio/x-flv', 'audio/mp3', 'audio/m4a', 'audio/mpeg', 'video/dailymotion', 'video/x-dailymotion', 'application/x-mpegURL']
        }
        // 'video/youtube', 'video/x-youtube', 
        // ,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
    ],
    youtube: [
        {version: null, types: ['video/youtube', 'video/x-youtube', 'audio/youtube', 'audio/x-youtube']}
    ],
    vimeo: [
        {version: null, types: ['video/vimeo', 'video/x-vimeo']}
    ]
};

/*
Utility methods
*/
mejs.Utility = {
    encodeUrl: function (url) {
        return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
    },
    escapeHTML: function (s) {
        return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
    },
    absolutizeUrl: function (url) {
        var el = document.createElement('div');
        el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
        return el.firstChild.href;
    },
    getScriptPath: function (scriptNames) {
        var
            i = 0,
            j,
            codePath = '',
            testname = '',
            slashPos,
            filenamePos,
            scriptUrl,
            scriptPath,
            scriptFilename,
            scripts = document.getElementsByTagName('script'),
            il = scripts.length,
            jl = scriptNames.length;

        // go through all <script> tags
        for (; i < il; i++) {
            scriptUrl = scripts[i].src;
            slashPos = scriptUrl.lastIndexOf('/');
            if (slashPos > -1) {
                scriptFilename = scriptUrl.substring(slashPos + 1);
                scriptPath = scriptUrl.substring(0, slashPos + 1);
            } else {
                scriptFilename = scriptUrl;
                scriptPath = '';
            }

            // see if any <script> tags have a file name that matches the 
            for (j = 0; j < jl; j++) {
                testname = scriptNames[j];
                filenamePos = scriptFilename.indexOf(testname);
                if (filenamePos > -1) {
                    codePath = scriptPath;
                    break;
                }
            }

            // if we found a path, then break and return it
            if (codePath !== '') {
                break;
            }
        }

        // send the best path back
        return codePath;
    },
    /*
     * Calculate the time format to use. We have a default format set in the
     * options but it can be imcomplete. We ajust it according to the media
     * duration.
     *
     * We support format like 'hh:mm:ss:ff'.
     */
    calculateTimeFormat: function (time, options, fps) {
        if (time < 0) {
            time = 0;
        }

        if (typeof fps == 'undefined') {
            fps = 25;
        }

        var format = options.timeFormat,
            firstChar = format[0],
            firstTwoPlaces = (format[1] == format[0]),
            separatorIndex = firstTwoPlaces ? 2 : 1,
            separator = ':',
            hours = Math.floor(time / 3600) % 24,
            minutes = Math.floor(time / 60) % 60,
            seconds = Math.floor(time % 60),
            frames = Math.floor(((time % 1) * fps).toFixed(3)),
            lis = [
                [frames, 'f'],
                [seconds, 's'],
                [minutes, 'm'],
                [hours, 'h']
            ];

        // Try to get the separator from the format
        if (format.length < separatorIndex) {
            separator = format[separatorIndex];
        }

        var required = false;

        for (var i = 0, len = lis.length; i < len; i++) {
            if (format.indexOf(lis[i][1]) !== -1) {
                required = true;
            }
            else if (required) {
                var hasNextValue = false;
                for (var j = i; j < len; j++) {
                    if (lis[j][0] > 0) {
                        hasNextValue = true;
                        break;
                    }
                }

                if (!hasNextValue) {
                    break;
                }

                if (!firstTwoPlaces) {
                    format = firstChar + format;
                }
                format = lis[i][1] + separator + format;
                if (firstTwoPlaces) {
                    format = lis[i][1] + format;
                }
                firstChar = lis[i][1];
            }
        }
        options.currentTimeFormat = format;
    },
    /*
     * Prefix the given number by zero if it is lower than 10.
     */
    twoDigitsString: function (n) {
        if (n < 10) {
            return '0' + n;
        }
        return String(n);
    },
    secondsToTimeCode: function (time, options) {
        if (time < 0) {
            time = 0;
        }

        // Maintain backward compatibility with method signature before v2.18.
        if (typeof options !== 'object') {
            var format = 'm:ss';
            format = arguments[1] ? 'hh:mm:ss' : format; // forceHours
            format = arguments[2] ? format + ':ff' : format; // showFrameCount

            options = {
                currentTimeFormat: format,
                framesPerSecond: arguments[3] || 25
            };
        }

        var fps = options.framesPerSecond;
        if (typeof fps === 'undefined') {
            fps = 25;
        }

        var format = options.currentTimeFormat,
            hours = Math.floor(time / 3600) % 24,
            minutes = Math.floor(time / 60) % 60,
            seconds = Math.floor(time % 60),
            frames = Math.floor(((time % 1) * fps).toFixed(3));
        lis = [
            [frames, 'f'],
            [seconds, 's'],
            [minutes, 'm'],
            [hours, 'h']
        ];

        var res = format;
        for (i = 0, len = lis.length; i < len; i++) {
            res = res.replace(lis[i][1] + lis[i][1], this.twoDigitsString(lis[i][0]));
            res = res.replace(lis[i][1], lis[i][0]);
        }
        return res;
    },

    timeCodeToSeconds: function (hh_mm_ss_ff, forceHours, showFrameCount, fps) {
        if (typeof showFrameCount == 'undefined') {
            showFrameCount = false;
        } else if (typeof fps == 'undefined') {
            fps = 25;
        }

        var tc_array = hh_mm_ss_ff.split(":"),
            tc_hh = parseInt(tc_array[0], 10),
            tc_mm = parseInt(tc_array[1], 10),
            tc_ss = parseInt(tc_array[2], 10),
            tc_ff = 0,
            tc_in_seconds = 0;

        if (showFrameCount) {
            tc_ff = parseInt(tc_array[3]) / fps;
        }

        tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;

        return tc_in_seconds;
    },


    convertSMPTEtoSeconds: function (SMPTE) {
        if (typeof SMPTE != 'string')
            return false;

        SMPTE = SMPTE.replace(',', '.');

        var secs = 0,
            decimalLen = (SMPTE.indexOf('.') != -1) ? SMPTE.split('.')[1].length : 0,
            multiplier = 1;

        SMPTE = SMPTE.split(':').reverse();

        for (var i = 0; i < SMPTE.length; i++) {
            multiplier = 1;
            if (i > 0) {
                multiplier = Math.pow(60, i);
            }
            secs += Number(SMPTE[i]) * multiplier;
        }
        return Number(secs.toFixed(decimalLen));
    },

    /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
    removeSwf: function (id) {
        var obj = document.getElementById(id);
        if (obj && /object|embed/i.test(obj.nodeName)) {
            if (mejs.MediaFeatures.isIE) {
                obj.style.display = "none";
                (function () {
                    if (obj.readyState == 4) {
                        mejs.Utility.removeObjectInIE(id);
                    } else {
                        setTimeout(arguments.callee, 10);
                    }
                })();
            } else {
                obj.parentNode.removeChild(obj);
            }
        }
    },
    removeObjectInIE: function (id) {
        var obj = document.getElementById(id);
        if (obj) {
            for (var i in obj) {
                if (typeof obj[i] == "function") {
                    obj[i] = null;
                }
            }
            obj.parentNode.removeChild(obj);
        }
    },
    determineScheme: function (url) {
        if (url && url.indexOf("://") != -1) {
            return url.substr(0, url.indexOf("://") + 3);
        }
        return "//"; // let user agent figure this out
    }
};


// Core detector, plugins are added below
mejs.PluginDetector = {

    // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
    hasPluginVersion: function (plugin, v) {
        var pv = this.plugins[plugin];
        v[1] = v[1] || 0;
        v[2] = v[2] || 0;
        return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
    },

    // cached values
    nav: window.navigator,
    ua: window.navigator.userAgent.toLowerCase(),

    // stored version numbers
    plugins: [],

    // runs detectPlugin() and stores the version number
    addPlugin: function (p, pluginName, mimeType, activeX, axDetect) {
        this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
    },

    // get the version number from the mimetype (all but IE) or ActiveX (IE)
    detectPlugin: function (pluginName, mimeType, activeX, axDetect) {

        var version = [0, 0, 0],
            description,
            i,
            ax;

        // Firefox, Webkit, Opera
        if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
            description = this.nav.plugins[pluginName].description;
            if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
                version = description.replace(pluginName, '').replace(/^\s+/, '').replace(/\sr/gi, '.').split('.');
                for (i = 0; i < version.length; i++) {
                    version[i] = parseInt(version[i].match(/\d+/), 10);
                }
            }
            // Internet Explorer / ActiveX
        } else if (typeof(window.ActiveXObject) != 'undefined') {
            try {
                ax = new ActiveXObject(activeX);
                if (ax) {
                    version = axDetect(ax);
                }
            }
            catch (e) {
            }
        }
        return version;
    }
};

// Add Flash detection
mejs.PluginDetector.addPlugin('flash', 'Shockwave Flash', 'application/x-shockwave-flash', 'ShockwaveFlash.ShockwaveFlash', function (ax) {
    // adapted from SWFObject
    var version = [],
        d = ax.GetVariable("$version");
    if (d) {
        d = d.split(" ")[1].split(",");
        version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
    }
    return version;
});

// Add Silverlight detection
mejs.PluginDetector.addPlugin('silverlight', 'Silverlight Plug-In', 'application/x-silverlight-2', 'AgControl.AgControl', function (ax) {
    // Silverlight cannot report its version number to IE
    // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
    // adapted from http://www.silverlightversion.com/
    var v = [0, 0, 0, 0],
        loopMatch = function (ax, v, i, n) {
            while (ax.isVersionSupported(v[0] + "." + v[1] + "." + v[2] + "." + v[3])) {
                v[i] += n;
            }
            v[i] -= n;
        };
    loopMatch(ax, v, 0, 1);
    loopMatch(ax, v, 1, 1);
    loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
    loopMatch(ax, v, 2, 1000);
    loopMatch(ax, v, 2, 100);
    loopMatch(ax, v, 2, 10);
    loopMatch(ax, v, 2, 1);
    loopMatch(ax, v, 3, 1);

    return v;
});
// add adobe acrobat
/*
PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
	var version = [],
		d = ax.GetVersions().split(',')[0].split('=')[1].split('.');

	if (d) {
		version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
	}
	return version;
});
*/
// necessary detection (fixes for <IE9)
mejs.MediaFeatures = {
    init: function () {
        var
            t = this,
            d = document,
            nav = mejs.PluginDetector.nav,
            ua = mejs.PluginDetector.ua.toLowerCase(),
            i,
            v,
            html5Elements = ['source', 'track', 'audio', 'video'];

        // detect browsers (only the ones that have some kind of quirk we need to work around)
        t.isiPad = (ua.match(/ipad/i) !== null);
        t.isiPhone = (ua.match(/iphone/i) !== null);
        t.isiOS = t.isiPhone || t.isiPad;
        t.isAndroid = (ua.match(/android/i) !== null);
        t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
        t.isBustedNativeHTTPS = (location.protocol === 'https:' && (ua.match(/android [12]\./) !== null || ua.match(/macintosh.* version.* safari/) !== null));
        t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1 || nav.appName.toLowerCase().match(/trident/gi) !== null);
        t.isChrome = (ua.match(/chrome/gi) !== null);
        t.isChromium = (ua.match(/chromium/gi) !== null);
        t.isFirefox = (ua.match(/firefox/gi) !== null);
        t.isWebkit = (ua.match(/webkit/gi) !== null);
        t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit && !t.isIE;
        t.isOpera = (ua.match(/opera/gi) !== null);
        t.hasTouch = ('ontouchstart' in window); //  && window.ontouchstart != null); // this breaks iOS 7

        // Borrowed from `Modernizr.svgasimg`, sources:
        // - https://github.com/Modernizr/Modernizr/issues/687
        // - https://github.com/Modernizr/Modernizr/pull/1209/files
        t.svgAsImg = !!document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1');

        // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
        for (i = 0; i < html5Elements.length; i++) {
            v = document.createElement(html5Elements[i]);
        }

        t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);

        // Fix for IE9 on Windows 7N / Windows 7KN (Media Player not installer)
        try {
            v.canPlayType("video/mp4");
        } catch (e) {
            t.supportsMediaTag = false;
        }

        t.supportsPointerEvents = (function () {
            // TAKEN FROM MODERNIZR
            var element = document.createElement('x'),
                documentElement = document.documentElement,
                getComputedStyle = window.getComputedStyle,
                supports;
            if (!('pointerEvents' in element.style)) {
                return false;
            }
            element.style.pointerEvents = 'auto';
            element.style.pointerEvents = 'x';
            documentElement.appendChild(element);
            supports = getComputedStyle &&
                getComputedStyle(element, '').pointerEvents === 'auto';
            documentElement.removeChild(element);
            return !!supports;
        })();


        // Older versions of Firefox can't move plugins around without it resetting,
        t.hasFirefoxPluginMovingProblem = false;

        // detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)

        // iOS
        t.hasiOSFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');

        // W3C
        t.hasNativeFullscreen = (typeof v.requestFullscreen !== 'undefined');

        // webkit/firefox/IE11+
        t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
        t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
        t.hasMsNativeFullScreen = (typeof v.msRequestFullscreen !== 'undefined');

        t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen || t.hasMsNativeFullScreen);
        t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;

        // Enabled?
        if (t.hasMozNativeFullScreen) {
            t.nativeFullScreenEnabled = document.mozFullScreenEnabled;
        } else if (t.hasMsNativeFullScreen) {
            t.nativeFullScreenEnabled = document.msFullscreenEnabled;
        }

        if (t.isChrome) {
            t.hasiOSFullScreen = false;
        }

        if (t.hasTrueNativeFullScreen) {

            t.fullScreenEventName = '';
            if (t.hasWebkitNativeFullScreen) {
                t.fullScreenEventName = 'webkitfullscreenchange';

            } else if (t.hasMozNativeFullScreen) {
                t.fullScreenEventName = 'mozfullscreenchange';

            } else if (t.hasMsNativeFullScreen) {
                t.fullScreenEventName = 'MSFullscreenChange';
            }

            t.isFullScreen = function () {
                if (t.hasMozNativeFullScreen) {
                    return d.mozFullScreen;

                } else if (t.hasWebkitNativeFullScreen) {
                    return d.webkitIsFullScreen;

                } else if (t.hasMsNativeFullScreen) {
                    return d.msFullscreenElement !== null;
                }
            }

            t.requestFullScreen = function (el) {

                if (t.hasWebkitNativeFullScreen) {
                    el.webkitRequestFullScreen();

                } else if (t.hasMozNativeFullScreen) {
                    el.mozRequestFullScreen();

                } else if (t.hasMsNativeFullScreen) {
                    el.msRequestFullscreen();

                }
            }

            t.cancelFullScreen = function () {
                if (t.hasWebkitNativeFullScreen) {
                    document.webkitCancelFullScreen();

                } else if (t.hasMozNativeFullScreen) {
                    document.mozCancelFullScreen();

                } else if (t.hasMsNativeFullScreen) {
                    document.msExitFullscreen();

                }
            }

        }


        // OS X 10.5 can't do this even if it says it can :(
        if (t.hasiOSFullScreen && ua.match(/mac os x 10_5/i)) {
            t.hasNativeFullScreen = false;
            t.hasiOSFullScreen = false;
        }

    }
};
mejs.MediaFeatures.init();

/*
extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
*/
mejs.HtmlMediaElement = {
    pluginType: 'native',
    isFullScreen: false,

    setCurrentTime: function (time) {
        this.currentTime = time;
    },

    setMuted: function (muted) {
        this.muted = muted;
    },

    setVolume: function (volume) {
        this.volume = volume;
    },

    // for parity with the plugin versions
    stop: function () {
        this.pause();
    },

    // This can be a url string
    // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
    setSrc: function (url) {

        // Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
        var
            existingSources = this.getElementsByTagName('source');
        while (existingSources.length > 0) {
            this.removeChild(existingSources[0]);
        }

        if (typeof url == 'string') {
            this.src = url;
        } else {
            var i, media;

            for (i = 0; i < url.length; i++) {
                media = url[i];
                if (this.canPlayType(media.type)) {
                    this.src = media.src;
                    break;
                }
            }
        }
    },

    setVideoSize: function (width, height) {
        this.width = width;
        this.height = height;
    }
};

/*
Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
*/
mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
    this.id = pluginid;
    this.pluginType = pluginType;
    this.src = mediaUrl;
    this.events = {};
    this.attributes = {};
};

// JavaScript values and ExternalInterface methods that match HTML5 video properties methods
// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
mejs.PluginMediaElement.prototype = {

    // special
    pluginElement: null,
    pluginType: '',
    isFullScreen: false,

    // not implemented :(
    playbackRate: -1,
    defaultPlaybackRate: -1,
    seekable: [],
    played: [],

    // HTML5 read-only properties
    paused: true,
    ended: false,
    seeking: false,
    duration: 0,
    error: null,
    tagName: '',

    // HTML5 get/set properties, but only set (updated by event handlers)
    muted: false,
    volume: 1,
    currentTime: 0,

    // HTML5 methods
    play: function () {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') {
                this.pluginApi.playVideo();
            } else {
                this.pluginApi.playMedia();
            }
            this.paused = false;
        }
    },
    load: function () {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') {
            } else {
                this.pluginApi.loadMedia();
            }

            this.paused = false;
        }
    },
    pause: function () {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') {
                if (this.pluginApi.getPlayerState() == 1) {
                    this.pluginApi.pauseVideo();
                }
            } else {
                this.pluginApi.pauseMedia();
            }


            this.paused = true;
        }
    },
    stop: function () {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') {
                this.pluginApi.stopVideo();
            } else {
                this.pluginApi.stopMedia();
            }
            this.paused = true;
        }
    },
    canPlayType: function (type) {
        var i,
            j,
            pluginInfo,
            pluginVersions = mejs.plugins[this.pluginType];

        for (i = 0; i < pluginVersions.length; i++) {
            pluginInfo = pluginVersions[i];

            // test if user has the correct plugin version
            if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {

                // test for plugin playback types
                for (j = 0; j < pluginInfo.types.length; j++) {
                    // find plugin that can play the type
                    if (type == pluginInfo.types[j]) {
                        return 'probably';
                    }
                }
            }
        }

        return '';
    },

    positionFullscreenButton: function (x, y, visibleAndAbove) {
        if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
            this.pluginApi.positionFullscreenButton(Math.floor(x), Math.floor(y), visibleAndAbove);
        }
    },

    hideFullscreenButton: function () {
        if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
            this.pluginApi.hideFullscreenButton();
        }
    },


    // custom methods since not all JavaScript implementations support get/set

    // This can be a url string
    // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
    setSrc: function (url) {
        if (typeof url == 'string') {
            this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
            this.src = mejs.Utility.absolutizeUrl(url);
        } else {
            var i, media;

            for (i = 0; i < url.length; i++) {
                media = url[i];
                if (this.canPlayType(media.type)) {
                    this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
                    this.src = mejs.Utility.absolutizeUrl(media.src);
                    break;
                }
            }
        }

    },
    setCurrentTime: function (time) {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') {
                this.pluginApi.seekTo(time);
            } else {
                this.pluginApi.setCurrentTime(time);
            }


            this.currentTime = time;
        }
    },
    setVolume: function (volume) {
        if (this.pluginApi != null) {
            // same on YouTube and MEjs
            if (this.pluginType == 'youtube') {
                this.pluginApi.setVolume(volume * 100);
            } else {
                this.pluginApi.setVolume(volume);
            }
            this.volume = volume;
        }
    },
    setMuted: function (muted) {
        if (this.pluginApi != null) {
            if (this.pluginType == 'youtube') {
                if (muted) {
                    this.pluginApi.mute();
                } else {
                    this.pluginApi.unMute();
                }
                this.muted = muted;
                this.dispatchEvent({type: 'volumechange'});
            } else {
                this.pluginApi.setMuted(muted);
            }
            this.muted = muted;
        }
    },

    // additional non-HTML5 methods
    setVideoSize: function (width, height) {

        //if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
        if (this.pluginElement && this.pluginElement.style) {
            this.pluginElement.style.width = width + 'px';
            this.pluginElement.style.height = height + 'px';
        }
        if (this.pluginApi != null && this.pluginApi.setVideoSize) {
            this.pluginApi.setVideoSize(width, height);
        }
        //}
    },

    setFullscreen: function (fullscreen) {
        if (this.pluginApi != null && this.pluginApi.setFullscreen) {
            this.pluginApi.setFullscreen(fullscreen);
        }
    },

    enterFullScreen: function () {
        if (this.pluginApi != null && this.pluginApi.setFullscreen) {
            this.setFullscreen(true);
        }

    },

    exitFullScreen: function () {
        if (this.pluginApi != null && this.pluginApi.setFullscreen) {
            this.setFullscreen(false);
        }
    },

    // start: fake events
    addEventListener: function (eventName, callback, bubble) {
        this.events[eventName] = this.events[eventName] || [];
        this.events[eventName].push(callback);
    },
    removeEventListener: function (eventName, callback) {
        if (!eventName) {
            this.events = {};
            return true;
        }
        var callbacks = this.events[eventName];
        if (!callbacks) return true;
        if (!callback) {
            this.events[eventName] = [];
            return true;
        }
        for (var i = 0; i < callbacks.length; i++) {
            if (callbacks[i] === callback) {
                this.events[eventName].splice(i, 1);
                return true;
            }
        }
        return false;
    },
    dispatchEvent: function (event) {
        var i,
            args,
            callbacks = this.events[event.type];

        if (callbacks) {
            for (i = 0; i < callbacks.length; i++) {
                callbacks[i].apply(this, [event]);
            }
        }
    },
    // end: fake events

    // fake DOM attribute methods
    hasAttribute: function (name) {
        return (name in this.attributes);
    },
    removeAttribute: function (name) {
        delete this.attributes[name];
    },
    getAttribute: function (name) {
        if (this.hasAttribute(name)) {
            return this.attributes[name];
        }
        return '';
    },
    setAttribute: function (name, value) {
        this.attributes[name] = value;
    },

    remove: function () {
        mejs.Utility.removeSwf(this.pluginElement.id);
    }
};

/*
Default options
*/
mejs.MediaElementDefaults = {
    // allows testing on HTML5, flash, silverlight
    // auto: attempts to detect what the browser can do
    // auto_plugin: prefer plugins and then attempt native HTML5
    // native: forces HTML5 playback
    // shim: disallows HTML5, will attempt either Flash or Silverlight
    // none: forces fallback view
    mode: 'auto',
    // remove or reorder to change plugin priority and availability
    plugins: ['flash', 'silverlight', 'youtube', 'vimeo'],
    // shows debug errors on screen
    enablePluginDebug: false,
    // use plugin for browsers that have trouble with Basic Authentication on HTTPS sites
    httpsBasicAuthSite: false,
    // overrides the type specified, useful for dynamic instantiation
    type: '',
    // path to Flash and Silverlight plugins
    pluginPath: mejs.Utility.getScriptPath(['mediaelement.js', 'mediaelement.min.js', 'mediaelement-and-player.js', 'mediaelement-and-player.min.js']),
    // name of flash file
    flashName: 'flashmediaelement.swf',
    // streamer for RTMP streaming
    flashStreamer: '',
    // set to 'always' for CDN version
    flashScriptAccess: 'sameDomain',
    // turns on the smoothing filter in Flash
    enablePluginSmoothing: false,
    // enabled pseudo-streaming (seek) on .mp4 files
    enablePseudoStreaming: false,
    // start query parameter sent to server for pseudo-streaming
    pseudoStreamingStartQueryParam: 'start',
    // name of silverlight file
    silverlightName: 'silverlightmediaelement.xap',
    // default if the <video width> is not specified
    defaultVideoWidth: 480,
    // default if the <video height> is not specified
    defaultVideoHeight: 270,
    // overrides <video width>
    pluginWidth: -1,
    // overrides <video height>
    pluginHeight: -1,
    // additional plugin variables in 'key=value' form
    pluginVars: [],
    // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
    // larger number is less accurate, but less strain on plugin->JavaScript bridge
    timerRate: 250,
    // initial volume for player
    startVolume: 0.8,
    success: function () {
    },
    error: function () {
    }
};

/*
Determines if a browser supports the <video> or <audio> element
and returns either the native element or a Flash/Silverlight version that
mimics HTML5 MediaElement
*/
mejs.MediaElement = function (el, o) {
    return mejs.HtmlMediaElementShim.create(el, o);
};

mejs.HtmlMediaElementShim = {

    create: function (el, o) {
        var
            options = {},
            htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
            tagName = htmlMediaElement.tagName.toLowerCase(),
            isMediaTag = (tagName === 'audio' || tagName === 'video'),
            src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
            poster = htmlMediaElement.getAttribute('poster'),
            autoplay = htmlMediaElement.getAttribute('autoplay'),
            preload = htmlMediaElement.getAttribute('preload'),
            controls = htmlMediaElement.getAttribute('controls'),
            playback,
            prop;

        // extend options
        for (prop in mejs.MediaElementDefaults) {
            options[prop] = mejs.MediaElementDefaults[prop];
        }
        for (prop in o) {
            options[prop] = o[prop];
        }


        // clean up attributes
        src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
        poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
        preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
        autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
        controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');

        // test for HTML5 and plugin capabilities
        playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
        playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
        playback.scheme = mejs.Utility.determineScheme(playback.url);

        if (playback.method == 'native') {
            // second fix for android
            if (mejs.MediaFeatures.isBustedAndroid) {
                htmlMediaElement.src = playback.url;
                htmlMediaElement.addEventListener('click', function () {
                    htmlMediaElement.play();
                }, false);
            }

            // add methods to native HTMLMediaElement
            return this.updateNative(playback, options, autoplay, preload);
        } else if (playback.method !== '') {
            // create plugin to mimic HTMLMediaElement

            return this.createPlugin(playback, options, poster, autoplay, preload, controls);
        } else {
            // boo, no HTML5, no Flash, no Silverlight.
            this.createErrorMessage(playback, options, poster);

            return this;
        }
    },

    determinePlayback: function (htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
        var
            mediaFiles = [],
            i,
            j,
            k,
            l,
            n,
            type,
            result = {method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio'), scheme: ''},
            pluginName,
            pluginVersions,
            pluginInfo,
            dummy,
            media;

        // STEP 1: Get URL and type from <video src> or <source src>

        // supplied type overrides <video type> and <source type>
        if (typeof options.type != 'undefined' && options.type !== '') {

            // accept either string or array of types
            if (typeof options.type == 'string') {
                mediaFiles.push({type: options.type, url: src});
            } else {

                for (i = 0; i < options.type.length; i++) {
                    mediaFiles.push({type: options.type[i], url: src});
                }
            }

            // test for src attribute first
        } else if (src !== null) {
            type = this.formatType(src, htmlMediaElement.getAttribute('type'));
            mediaFiles.push({type: type, url: src});

            // then test for <source> elements
        } else {
            // test <source> types to see if they are usable
            for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
                n = htmlMediaElement.childNodes[i];
                if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
                    src = n.getAttribute('src');
                    type = this.formatType(src, n.getAttribute('type'));
                    media = n.getAttribute('media');

                    if (!media || !window.matchMedia || (window.matchMedia && window.matchMedia(media).matches)) {
                        mediaFiles.push({type: type, url: src});
                    }
                }
            }
        }

        // in the case of dynamicly created players
        // check for audio types
        if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
            result.isVideo = false;
        }


        // STEP 2: Test for playback method

        // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
        if (mejs.MediaFeatures.isBustedAndroid) {
            htmlMediaElement.canPlayType = function (type) {
                return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
            };
        }

        // special case for Chromium to specify natively supported video codecs (i.e. WebM and Theora) 
        if (mejs.MediaFeatures.isChromium) {
            htmlMediaElement.canPlayType = function (type) {
                return (type.match(/video\/(webm|ogv|ogg)/gi) !== null) ? 'maybe' : '';
            };
        }

        // test for native playback first
        if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native') && !(mejs.MediaFeatures.isBustedNativeHTTPS && options.httpsBasicAuthSite === true)) {

            if (!isMediaTag) {

                // create a real HTML5 Media Element 
                dummy = document.createElement(result.isVideo ? 'video' : 'audio');
                htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
                htmlMediaElement.style.display = 'none';

                // use this one from now on
                result.htmlMediaElement = htmlMediaElement = dummy;
            }

            for (i = 0; i < mediaFiles.length; i++) {
                // normal check
                if (mediaFiles[i].type == "video/m3u8" || htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
                    // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
                    || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/, 'mpeg')).replace(/no/, '') !== ''
                    // special case for m4a supported by detecting mp4 support
                    || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/m4a/, 'mp4')).replace(/no/, '') !== '') {
                    result.method = 'native';
                    result.url = mediaFiles[i].url;
                    break;
                }
            }

            if (result.method === 'native') {
                if (result.url !== null) {
                    htmlMediaElement.src = result.url;
                }

                // if `auto_plugin` mode, then cache the native result but try plugins.
                if (options.mode !== 'auto_plugin') {
                    return result;
                }
            }
        }

        // if native playback didn't work, then test plugins
        if (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'shim') {
            for (i = 0; i < mediaFiles.length; i++) {
                type = mediaFiles[i].type;

                // test all plugins in order of preference [silverlight, flash]
                for (j = 0; j < options.plugins.length; j++) {

                    pluginName = options.plugins[j];

                    // test version of plugin (for future features)
                    pluginVersions = mejs.plugins[pluginName];

                    for (k = 0; k < pluginVersions.length; k++) {
                        pluginInfo = pluginVersions[k];

                        // test if user has the correct plugin version

                        // for youtube/vimeo
                        if (pluginInfo.version == null ||

                            mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {

                            // test for plugin playback types
                            for (l = 0; l < pluginInfo.types.length; l++) {
                                // find plugin that can play the type
                                if (type.toLowerCase() == pluginInfo.types[l].toLowerCase()) {
                                    result.method = pluginName;
                                    result.url = mediaFiles[i].url;
                                    return result;
                                }
                            }
                        }
                    }
                }
            }
        }

        // at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
        // if we have native support then return that.
        if (options.mode === 'auto_plugin' && result.method === 'native') {
            return result;
        }

        // what if there's nothing to play? just grab the first available
        if (result.method === '' && mediaFiles.length > 0) {
            result.url = mediaFiles[0].url;
        }

        return result;
    },

    formatType: function (url, type) {
        // if no type is supplied, fake it with the extension
        if (url && !type) {
            return this.getTypeFromFile(url);
        } else {
            // only return the mime part of the type in case the attribute contains the codec
            // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
            // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`

            if (type && ~type.indexOf(';')) {
                return type.substr(0, type.indexOf(';'));
            } else {
                return type;
            }
        }
    },

    getTypeFromFile: function (url) {
        url = url.split('?')[0];
        var
            ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase(),
            av = /(mp4|m4v|ogg|ogv|m3u8|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video/' : 'audio/';
        return this.getTypeFromExtension(ext, av);
    },

    getTypeFromExtension: function (ext, av) {
        av = av || '';

        switch (ext) {
            case 'mp4':
            case 'm4v':
            case 'm4a':
            case 'f4v':
            case 'f4a':
                return av + 'mp4';
            case 'flv':
                return av + 'x-flv';
            case 'webm':
            case 'webma':
            case 'webmv':
                return av + 'webm';
            case 'ogg':
            case 'oga':
            case 'ogv':
                return av + 'ogg';
            case 'm3u8':
                return 'application/x-mpegurl';
            case 'ts':
                return av + 'mp2t';
            default:
                return av + ext;
        }
    },

    createErrorMessage: function (playback, options, poster) {
        var
            htmlMediaElement = playback.htmlMediaElement,
            errorContainer = document.createElement('div'),
            errorContent = options.customError;

        errorContainer.className = 'me-cannotplay';

        try {
            errorContainer.style.width = htmlMediaElement.width + 'px';
            errorContainer.style.height = htmlMediaElement.height + 'px';
        } catch (e) {
        }

        if (!errorContent) {
            errorContent = '<a href="' + playback.url + '">';

            if (poster !== '') {
                errorContent += '<img src="' + poster + '" width="100%" height="100%" alt="" />';
            }

            errorContent += '<span>' + mejs.i18n.t('Download File') + '</span></a>';
        }

        errorContainer.innerHTML = errorContent;

        htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
        htmlMediaElement.style.display = 'none';

        options.error(htmlMediaElement);
    },

    createPlugin: function (playback, options, poster, autoplay, preload, controls) {
        var
            htmlMediaElement = playback.htmlMediaElement,
            width = 1,
            height = 1,
            pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
            pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
            container = document.createElement('div'),
            specialIEContainer,
            node,
            initVars;

        // copy tagName from html media element
        pluginMediaElement.tagName = htmlMediaElement.tagName

        // copy attributes from html media element to plugin media element
        for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
            var attribute = htmlMediaElement.attributes[i];
            if (attribute.specified) {
                pluginMediaElement.setAttribute(attribute.name, attribute.value);
            }
        }

        // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
        node = htmlMediaElement.parentNode;

        while (node !== null && node.tagName != null && node.tagName.toLowerCase() !== 'body' &&
        node.parentNode != null && node.parentNode.tagName != null && node.parentNode.constructor != null && node.parentNode.constructor.name === "ShadowRoot") {
            if (node.parentNode.tagName.toLowerCase() === 'p') {
                node.parentNode.parentNode.insertBefore(node, node.parentNode);
                break;
            }
            node = node.parentNode;
        }

        if (playback.isVideo) {
            width = (options.pluginWidth > 0) ? options.pluginWidth : (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
            height = (options.pluginHeight > 0) ? options.pluginHeight : (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;

            // in case of '%' make sure it's encoded
            width = mejs.Utility.encodeUrl(width);
            height = mejs.Utility.encodeUrl(height);

        } else {
            if (options.enablePluginDebug) {
                width = 320;
                height = 240;
            }
        }

        // register plugin
        pluginMediaElement.success = options.success;

        // add container (must be added to DOM before inserting HTML for IE)
        container.className = 'me-plugin';
        container.id = pluginid + '_container';

        if (playback.isVideo) {
            htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
        } else {
            document.body.insertBefore(container, document.body.childNodes[0]);
        }

        if (playback.method === 'flash' || playback.method === 'silverlight') {

            // flash/silverlight vars
            initVars = [
                'id=' + pluginid,
                'isvideo=' + ((playback.isVideo) ? "true" : "false"),
                'autoplay=' + ((autoplay) ? "true" : "false"),
                'preload=' + preload,
                'width=' + width,
                'startvolume=' + options.startVolume,
                'timerrate=' + options.timerRate,
                'flashstreamer=' + options.flashStreamer,
                'height=' + height,
                'pseudostreamstart=' + options.pseudoStreamingStartQueryParam];

            if (playback.url !== null) {
                if (playback.method == 'flash') {
                    initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
                } else {
                    initVars.push('file=' + playback.url);
                }
            }
            if (options.enablePluginDebug) {
                initVars.push('debug=true');
            }
            if (options.enablePluginSmoothing) {
                initVars.push('smoothing=true');
            }
            if (options.enablePseudoStreaming) {
                initVars.push('pseudostreaming=true');
            }
            if (controls) {
                initVars.push('controls=true'); // shows controls in the plugin if desired
            }
            if (options.pluginVars) {
                initVars = initVars.concat(options.pluginVars);
            }

            // call from plugin
            window[pluginid + '_init'] = function () {
                switch (pluginMediaElement.pluginType) {
                    case 'flash':
                        pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(pluginid);
                        break;
                    case 'silverlight':
                        pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
                        pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
                        break;
                }

                if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
                    pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
                }
            }

            // event call from plugin
            window[pluginid + '_event'] = function (eventName, values) {

                var
                    e,
                    i,
                    bufferedTime;

                // fake event object to mimic real HTML media event.
                e = {
                    type: eventName,
                    target: pluginMediaElement
                };

                // attach all values to element and event object
                for (i in values) {
                    pluginMediaElement[i] = values[i];
                    e[i] = values[i];
                }

                // fake the newer W3C buffered TimeRange (loaded and total have been removed)
                bufferedTime = values.bufferedTime || 0;

                e.target.buffered = e.buffered = {
                    start: function (index) {
                        return 0;
                    },
                    end: function (index) {
                        return bufferedTime;
                    },
                    length: 1
                };

                pluginMediaElement.dispatchEvent(e);
            }


        }

        switch (playback.method) {
            case 'silverlight':
                container.innerHTML =
                    '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
                    '<param name="initParams" value="' + initVars.join(',') + '" />' +
                    '<param name="windowless" value="true" />' +
                    '<param name="background" value="black" />' +
                    '<param name="minRuntimeVersion" value="3.0.0.0" />' +
                    '<param name="autoUpgrade" value="true" />' +
                    '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
                    '</object>';
                break;

            case 'flash':

                if (mejs.MediaFeatures.isIE) {
                    specialIEContainer = document.createElement('div');
                    container.appendChild(specialIEContainer);
                    specialIEContainer.outerHTML =
                        '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
                        'id="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
                        '<param name="movie" value="' + options.pluginPath + options.flashName + '?' + (new Date().getTime()) + '" />' +
                        '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
                        '<param name="quality" value="high" />' +
                        '<param name="bgcolor" value="#000000" />' +
                        '<param name="wmode" value="transparent" />' +
                        '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '" />' +
                        '<param name="allowFullScreen" value="true" />' +
                        '<param name="scale" value="default" />' +
                        '</object>';

                } else {

                    container.innerHTML =
                        '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
                        'play="true" ' +
                        'loop="false" ' +
                        'quality="high" ' +
                        'bgcolor="#000000" ' +
                        'wmode="transparent" ' +
                        'allowScriptAccess="' + options.flashScriptAccess + '" ' +
                        'allowFullScreen="true" ' +
                        'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
                        'src="' + options.pluginPath + options.flashName + '" ' +
                        'flashvars="' + initVars.join('&') + '" ' +
                        'width="' + width + '" ' +
                        'height="' + height + '" ' +
                        'scale="default"' +
                        'class="mejs-shim"></embed>';
                }
                break;

            case 'youtube':


                var videoId;
                // youtu.be url from share button
                if (playback.url.lastIndexOf("youtu.be") != -1) {
                    videoId = playback.url.substr(playback.url.lastIndexOf('/') + 1);
                    if (videoId.indexOf('?') != -1) {
                        videoId = videoId.substr(0, videoId.indexOf('?'));
                    }
                }
                else {
                    // https://www.youtube.com/watch?v=
                    var videoIdMatch = playback.url.match(/[?&]v=([^&#]+)|&|#|$/);
                    if (videoIdMatch) {
                        videoId = videoIdMatch[1];
                    }
                }
                youtubeSettings = {
                    container: container,
                    containerId: container.id,
                    pluginMediaElement: pluginMediaElement,
                    pluginId: pluginid,
                    videoId: videoId,
                    height: height,
                    width: width,
                    scheme: playback.scheme
                };

                // favor iframe version of YouTube
                if (window.postMessage) {
                    mejs.YouTubeApi.enqueueIframe(youtubeSettings);
                } else if (mejs.PluginDetector.hasPluginVersion('flash', [10, 0, 0])) {
                    mejs.YouTubeApi.createFlash(youtubeSettings, options);
                }

                break;

            // DEMO Code. Does NOT work.
            case 'vimeo':
                var player_id = pluginid + "_player";
                pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/') + 1);

                container.innerHTML = '<iframe src="' + playback.scheme + 'player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?api=1&portrait=0&byline=0&title=0&player_id=' + player_id + '" width="' + width + '" height="' + height + '" frameborder="0" class="mejs-shim" id="' + player_id + '" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                if (typeof($f) == 'function') { // froogaloop available
                    var player = $f(container.childNodes[0]),
                        playerState = -1;

                    player.addEvent('ready', function () {

                        player.playVideo = function () {
                            player.api('play');
                        }
                        player.stopVideo = function () {
                            player.api('unload');
                        }
                        player.pauseVideo = function () {
                            player.api('pause');
                        }
                        player.seekTo = function (seconds) {
                            player.api('seekTo', seconds);
                        }
                        player.setVolume = function (volume) {
                            player.api('setVolume', volume);
                        }
                        player.setMuted = function (muted) {
                            if (muted) {
                                player.lastVolume = player.api('getVolume');
                                player.api('setVolume', 0);
                            } else {
                                player.api('setVolume', player.lastVolume);
                                delete player.lastVolume;
                            }
                        }
                        // parity with YT player
                        player.getPlayerState = function () {
                            return playerState;
                        }

                        function createEvent(player, pluginMediaElement, eventName, e) {
                            var event = {
                                type: eventName,
                                target: pluginMediaElement
                            };
                            if (eventName == 'timeupdate') {
                                pluginMediaElement.currentTime = event.currentTime = e.seconds;
                                pluginMediaElement.duration = event.duration = e.duration;
                            }
                            pluginMediaElement.dispatchEvent(event);
                        }

                        player.addEvent('play', function () {
                            playerState = 1;
                            createEvent(player, pluginMediaElement, 'play');
                            createEvent(player, pluginMediaElement, 'playing');
                        });

                        player.addEvent('pause', function () {
                            playerState = 2;
                            createEvent(player, pluginMediaElement, 'pause');
                        });

                        player.addEvent('finish', function () {
                            playerState = 0;
                            createEvent(player, pluginMediaElement, 'ended');
                        });

                        player.addEvent('playProgress', function (e) {
                            createEvent(player, pluginMediaElement, 'timeupdate', e);
                        });

                        player.addEvent('seek', function (e) {
                            playerState = 3;
                            createEvent(player, pluginMediaElement, 'seeked', e);
                        });

                        player.addEvent('loadProgress', function (e) {
                            playerState = 3;
                            createEvent(player, pluginMediaElement, 'progress', e);
                        });

                        pluginMediaElement.pluginElement = container;
                        pluginMediaElement.pluginApi = player;

                        pluginMediaElement.success(pluginMediaElement, pluginMediaElement.pluginElement);
                    });
                }
                else {
                    console.warn("You need to include froogaloop for vimeo to work");
                }
                break;
        }
        // hide original element
        htmlMediaElement.style.display = 'none';
        // prevent browser from autoplaying when using a plugin
        htmlMediaElement.removeAttribute('autoplay');

        return pluginMediaElement;
    },

    updateNative: function (playback, options, autoplay, preload) {

        var htmlMediaElement = playback.htmlMediaElement,
            m;


        // add methods to video object to bring it into parity with Flash Object
        for (m in mejs.HtmlMediaElement) {
            htmlMediaElement[m] = mejs.HtmlMediaElement[m];
        }

        /*
        Chrome now supports preload="none"
        if (mejs.MediaFeatures.isChrome) {
        
            // special case to enforce preload attribute (Chrome doesn't respect this)
            if (preload === 'none' && !autoplay) {
            
                // forces the browser to stop loading (note: fails in IE9)
                htmlMediaElement.src = '';
                htmlMediaElement.load();
                htmlMediaElement.canceledPreload = true;

                htmlMediaElement.addEventListener('play',function() {
                    if (htmlMediaElement.canceledPreload) {
                        htmlMediaElement.src = playback.url;
                        htmlMediaElement.load();
                        htmlMediaElement.play();
                        htmlMediaElement.canceledPreload = false;
                    }
                }, false);
            // for some reason Chrome forgets how to autoplay sometimes.
            } else if (autoplay) {
                htmlMediaElement.load();
                htmlMediaElement.play();
            }
        }
        */

        // fire success code
        options.success(htmlMediaElement, htmlMediaElement);

        return htmlMediaElement;
    }
};

/*
 - test on IE (object vs. embed)
 - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
 - fullscreen?
*/

// YouTube Flash and Iframe API
mejs.YouTubeApi = {
    isIframeStarted: false,
    isIframeLoaded: false,
    loadIframeApi: function (yt) {
        if (!this.isIframeStarted) {
            var tag = document.createElement('script');
            tag.src = yt.scheme + "www.youtube.com/player_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
            this.isIframeStarted = true;
        }
    },
    iframeQueue: [],
    enqueueIframe: function (yt) {

        if (this.isLoaded) {
            this.createIframe(yt);
        } else {
            this.loadIframeApi(yt);
            this.iframeQueue.push(yt);
        }
    },
    createIframe: function (settings) {

        var
            pluginMediaElement = settings.pluginMediaElement,
            player = new YT.Player(settings.containerId, {
                height: settings.height,
                width: settings.width,
                videoId: settings.videoId,
                playerVars: {controls: 0, wmode: 'transparent'},
                events: {
                    'onReady': function () {

                        // wrapper to match
                        player.setVideoSize = function (width, height) {
                            player.setSize(width, height);
                        }

                        // hook up iframe object to MEjs
                        settings.pluginMediaElement.pluginApi = player;
                        settings.pluginMediaElement.pluginElement = document.getElementById(settings.containerId);

                        // init mejs
                        pluginMediaElement.success(pluginMediaElement, pluginMediaElement.pluginElement);

                        // create timer
                        setInterval(function () {
                            mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
                        }, 250);
                    },
                    'onStateChange': function (e) {

                        mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);

                    }
                }
            });
    },

    createEvent: function (player, pluginMediaElement, eventName) {
        var event = {
            type: eventName,
            target: pluginMediaElement
        };

        if (player && player.getDuration) {

            // time 
            pluginMediaElement.currentTime = event.currentTime = player.getCurrentTime();
            pluginMediaElement.duration = event.duration = player.getDuration();

            // state
            event.paused = pluginMediaElement.paused;
            event.ended = pluginMediaElement.ended;

            // sound
            event.muted = player.isMuted();
            event.volume = player.getVolume() / 100;

            // progress
            event.bytesTotal = player.getVideoBytesTotal();
            event.bufferedBytes = player.getVideoBytesLoaded();

            // fake the W3C buffered TimeRange
            var bufferedTime = event.bufferedBytes / event.bytesTotal * event.duration;

            event.target.buffered = event.buffered = {
                start: function (index) {
                    return 0;
                },
                end: function (index) {
                    return bufferedTime;
                },
                length: 1
            };

        }

        // send event up the chain
        pluginMediaElement.dispatchEvent(event);
    },

    iFrameReady: function () {

        this.isLoaded = true;
        this.isIframeLoaded = true;

        while (this.iframeQueue.length > 0) {
            var settings = this.iframeQueue.pop();
            this.createIframe(settings);
        }
    },

    // FLASH!
    flashPlayers: {},
    createFlash: function (settings) {

        this.flashPlayers[settings.pluginId] = settings;

        /*
        settings.container.innerHTML =
            '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + settings.scheme + 'www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
                'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
                '<param name="allowScriptAccess" value="sameDomain">' +
                '<param name="wmode" value="transparent">' +
            '</object>';
        */

        var specialIEContainer,
            youtubeUrl = settings.scheme + 'www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';

        if (mejs.MediaFeatures.isIE) {

            specialIEContainer = document.createElement('div');
            settings.container.appendChild(specialIEContainer);
            specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="' + settings.scheme + 'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
                'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '" class="mejs-shim">' +
                '<param name="movie" value="' + youtubeUrl + '" />' +
                '<param name="wmode" value="transparent" />' +
                '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '" />' +
                '<param name="allowFullScreen" value="true" />' +
                '</object>';
        } else {
            settings.container.innerHTML =
                '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
                'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
                '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '">' +
                '<param name="wmode" value="transparent">' +
                '</object>';
        }

    },

    flashReady: function (id) {
        var
            settings = this.flashPlayers[id],
            player = document.getElementById(id),
            pluginMediaElement = settings.pluginMediaElement;

        // hook up and return to MediaELementPlayer.success	
        pluginMediaElement.pluginApi =
            pluginMediaElement.pluginElement = player;

        settings.success(pluginMediaElement, pluginMediaElement.pluginElement);

        // load the youtube video
        player.cueVideoById(settings.videoId);

        var callbackName = settings.containerId + '_callback';

        window[callbackName] = function (e) {
            mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
        }

        player.addEventListener('onStateChange', callbackName);

        setInterval(function () {
            mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
        }, 250);

        mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'canplay');
    },

    handleStateChange: function (youTubeState, player, pluginMediaElement) {
        switch (youTubeState) {
            case -1: // not started
                pluginMediaElement.paused = true;
                pluginMediaElement.ended = true;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
                //createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
                break;
            case 0:
                pluginMediaElement.paused = false;
                pluginMediaElement.ended = true;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
                break;
            case 1:
                pluginMediaElement.paused = false;
                pluginMediaElement.ended = false;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
                break;
            case 2:
                pluginMediaElement.paused = true;
                pluginMediaElement.ended = false;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
                break;
            case 3: // buffering
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
                break;
            case 5:
                // cued?
                break;

        }

    }
}
// IFRAME
window.onYouTubePlayerAPIReady = function () {
    mejs.YouTubeApi.iFrameReady();
};
// FLASH
window.onYouTubePlayerReady = function (id) {
    mejs.YouTubeApi.flashReady(id);
};

window.mejs = mejs;
window.MediaElement = mejs.MediaElement;

/*
 * Adds Internationalization and localization to mediaelement.
 *
 * This file does not contain translations, you have to add them manually.
 * The schema is always the same: me-i18n-locale-[IETF-language-tag].js
 *
 * Examples are provided both for german and chinese translation.
 *
 *
 * What is the concept beyond i18n?
 *   http://en.wikipedia.org/wiki/Internationalization_and_localization
 *
 * What langcode should i use?
 *   http://en.wikipedia.org/wiki/IETF_language_tag
 *   https://tools.ietf.org/html/rfc5646
 *
 *
 * License?
 *
 *   The i18n file uses methods from the Drupal project (drupal.js):
 *     - i18n.methods.t() (modified)
 *     - i18n.methods.checkPlain() (full copy)
 *
 *   The Drupal project is (like mediaelementjs) licensed under GPLv2.
 *    - http://drupal.org/licensing/faq/#q1
 *    - https://github.com/johndyer/mediaelement
 *    - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *
 * @author
 *   Tim Latz (latz.tim@gmail.com)
 *
 *
 * @params
 *  - context - document, iframe ..
 *  - exports - CommonJS, window ..
 *
 */
;(function (context, exports, undefined) {
    "use strict";

    var i18n = {
        "locale": {
            // Ensure previous values aren't overwritten.
            "language": (exports.i18n && exports.i18n.locale.language) || '',
            "strings": (exports.i18n && exports.i18n.locale.strings) || {}
        },
        "ietf_lang_regex": /^(x\-)?[a-z]{2,}(\-\w{2,})?(\-\w{2,})?$/,
        "methods": {}
    };
// start i18n


    /**
     * Get language, fallback to browser's language if empty
     *
     * IETF: RFC 5646, https://tools.ietf.org/html/rfc5646
     * Examples: en, zh-CN, cmn-Hans-CN, sr-Latn-RS, es-419, x-private
     */
    i18n.getLanguage = function () {
        var language = i18n.locale.language || window.navigator.userLanguage || window.navigator.language;
        return i18n.ietf_lang_regex.exec(language) ? language : null;

        //(WAS: convert to iso 639-1 (2-letters, lower case))
        //return language.substr(0, 2).toLowerCase();
    };

    // i18n fixes for compatibility with WordPress
    if (typeof mejsL10n != 'undefined') {
        i18n.locale.language = mejsL10n.language;
    }


    /**
     * Encode special characters in a plain-text string for display as HTML.
     */
    i18n.methods.checkPlain = function (str) {
        var character, regex,
            replace = {
                '&': '&amp;',
                '"': '&quot;',
                '<': '&lt;',
                '>': '&gt;'
            };
        str = String(str);
        for (character in replace) {
            if (replace.hasOwnProperty(character)) {
                regex = new RegExp(character, 'g');
                str = str.replace(regex, replace[character]);
            }
        }
        return str;
    };

    /**
     * Translate strings to the page language or a given language.
     *
     *
     * @param str
     *   A string containing the English string to translate.
     *
     * @param options
     *   - 'context' (defaults to the default context): The context the source string
     *     belongs to.
     *
     * @return
     *   The translated string, escaped via i18n.methods.checkPlain()
     */
    i18n.methods.t = function (str, options) {

        // Fetch the localized version of the string.
        if (i18n.locale.strings && i18n.locale.strings[options.context] && i18n.locale.strings[options.context][str]) {
            str = i18n.locale.strings[options.context][str];
        }

        return i18n.methods.checkPlain(str);
    };


    /**
     * Wrapper for i18n.methods.t()
     *
     * @see i18n.methods.t()
     * @throws InvalidArgumentException
     */
    i18n.t = function (str, options) {

        if (typeof str === 'string' && str.length > 0) {

            // check every time due language can change for
            // different reasons (translation, lang switcher ..)
            var language = i18n.getLanguage();

            options = options || {
                "context": language
            };

            return i18n.methods.t(str, options);
        }
        else {
            throw {
                "name": 'InvalidArgumentException',
                "message": 'First argument is either not a string or empty.'
            };
        }
    };

// end i18n
    exports.i18n = i18n;
}(document, mejs));

// i18n fixes for compatibility with WordPress
;(function (exports, undefined) {

    "use strict";

    if (typeof mejsL10n != 'undefined') {
        exports[mejsL10n.language] = mejsL10n.strings;
    }

}(mejs.i18n.locale.strings));
