/* REQUIRED STYLES (be careful overriding)
================================================================================ */

/* Box containing video, controls, and download links.
   If you want to add some kind of frame or special positioning, use another containing element, not video-js-box. */
.video-js-box { text-align: left; position: relative; vertical-align: bottom; } /* Will be set to the width of the video element */

/* Video Element */
video.video-js { background-color: #000; position: relative; }

/* Fullscreen styles for main elements */
.video-js-box.vjs-fullscreen { position: fixed; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: 1000; }
.video-js-box.vjs-fullscreen video.video-js { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1001; }
.video-js-box.vjs-fullscreen .vjs-controls { z-index: 1002; }

/* Poster Style */
.video-js-box .vjs-poster { display: block; position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
/* Subtiles Style */
.video-js-box .vjs-subtitles { color:#fff; font-size: 20px; text-align: center; bottom: 20px; left: 0; right: 0; position: absolute; z-index: 1002; }

/* DEFAULT SKIN (override in another file)
================================================================================
Using all CSS to draw the controls. Images could be used if desired.
Instead of editing this file, I recommend creating your own skin CSS file to be included after this file,
so you can upgrade to newer versions easier. */

/* Controls Layout
   Using a Holy Grail type method to allow the progress bar holder to expand into all available space,
   but using abosolute positioning for individual controls. http://www.alistapart.com/articles/holygrail */
.vjs-controls {
  list-style: none; position: absolute; margin: 0; border: none; opacity: 0.85; color: #fff;
  display: none; /* Start hidden */
  left: 0; right: 0; /* 100% width of video-js-box */
  height: 35px; /* Including any margin you want above or below control items */
  padding-left: 35px; /* Width of play button + margin */
  padding-right: 165px; /* Width of all the controls to the right of the progress control + margins */
}
/* Controls styles when below the video */
.video-js-box.vjs-controls-below .vjs-controls { background-color: #000; }

.vjs-controls > li { /* Direct li children of control bar */
  position: absolute; list-style: none; float: left; padding: 0; text-align: center;
  height: 25px; /* Default height of individual controls */
  margin: 5px 0 0 0; /* Top margin to put space between video and controls when controls are below */

  /* CSS Background Gradients */
  /* Default */ background-color: #0B151A;
  /* Webkit  */ background: #1F3744 -webkit-gradient(linear, left top, left bottom, from(#0B151A), to(#1F3744)) left 12px;
  /* Firefox */ background: #1F3744 -moz-linear-gradient(top,  #0B151A,  #1F3744) left 12px;

  /* CSS Curved Corners */
  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;

  /* CSS Shadows */
  box-shadow: 1px 1px 2px #000; -webkit-box-shadow: 1px 1px 2px #000; -moz-box-shadow: 1px 1px 2px #000;
}
/* Placement of Control Items */
.vjs-controls > li.vjs-play-control       { width: 25px; left: 5px; }
.vjs-controls > li.vjs-progress-control   { width: 100%; position: relative; }
.vjs-controls > li.vjs-time-control       { width: 75px; right: 90px; }
.vjs-controls > li.vjs-volume-control     { width: 50px; right: 35px; }
.vjs-controls > li.vjs-fullscreen-control { width: 25px; right: 5px; }

/* Removing curves on progress control and time control to join them. */
.vjs-controls > li.vjs-progress-control {
  border-top-right-radius: 0; -webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0;
  border-bottom-right-radius: 0; -webkit-border-bottom-right-radius: 0; -moz-border-radius-bottomright: 0;
}
.vjs-controls > li.vjs-time-control {
  border-top-left-radius: 0; -webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0;
  border-bottom-left-radius: 0; -webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0;
}

/* Play/Pause
-------------------------------------------------------------------------------- */
.vjs-play-control { cursor: pointer !important; }
.vjs-play-control span { display: block; font-size: 0; line-height: 0; }
.vjs-play-control.vjs-play span {
  width: 0; height: 0; margin: 8px 0 0 8px;
  /* Drawing the play triangle with borders - http://www.infimum.dk/HTML/slantinfo.html */
  border-left: 10px solid #fff; /* Width & Color of play icon */
  /* Height of play icon is total top & bottom border widths. Color is transparent. */
  border-top: 5px solid rgba(0,0,0,0); border-bottom: 5px solid rgba(0,0,0,0);
}
.vjs-play-control.vjs-pause span {
  width: 3px; height: 10px; margin: 8px auto 0;
  /* Drawing the pause bars with borders */
  border-top: 0px; border-left: 3px solid #fff; border-bottom: 0px; border-right: 3px solid #fff;
}

/* Progress
-------------------------------------------------------------------------------- */
.vjs-progress-holder { /* Box containing play and load progresses */
  position: relative; list-style: none; padding: 0; overflow:hidden; cursor: pointer !important;
  height: 9px; border: 1px solid #777;
  margin: 7px 1px 0 5px; /* Placement within the progress control item */
  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
}
.vjs-progress-holder li { /* Progress Bars */
  position: absolute; display: block; width: 0; height: 9px;
  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
}
.vjs-play-progress {
  /* Default */ background: #fff;
  /* Webkit  */ background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#777));
  /* Firefox */ background: -moz-linear-gradient(top,  #fff,  #777);
}
.vjs-load-progress {
  opacity: 0.8;
  /* Default */ background-color: #555;
  /* Webkit  */ background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#aaa));
  /* Firefox */ background: -moz-linear-gradient(top,  #555,  #aaa);
}

/* Time Display
-------------------------------------------------------------------------------- */
.vjs-controls .vjs-time-control { font-size: 10px; line-height: 1; font-weight: normal; font-family: Helvetica, Arial, sans-serif; }
.vjs-controls .vjs-time-control span { line-height: 25px; /* Centering vertically */ }

/* Volume
-------------------------------------------------------------------------------- */
.vjs-volume-control { cursor: pointer !important; }
.vjs-volume-control ul { list-style: none; display: block; margin: 0 5px 0 5px; padding: 4px 0 0 0; }
/* Drawing the volume icon using 6 li elements */
.vjs-volume-control ul li { /* Individual volume bars */
  list-style: none; float: left; padding: 0;
  margin: 0 2px 0 0; /* Space between */
  width: 5px; height: 0px; /* Total height is height + bottom border */
  border-bottom: 18px solid #555; /* Default (off) color and height of visible portion */
}
.vjs-volume-control ul li.vjs-volume-level-on { border-color: #fff; /* Volume on bar color */ }
/* Creating differnt bar heights through height (transparent) and bottom border (visible). */
.vjs-volume-control ul li:nth-child(1) { border-bottom-width: 2px; height: 16px; }
.vjs-volume-control ul li:nth-child(2) { border-bottom-width: 4px; height: 14px; }
.vjs-volume-control ul li:nth-child(3) { border-bottom-width: 7px; height: 11px; }
.vjs-volume-control ul li:nth-child(4) { border-bottom-width: 10px; height: 8px; }
.vjs-volume-control ul li:nth-child(5) { border-bottom-width: 14px; height: 4px; }
.vjs-volume-control ul li:nth-child(6) { margin-right: 0; }

/* Fullscreen
-------------------------------------------------------------------------------- */
.vjs-fullscreen-control { cursor: pointer !important; }
.vjs-fullscreen-control ul {
  list-style: none; padding: 0; text-align: left; vertical-align: top; cursor: pointer !important;
  margin: 5px 0 0 5px; /* Placement within the fullscreen control item */
  width: 20px; height: 20px;
}
/* Drawing the fullscreen icon using 4 li elements */
.vjs-fullscreen-control ul li { list-style: none; float: left; margin: 0; padding: 0; font-size: 0; line-height: 0; width: 0; text-align: left; vertical-align: top; }
.vjs-fullscreen-control ul li:nth-child(1) { /* Top-left triangle */
  margin-right: 3px; /* Space between top-left and top-right */
  margin-bottom: 3px; /* Space between top-left and bottom-left */
  border-top: 6px solid #fff; /* Height and color */
  border-right: 6px solid rgba(0,0,0,0);  /* Width */
}
.vjs-fullscreen-control ul li:nth-child(2) { border-top: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
.vjs-fullscreen-control ul li:nth-child(3) { clear: both; margin: 0 3px 0 0; border-bottom: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }
.vjs-fullscreen-control ul li:nth-child(4) { border-bottom: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
/* Icon when video is in fullscreen mode */
.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(1) { border: none; border-bottom: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(2) { border: none; border-bottom: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }
.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(3) { border: none; border-top: 6px solid #fff; border-left: 6px solid rgba(0,0,0,0); }
.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(4) { border: none; border-top: 6px solid #fff; border-right: 6px solid rgba(0,0,0,0); }

/* Download Links - Used for browsers that don't support any video.
-------------------------------------------------------------------------------- */
.vjs-no-video { font-size: small; }


keep keep keep keep replace keep keep keep keep

linksHiding: true, // Hide download links when video is supported

flashIsDominant: false // Always use Flash when available

/*
This file is part of VideoJS. Copyright 2010 Zencoder, Inc.

VideoJS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

VideoJS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with VideoJS.  If not, see <http://www.gnu.org/licenses/>.
*/

// Using jresig's Class implementation http://ejohn.org/blog/simple-javascript-inheritance/
(function(){var initializing=false, fnTest=/xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; this.JRClass = function(){}; JRClass.extend = function(prop) { var _super = this.prototype; initializing = true; var prototype = new this(); initializing = false; for (var name in prop) { prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; this._super = _super[name]; var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } function JRClass() { if ( !initializing && this.init ) this.init.apply(this, arguments); } JRClass.prototype = prototype; JRClass.constructor = JRClass; JRClass.extend = arguments.callee; return JRClass;};})();

// Video JS Player Class
var VideoJS = JRClass.extend({

  // Initialize the player for the supplied video tag element
  // element: video tag
  init: function(element, setOptions){

    // Hide default controls
    this.video.controls = false;

    // Allow an ID string or an element
    if (typeof element == 'string') {
      this.video = document.getElementById(element);
    } else {
      this.video = element;
    }

    // Store reference to player on the video element.
    // So you can acess the player later: document.getElementById("video_id").player.play();
    this.video.player = this;

    // Default Options
    this.options = {
      controlsBelow: false, // Display control bar below video vs. in front of
      controlsHiding: true, // Hide controls when not over the video
      defaultVolume: 0.85, // Will be overridden by localStorage volume if available
      flashVersion: 9, // Required flash version for fallback
      linksHiding: true // Hide download links when video is supported
    };

    // Override default options with global options
    if (typeof VideoJS.options == "object") _V_.merge(this.options, VideoJS.options);

    // Override global options with options specific to this video
    if (typeof setOptions == "object") _V_.merge(this.options, setOptions);

    this.box = this.video.parentNode;
    this.flashFallback = this.getFlashFallback();
    this.linksFallback = this.getLinksFallback();

    // Hide download links if video can play
    if(VideoJS.browserSupportsVideo() || ((this.flashFallback || VideoJS.isIE()) && this.flashVersionSupported())) {
      this.hideLinksFallback();
    }

    // Check if browser can play HTML5 video
    if (VideoJS.browserSupportsVideo()) {
      // Force flash fallback when there's no supported source
      if (this.canPlaySource() == false) {
        this.replaceWithFlash();
        return;
      }
    } else {
      return;
    }

    // For iPads, controls need to always show because there's no hover
    // The controls also have to be below for the full-window mode to work.
    if (VideoJS.isIpad()) {
      this.options.controlsBelow = true;
      this.options.controlsHiding = false;
    }

    if (this.options.controlsBelow) {
      _V_.addClass(this.box, "vjs-controls-below");
    }

    // Store amount of video loaded
    this.percentLoaded = 0;

    this.buildPoster();
    this.showPoster();

    this.buildController();
    this.showController();

    // Position & show controls when data is loaded
    this.video.addEventListener("loadeddata", this.onLoadedData.context(this), false);

    // Listen for when the video is played
    this.video.addEventListener("play", this.onPlay.context(this), false);
    // Listen for when the video is paused
    this.video.addEventListener("pause", this.onPause.context(this), false);
    // Listen for when the video ends
    this.video.addEventListener("ended", this.onEnded.context(this), false);
    // Listen for a volume change
    this.video.addEventListener('volumechange',this.onVolumeChange.context(this),false);
    // Listen for video errors
    this.video.addEventListener('error',this.onError.context(this),false);
    // Listen for Video Load Progress (currently does not if html file is local)
    this.video.addEventListener('progress', this.onProgress.context(this), false);
    // Set interval for load progress using buffer watching method
    this.watchBuffer = setInterval(this.updateBufferedTotal.context(this), 33);
    // Listen for Video time update
    this.video.addEventListener('timeupdate', this.onTimeUpdate.context(this), false);

    // Listen for clicks on the play/pause button
    this.playControl.addEventListener("click", this.onPlayControlClick.context(this), false);
    // Make a click on the video act like a click on the play button.
    this.video.addEventListener("click", this.onPlayControlClick.context(this), false);
    // Make a click on the poster act like a click on the play button.
    if (this.poster) this.poster.addEventListener("click", this.onPlayControlClick.context(this), false);

    // Listen for drags on the progress bar
    this.progressHolder.addEventListener("mousedown", this.onProgressHolderMouseDown.context(this), false);
    // Listen for a release on the progress bar
    this.progressHolder.addEventListener("mouseup", this.onProgressHolderMouseUp.context(this), false);

    // Set to stored volume OR 85%
    this.setVolume(localStorage.volume || this.options.defaultVolume);
    // Listen for a drag on the volume control
    this.volumeControl.addEventListener("mousedown", this.onVolumeControlMouseDown.context(this), false);
    // Listen for a release on the volume control
    this.volumeControl.addEventListener("mouseup", this.onVolumeControlMouseUp.context(this), false);
    // Set the display to the initial volume
    this.updateVolumeDisplay();

    // Listen for clicks on the button
    this.fullscreenControl.addEventListener("click", this.onFullscreenControlClick.context(this), false);

    // Listen for the mouse move the video. Used to reveal the controller.
    this.video.addEventListener("mousemove", this.onVideoMouseMove.context(this), false);
    // Listen for the mouse moving out of the video. Used to hide the controller.
    this.video.addEventListener("mouseout", this.onVideoMouseOut.context(this), false);

    // Listen for the mouse move the poster image. Used to reveal the controller.
    if (this.poster) this.poster.addEventListener("mousemove", this.onVideoMouseMove.context(this), false);
    // Listen for the mouse moving out of the poster image. Used to hide the controller.
    if (this.poster) this.poster.addEventListener("mouseout", this.onVideoMouseOut.context(this), false);

    // Have to add the mouseout to the controller too or it may not hide.
    // For some reason the same isn't needed for mouseover
    this.controls.addEventListener("mouseout", this.onVideoMouseOut.context(this), false);

    // Create listener for esc key while in full screen mode
    // Creating it during initialization to add context
    // and because it has to be removed with removeEventListener
    this.onEscKey = function(event){
      if (event.keyCode == 27) {
        this.fullscreenOff();
      }
    }.context(this);

    this.onWindowResize = function(event){
      this.positionController();
    }.context(this);

    // Support older browsers that used autobuffer
    this.fixPreloading();

    // Load subtitles. Based on http://matroska.org/technical/specs/subtitles/srt.html
    this.subtitlesSource = this.video.getAttribute("data-subtitles");
    if (this.subtitlesSource != null) {
      this.loadSubtitles();
      this.buildSubtitles();
    }

  },

  // Support older browsers that used "autobuffer"
  fixPreloading: function(){
    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("preload")) {
      this.video.autobuffer = true;
    }
  },

  // Translate functionality
  play: function(){ this.video.play(); },
  pause: function(){ this.video.pause(); },

  buildController: function(){

    /* Creating this HTML

          00:00 / 00:00

    */

    // Create a list element to hold the different controls
    this.controls = _V_.createElement("ul", { className: "vjs-controls" });
    // Add the controls to the video's container
    this.video.parentNode.appendChild(this.controls);

    // Build the play control
    this.playControl = _V_.createElement("li", { className: "vjs-play-control vjs-play", innerHTML: "" });
    this.controls.appendChild(this.playControl);

    // Build the progress control
    this.progressControl = _V_.createElement("li", { className: "vjs-progress-control" });
    this.controls.appendChild(this.progressControl);

    // Create a holder for the progress bars
    this.progressHolder = _V_.createElement("ul", { className: "vjs-progress-holder" });
    this.progressControl.appendChild(this.progressHolder);

    // Create the loading progress display
    this.loadProgress = _V_.createElement("li", { className: "vjs-load-progress" });
    this.progressHolder.appendChild(this.loadProgress)

    // Create the playing progress display
    this.playProgress = _V_.createElement("li", { className: "vjs-play-progress" });
    this.progressHolder.appendChild(this.playProgress);

    // Create the progress time display (00:00 / 00:00)
    this.timeControl = _V_.createElement("li", { className: "vjs-time-control" });
    this.controls.appendChild(this.timeControl);

    // Create the current play time display
    this.currentTimeDisplay = _V_.createElement("span", { className: "vjs-current-time-display", innerHTML: "00:00" });
    this.timeControl.appendChild(this.currentTimeDisplay);

    // Add time separator
    this.timeSeparator = _V_.createElement("span", { innerHTML: " / " });
    this.timeControl.appendChild(this.timeSeparator);

    // Create the total duration display
    this.durationDisplay = _V_.createElement("span", { className: "vjs-duration-display", innerHTML: "00:00" });
    this.timeControl.appendChild(this.durationDisplay);

    // Create the volumne control
    this.volumeControl = _V_.createElement("li", {
      className: "vjs-volume-control",
      innerHTML: "

"
    });
    this.controls.appendChild(this.volumeControl);
    this.volumeDisplay = this.volumeControl.children[0]

    // Crete the fullscreen control
    this.fullscreenControl = _V_.createElement("li", {
      className: "vjs-fullscreen-control",
      innerHTML: "

"
    });
    this.controls.appendChild(this.fullscreenControl);
  },

  // Get the download links block element
  getLinksFallback: function(){
    return this.box.getElementsByTagName("P")[0];
  },

  // Hide no-video download paragraph
  hideLinksFallback: function(){
    if (this.options.linksHiding && this.linksFallback) this.linksFallback.style.display = "none";
  },

  getFlashFallback: function(){
    if (VideoJS.isIE()) return;
    var children = this.box.getElementsByClassName("vjs-flash-fallback");
    for (var i=0,j=children.length; i<j; i++) {
      if (children[i].tagName.toUpperCase() == "OBJECT") {
        return children[i];
      }
    }
  },

  replaceWithFlash: function(){
    // this.flashFallback = this.video.removeChild(this.flashFallback);
    if (this.flashFallback) {
      this.box.insertBefore(this.flashFallback, this.video);
      this.video.style.display = "none"; // Removing it was breaking later players
    }
  },

  // Show the controller
  showController: function(){
    this.controls.style.display = "block";
    this.positionController();
  },

  // Place controller relative to the video's position
  positionController: function(){
    // Make sure the controls are visible
    if (this.controls.style.display == 'none') return;

    // Sometimes the CSS styles haven't been applied to the controls yet
    // when we're trying to calculate the height and position them correctly.
    // This causes a flicker where the controls are out of place.
    // Best way I can think of to test this is to check if the width of all the controls are the same.
    // If so, hide the controller and delay positioning them briefly.
    if (this.playControl.offsetWidth == this.progressControl.offsetWidth
     && this.playControl.offsetWidth == this.timeControl.offsetWidth
     && this.playControl.offsetWidth == this.volumeControl.offsetWidth) {
       // Don't want to create an endless loop either.
       if (!this.positionRetries) this.positionRetries = 1;
       if (this.positionRetries++ < 100) {
         this.controls.style.display = "none";
         setTimeout(this.showController.context(this),0);
         return;
       }
    }

    // Set width based on fullscreen or not.
    if (this.videoIsFullScreen) {
      this.box.style.width = "";
    } else {
      this.box.style.width = this.video.offsetWidth + "px";
    }

    if (this.options.controlsBelow) {
      if (this.videoIsFullScreen) {
        this.box.style.height = "";
        this.video.style.height = (this.box.offsetHeight - this.controls.offsetHeight) + "px";
      } else {
        this.video.style.height = "";
        this.box.style.height = this.video.offsetHeight + this.controls.offsetHeight + "px";
      }
      this.controls.style.top = this.video.offsetHeight + "px";
    } else {
      this.controls.style.top = (this.video.offsetHeight - this.controls.offsetHeight) + "px";
    }

    this.sizeProgressBar();
  },

  // Hide the controller
  hideController: function(){
    if (this.options.controlsHiding) this.controls.style.display = "none";
  },

  // Update poster source from attribute or fallback image
  // iPad breaks if you include a poster attribute, so this fixes that
  updatePosterSource: function(){
    if (!this.video.poster) {
      var images = this.video.getElementsByTagName("img");
      if (images.length > 0) this.video.poster = images[0].src;
    }
  },

  buildPoster: function(){
    this.updatePosterSource();
    if (this.video.poster) {
      this.poster = document.createElement("img");
      // Add poster to video box
      this.video.parentNode.appendChild(this.poster);

      // Add poster image data
      this.poster.src = this.video.poster;
      // Add poster styles
      this.poster.className = "vjs-poster";
    } else {
      this.poster = false;
    }
  },

  // Add the video poster to the video's container, to fix autobuffer/preload bug
  showPoster: function(){
    if (!this.poster) return;
    this.poster.style.display = "block";
    this.positionPoster();
  },

  // Size the poster image
  positionPoster: function(){
    // Only if the poster is visible
    if (this.poster == false || this.poster.style.display == 'none') return;
    this.poster.style.height = this.video.offsetHeight + "px";
    this.poster.style.width = this.video.offsetWidth + "px";
  },

  hidePoster: function(){
    if (!this.poster) return;
    this.poster.style.display = "none";
  },

  canPlaySource: function(){
    var children = this.video.children;
    for (var i=0,j=children.length; i<j; i++) {
      if (children[i].tagName.toUpperCase() == "SOURCE") {
        var canPlay = this.video.canPlayType(children[i].type);
        if(canPlay == "probably" || canPlay == "maybe") {
          return true;
        }
      }
    }
    return false;
  },

  // When the video is played
  onPlay: function(event){
    this.playControl.className = "vjs-play-control vjs-pause";
    this.hidePoster();
    this.trackPlayProgress();
  },

  // When the video is paused
  onPause: function(event){
    this.playControl.className = "vjs-play-control vjs-play";
    this.stopTrackingPlayProgress();
  },

  // When the video ends
  onEnded: function(event){
    this.video.pause();
    this.onPause();
  },

  onVolumeChange: function(event){
    this.updateVolumeDisplay();
  },

  onError: function(event){
    console.log(event);
    console.log(this.video.error);
  },

  onLoadedData: function(event){
    this.showController();
  },

  // When the video's load progress is updated
  // Does not work in all browsers (Safari/Chrome 5)
  onProgress: function(event){
    if(event.total > 0) {
      this.setLoadProgress(event.loaded / event.total);
    }
  },

  // Buffer watching method for load progress.
  // Used for browsers that don't support the progress event
  updateBufferedTotal: function(){
    if (this.video.buffered) {
      if (this.video.buffered.length >= 1) {
        this.setLoadProgress(this.video.buffered.end(0) / this.video.duration);
        if (this.video.buffered.end(0) == this.video.duration) {
          clearInterval(this.watchBuffer);
        }
      }
    } else {
      clearInterval(this.watchBuffer);
    }
  },

  setLoadProgress: function(percentAsDecimal){
    if (percentAsDecimal > this.percentLoaded) {
      this.percentLoaded = percentAsDecimal;
      this.updateLoadProgress();
    }
  },

  updateLoadProgress: function(){
    if (this.controls.style.display == 'none') return;
    this.loadProgress.style.width = (this.percentLoaded * (_V_.getComputedStyleValue(this.progressHolder, "width").replace("px", ""))) + "px";
  },

  // React to clicks on the play/pause button
  onPlayControlClick: function(event){
    if (this.video.paused) {
      this.video.play();
    } else {
      this.video.pause();
    }
  },

  // Adjust the play position when the user drags on the progress bar
  onProgressHolderMouseDown: function(event){
    this.stopTrackingPlayProgress();

    if (this.video.paused) {
      this.videoWasPlaying = false;
    } else {
      this.videoWasPlaying = true;
      this.video.pause();
    }

    _V_.blockTextSelection();
    document.onmousemove = function(event) {
      this.setPlayProgressWithEvent(event);
    }.context(this);

    document.onmouseup = function(event) {
      _V_.unblockTextSelection();
      document.onmousemove = null;
      document.onmouseup = null;
      if (this.videoWasPlaying) {
        this.video.play();
        this.trackPlayProgress();
      }
    }.context(this);
  },

  // When the user stops dragging on the progress bar, update play position
  // Backup for when the user only clicks and doesn't drag
  onProgressHolderMouseUp: function(event){
    this.setPlayProgressWithEvent(event);

    // Fixe for an apparent play button state issue.
    if (this.video.paused) {
      this.onPause();
    } else {
      this.onPlay();
    }
  },

  // Adjust the volume when the user drags on the volume control
  onVolumeControlMouseDown: function(event){
    _V_.blockTextSelection();
    document.onmousemove = function(event) {
      this.setVolumeWithEvent(event);
    }.context(this);
    document.onmouseup = function() {
      _V_.unblockTextSelection();
      document.onmousemove = null;
      document.onmouseup = null;
    }.context(this);
  },

  // When the user stops dragging, set a new volume
  // Backup for when the user only clicks and doesn't drag
  onVolumeControlMouseUp: function(event){
    this.setVolumeWithEvent(event);
  },

  // When the user clicks on the fullscreen button, update fullscreen setting
  onFullscreenControlClick: function(event){
    if (!this.videoIsFullScreen) {
      this.fullscreenOn();
    } else {
      this.fullscreenOff();
    }
  },

  onVideoMouseMove: function(event){
    this.showController();
    clearInterval(this.mouseMoveTimeout);
    this.mouseMoveTimeout = setTimeout(function(){ this.hideController(); }.context(this), 4000);
  },

  onVideoMouseOut: function(event){
    // Prevent flicker by making sure mouse hasn't left the video
    var parent = event.relatedTarget;
    while (parent && parent !== this.video && parent !== this.controls) {
      parent = parent.parentNode;
    }
    if (parent !== this.video && parent !== this.controls) {
      this.hideController();
    }
  },

  // Adjust the width of the progress bar to fill the controls width
  sizeProgressBar: function(){
    this.updatePlayProgress();
    this.updateLoadProgress();
  },

  // Get the space between controls. For more flexible styling.
  getControlsPadding: function(){
    return _V_.findPosX(this.playControl) - _V_.findPosX(this.controls)
  },

  // When dynamically placing controls, if there are borders on the controls, it can break to a new line.
  getControlBorderAdjustment: function(){
    var leftBorder = parseInt(_V_.getComputedStyleValue(this.playControl, "border-left-width").replace("px", ""));
    var rightBorder = parseInt(_V_.getComputedStyleValue(this.playControl, "border-right-width").replace("px", ""));
    return leftBorder + rightBorder;
  },

  // Track & display the current play progress
  trackPlayProgress: function(){
    if(this.playProgressInterval) clearInterval(this.playProgressInterval);
    this.playProgressInterval = setInterval(function(){ this.updatePlayProgress(); }.context(this), 33);
  },

  // Turn off play progress tracking (when paused)
  stopTrackingPlayProgress: function(){
    clearInterval(this.playProgressInterval);
  },

  // Ajust the play progress bar's width based on the current play time
  updatePlayProgress: function(){
    if (this.controls.style.display == 'none') return;
    this.playProgress.style.width = ((this.video.currentTime / this.video.duration) * (_V_.getComputedStyleValue(this.progressHolder, "width").replace("px", ""))) + "px";
    this.updateTimeDisplay();
  },

  // Update the play position based on where the user clicked on the progresss bar
  setPlayProgress: function(newProgress){
    this.video.currentTime = newProgress * this.video.duration;
    this.playProgress.style.width = newProgress * (_V_.getComputedStyleValue(this.progressHolder, "width").replace("px", "")) + "px";
    this.updateTimeDisplay();
    // currentTime changed, reset subtitles
    if (this.subtitles != null) { this.currentSubtitlePosition = 0; }
  },

  setPlayProgressWithEvent: function(event){
    var newProgress = _V_.getRelativePosition(event.pageX, this.progressHolder);
    this.setPlayProgress(newProgress);
  },

  // Update the displayed time (00:00)
  updateTimeDisplay: function(){
    this.currentTimeDisplay.innerHTML = _V_.formatTime(this.video.currentTime);
    if (this.video.duration) this.durationDisplay.innerHTML = _V_.formatTime(this.video.duration);
  },

  // Set a new volume based on where the user clicked on the volume control
  setVolume: function(newVol){
    this.video.volume = parseFloat(newVol);
    localStorage.volume = this.video.volume;
  },

  setVolumeWithEvent: function(event){
    var newVol = _V_.getRelativePosition(event.pageX, this.volumeControl.children[0]);
    this.setVolume(newVol);
  },

  // Update the volume control display
  // Unique to these default controls. Uses borders to create the look of bars.
  updateVolumeDisplay: function(){
    var volNum = Math.ceil(this.video.volume * 6);
    for(var i=0; i<6; i++) {
      if (i < volNum) {
        _V_.addClass(this.volumeDisplay.children[i], "vjs-volume-level-on")
      } else {
        _V_.removeClass(this.volumeDisplay.children[i], "vjs-volume-level-on");
      }
    }
  },

  // Check if browser can use this flash player
  flashVersionSupported: function(){
    return VideoJS.getFlashVersion() >= this.options.flashVersion;
  },

  /* Fullscreen / Full-window
  ================================================================================ */
  // Turn on fullscreen (window) mode
  // Real fullscreen isn't available in browsers quite yet.
  fullscreenOn: function(){
    if (!this.nativeFullscreenOn()) {
      this.videoIsFullScreen = true;

      // Storing original doc overflow value to return to when fullscreen is off
      this.docOrigOverflow = document.documentElement.style.overflow;

      // Add listener for esc key to exit fullscreen
      document.addEventListener("keydown", this.onEscKey, false);

      // Add listener for a window resize
      window.addEventListener("resize", this.onWindowResize, false);

      // Hide any scroll bars
      document.documentElement.style.overflow = 'hidden';

      // Apply fullscreen styles
      _V_.addClass(this.box, "vjs-fullscreen");

      // Resize the controller and poster
      this.positionController();
      this.positionPoster();
    }
  },

  nativeFullscreenOn: function(){
    if(typeof this.video.webkitEnterFullScreen == 'function' && false) {
      // Seems to be broken in Chromium/Chrome
      if (!navigator.userAgent.match("Chrome")) {
        this.video.webkitEnterFullScreen();
        return true;
      }
    }
  },

  // Turn off fullscreen (window) mode
  fullscreenOff: function(){
    this.videoIsFullScreen = false;

    document.removeEventListener("keydown", this.onEscKey, false);
    window.removeEventListener("resize", this.onWindowResize, false);

    // Unhide scroll bars.
    document.documentElement.style.overflow = this.docOrigOverflow;

    // Remove fullscreen styles
    _V_.removeClass(this.box, "vjs-fullscreen");

    // Resize to original settings
    this.positionController();
    this.positionPoster();
  },

  /* Subtitles
  ================================================================================ */
  loadSubtitles: function() {
    if (typeof XMLHttpRequest == "undefined") {
      XMLHttpRequest = function () {
        try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
          catch (e) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
          catch (e) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP"); }
          catch (e) {}
        //Microsoft.XMLHTTP points to Msxml2.XMLHTTP.3.0 and is redundant
        throw new Error("This browser does not support XMLHttpRequest.");
      };
    }
    var request = new XMLHttpRequest();
    request.open("GET",this.subtitlesSource);
    request.onreadystatechange = function() {
      if (request.readyState == 4 && request.status == 200) {
        this.parseSubtitles(request.responseText);
      }
    }.context(this);
    request.send();
  },

  parseSubtitles: function(text) {
    var lines = text.replace("\r",'').split("\n");
    this.subtitles = new Array();
    this.currentSubtitlePosition = 0;

    var i = 0;
    while(i<lines.length) {
      // define the current subtitle object
      var subtitle = {};
      // get the number
      subtitle.id = lines[i++];
      if (subtitle.id=="") {
        break;
      }

      // get time
      var time = lines[i++].split(" --> ");
      subtitle.startTime = this.parseSubtitleTime(time[0]);
      subtitle.endTime = this.parseSubtitleTime(time[1]);

      // get subtitle text
      var text = new Array();
      while(lines[i].length>0 && lines[i]!="\r") {
        text.push(lines[i++]);
      }
      subtitle.text = text.join('
');

      // add this subtitle
      this.subtitles.push(subtitle);

      // ignore the blank line
      i++;
    }
  },

  parseSubtitleTime: function(timeText) {
    var parts = timeText.split(':');
    var time = 0;
    // hours => seconds
    time += parseInt(parts[0])*60*60;
    // minutes => seconds
    time += parseInt(parts[1])*60;
    // get seconds
    var seconds = parts[2].split(',');
    time += parseInt(seconds[0]);
    // add miliseconds
    time = time + parseInt(seconds[1])/1000;
    return time;
  },

  buildSubtitles: function(){
    /* Creating this HTML

    */
    this.subtitlesDiv = _V_.createElement("div", { className: 'vjs-subtitles' });
    this.video.parentNode.appendChild(this.subtitlesDiv);
  },

  onTimeUpdate: function(){
    // show the subtitles
    if (this.subtitles != null) {
      var x = this.currentSubtitlePosition;

      while (x<this.subtitles.length && this.video.currentTime>this.subtitles[x].endTime) {
        if (this.subtitles[x].showing) {
          this.subtitles[x].showing = false;
          this.subtitlesDiv.innerHTML = "";
        }
        this.currentSubtitlePosition++;
        x = this.currentSubtitlePosition;
      }

      if (this.currentSubtitlePosition>=this.subtitles.length)
        return;

      if (this.video.currentTime>=this.subtitles[x].startTime && this.video.currentTime<=this.subtitles[x].endTime) {
        this.subtitlesDiv.innerHTML = this.subtitles[x].text;
        this.subtitles[x].showing = true;
      }
    }
  }
})

////////////////////////////////////////////////////////////////////////////////
// Convenience Functions (mini library)
// Functions not specific to video or VideoJS and could be replaced with a library like jQuery
////////////////////////////////////////////////////////////////////////////////
var _V_ = {
  addClass: function(element, classToAdd){
    if (element.className.split(/\s+/).lastIndexOf(classToAdd) == -1) { element.className = element.className == "" ? classToAdd : element.className + " " + classToAdd; }
  },

  removeClass: function(element, classToRemove){
    if (element.className.indexOf(classToRemove) == -1) return;
    var classNames = element.className.split(/\s+/);
    classNames.splice(classNames.lastIndexOf(classToRemove),1);
    element.className = classNames.join(" ");
  },

  merge: function(obj1, obj2){
    for(attrname in obj2){obj1[attrname]=obj2[attrname];} return obj1;
  },

  createElement: function(tagName, attributes){
    return _V_.merge(document.createElement(tagName), attributes);
  },

  // Attempt to block the ability to select text while dragging controls
  blockTextSelection: function(){
    document.body.focus();
    document.onselectstart = function () { return false; };
  },

  // Turn off text selection blocking
  unblockTextSelection: function(){
    document.onselectstart = function () { return true; };
  },

  // Return seconds as MM:SS
  formatTime: function(seconds) {
    seconds = Math.round(seconds);
    minutes = Math.floor(seconds / 60);
    minutes = (minutes >= 10) ? minutes : "0" + minutes;
    seconds = Math.floor(seconds % 60);
    seconds = (seconds >= 10) ? seconds : "0" + seconds;
    return minutes + ":" + seconds;
  },

  // Return the relative horizonal position of an event as a value from 0-1
  getRelativePosition: function(x, relativeElement){
    return Math.max(0, Math.min(1, (x - _V_.findPosX(relativeElement)) / relativeElement.offsetWidth));
  },

  // Get an objects position on the page
  findPosX: function(obj) {
    var curleft = obj.offsetLeft;
    while(obj = obj.offsetParent) {
      curleft += obj.offsetLeft;
    }
    return curleft;
  },

  getComputedStyleValue: function(element, style){
    return window.getComputedStyle(element, null).getPropertyValue(style);
  },

  // DOM Ready functionality adapted from jQuery. http://jquery.com/
  bindDOMReady: function(){
    if (document.readyState === "complete") {
      return _V_.DOMReady();
    }
    if (document.addEventListener) {
      document.addEventListener("DOMContentLoaded", _V_.DOMContentLoaded, false);
      window.addEventListener("load", _V_.DOMReady, false);
    } else if (document.attachEvent) {
      document.attachEvent("onreadystatechange", _V_.DOMContentLoaded);
      window.attachEvent("onload", _V_.DOMReady);
    }
  },

  DOMContentLoaded: function(){
    if (document.addEventListener) {
      document.removeEventListener( "DOMContentLoaded", _V_.DOMContentLoaded, false);
      _V_.DOMReady();
    } else if ( document.attachEvent ) {
      if ( document.readyState === "complete" ) {
        document.detachEvent("onreadystatechange", _V_.DOMContentLoaded);
        _V_.DOMReady();
      }
    }
  },

  // Functions to be run once the DOM is loaded
  DOMReadyList: [],
  addToDOMReady: function(fn){
    if (_V_.DOMIsReady) {
      fn.call(document)
    } else {
      _V_.DOMReadyList.push(fn);
    }
  },

  DOMIsReady: false,
  DOMReady: function(){
    if (_V_.DOMIsReady) return;
    if (!document.body) { return setTimeout(_V_.DOMReady, 13); }
    _V_.DOMIsReady = true;
    if (_V_.DOMReadyList) {
      for (var i=0; i<_V_.DOMReadyList.length; i++) {

        _V_.DOMReadyList[i].call(document)
      }
      _V_.DOMReadyList = null;
    }
  }

}
_V_.bindDOMReady();

////////////////////////////////////////////////////////////////////////////////
// Class Methods
// Functions that don't apply to individual videos.
////////////////////////////////////////////////////////////////////////////////

// Add VideoJS to all video tags with the video-js class when the DOM is ready
VideoJS.setupAllWhenReady = function(options){
  // Options is stored globally, and added ot any new player on init
  VideoJS.options = options;
  VideoJS.DOMReady(VideoJS.setup);
}

// Run the supplied function when the DOM is ready
VideoJS.DOMReady = function(fn){
  _V_.addToDOMReady(fn);
}

// Set up a specific video or array of video elements
// "video" can be:
//    false, undefined, or "All": set up all videos with the video-js class
//    A video tag ID or video tag element: set up one video and return one player
//    An array of video tag elements/IDs: set up each and return an array of players
VideoJS.setup = function(videos, options){

  var returnSingular = false,
  playerList = [];

  // If videos is undefined or "All", set up all videos with the video-js class
  if (!videos || videos == "All") {
    videos = VideoJS.getVideoJSTags();

  // If videos is not an array, add to an array
  } else if (typeof videos != 'object') {
    videos = [videos];
    returnSingular = true;
  }

  // Loop through videos and create players for them
  for (var i=0; i<videos.length; i++) {
    if (typeof videos[i] == 'string') {
      videoElement = document.getElementById(videos[i]);
    } else { // assume DOM object
      videoElement = videos[i];
    }
    playerList.push(new VideoJS(videoElement, options));
  }

  // Return one or all depending on what was passed in
  return (returnSingular) ? playerList[0] : playerList;
}

// Find video tags with the video-js class
VideoJS.getVideoJSTags = function() {
  var videoTags = document.getElementsByTagName("video"),
  videoJSTags = [];

  for (var i=0,j=videoTags.length; i<j; i++) {
    videoTag = videoTags[i];
    if (videoTag.className.indexOf("video-js") != -1) {
      videoJSTags.push(videoTag);
    }
  }

  return videoJSTags;
}

// Check if the browser supports video.
VideoJS.browserSupportsVideo = function() {
  if (typeof VideoJS.videoSupport != "undefined") return VideoJS.videoSupport;
  return VideoJS.videoSupport = !!document.createElement('video').canPlayType;
}

VideoJS.getFlashVersion = function(){
  // Cache Version
  if (typeof VideoJS.flashVersion != "undefined") return VideoJS.flashVersion;
  var version = 0;
  if (typeof navigator.plugins != "undefined" && typeof navigator.plugins["Shockwave Flash"] == "object") {
    desc = navigator.plugins["Shockwave Flash"].description;
    if (desc && !(typeof navigator.mimeTypes != "undefined" && navigator.mimeTypes["application/x-shockwave-flash"] && !navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)) {
      version = parseInt(desc.match(/^.*\s+([^\s]+)\.[^\s]+\s+[^\s]+$/)[1]);
    }
  } else if (typeof window.ActiveXObject != "undefined") {
    try {
      var testObject = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
      if (testObject) {
        version = parseInt(testObject.GetVariable("$version").match(/^[^\s]+\s(\d+)/)[1]);
      }
    }
    catch(e) {}
  }
  return VideoJS.flashVersion = version;
}

VideoJS.isIE = function(){ return !+"\v1"; }
VideoJS.isIpad = function(){ return navigator.userAgent.match(/iPad/i) != null; }

// Allows for binding context to functions
// when using in event listeners and timeouts
Function.prototype.context = function(obj) {
  var method = this
  temp = function() {
    return method.apply(obj, arguments)
  }
 return temp
}


                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.


.hu-css .vjs-controls {
  height: 47px; opacity: 0.95; color: #fff;
  padding-left: 84px; /* Width of play button + margin */
  padding-right: 0px; /* Width of all the controls to the right of the progress control + margins */
  background: #3A3835;
}

.hu-css .vjs-controls > li {
  background: none;
  border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0;
  box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;
}

/* Top Level Items */
.hu-css .vjs-controls > li.vjs-play-control,
.hu-css .vjs-controls > li.vjs-volume-control,
.hu-css .vjs-controls > li.vjs-fullscreen-control {
  bottom: 20px; height: 27px;
}
/* Bottom Level Items */
.hu-css .vjs-controls > li.vjs-progress-control, .hu-css .vjs-controls > li.vjs-time-control {
  margin-top: 28px; height: 19px;
}

/* Placement of Control Items */
.hu-css .vjs-controls > li.vjs-play-control       { width: 33px; left: 0px; }
.hu-css .vjs-controls > li.vjs-progress-control   { width: 100%; position: relative; }
.hu-css .vjs-controls > li.vjs-time-control       { width: 84px; left: 0px; }
.hu-css .vjs-controls > li.vjs-volume-control     { width: 43px; right: 44px; }
.hu-css .vjs-controls > li.vjs-fullscreen-control { width: 43px; right: 0px; }

/* Play/Pause
-------------------------------------------------------------------------------- */
.hu-css .vjs-play-control.vjs-play span { margin: 9px 0 0 12px; }
.hu-css .vjs-play-control.vjs-pause span { margin: 9px 0 0 12px; }
.hu-css .vjs-play-control:hover { background-color: #000; }

/* Progress
-------------------------------------------------------------------------------- */
.hu-css .vjs-progress-holder { /* Box containing play and load progresses */
  height: 19px; border: none;
  margin: 0px 0px 0 0px; /* Placement within the progress control item */
  background: #000;
  border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0;
}
.hu-css .vjs-progress-holder li { height: 13px; margin-top: 3px; border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; }
.hu-css .vjs-play-progress {
  /* Default */ background: #777;
  /* Webkit  */ background: -webkit-gradient(linear, left top, left bottom, from(#999), to(#777));
  /* Firefox */ background: -moz-linear-gradient(top,  #999,  #777);
}
.hu-css .vjs-load-progress { background: #555; }

/* Time Display
-------------------------------------------------------------------------------- */
.hu-css .vjs-controls .vjs-time-control { font-size: 11px; background: #000; }
.hu-css .vjs-controls .vjs-time-control span { line-height: 19px; /* Centering vertically */ }

/* Volume
-------------------------------------------------------------------------------- */
/*.hu-css .vjs-volume-control:hover { background-color: #000; }*/
.hu-css .vjs-volume-control ul { margin: 0 5px 0 5px; padding: 9px 0 0 0; }
.hu-css .vjs-volume-control ul li { /* Individual volume bars */
  margin: 0 2px 0 0; /* Space between */
  width: 3px; height: 0px; /* Total height is height + bottom border */
  border-bottom: 12px solid #555; /* Default (off) color and height of visible portion */
}
.hu-css .vjs-volume-control ul li.vjs-volume-level-on { border-color: #fff; /* Volume on bar color */ }
/* Creating differnt bar heights through height (transparent) and bottom border (visible). */
.hu-css .vjs-volume-control ul li:nth-child(1) { border-bottom-width: 2px; height: 10px; }
.hu-css .vjs-volume-control ul li:nth-child(2) { border-bottom-width: 4px; height: 8px; }
.hu-css .vjs-volume-control ul li:nth-child(3) { border-bottom-width: 6px; height: 6px; }
.hu-css .vjs-volume-control ul li:nth-child(4) { border-bottom-width: 8px; height: 4px; }
.hu-css .vjs-volume-control ul li:nth-child(5) { border-bottom-width: 10px; height: 2px; }

/* Fullscreen
-------------------------------------------------------------------------------- */
.hu-css .vjs-fullscreen-control:hover { background-color: #000; }
.hu-css .vjs-fullscreen-control ul { margin: 8px 0 0 0px; padding-left: 13px; height: 13px; border-left: 1px solid #555; }
.hu-css .vjs-fullscreen-control ul li:nth-child(1) { margin-right: 9px; margin-bottom: 5px; border-top: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.hu-css .vjs-fullscreen-control ul li:nth-child(2) { border-top: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.hu-css .vjs-fullscreen-control ul li:nth-child(3) { clear: both; margin: 0 9px 0 0; border-bottom: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.hu-css .vjs-fullscreen-control ul li:nth-child(4) { border-bottom: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
/* Icon when video is in fullscreen mode */
.hu-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(1) { border: none; border-bottom: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.hu-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(2) { border: none; border-bottom: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.hu-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(3) { border: none; border-top: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.hu-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(4) { border: none; border-top: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }


// Check if browser can play HTML5 video

keep keep keep keep keep replace replace keep keep keep

// Force flash fallback when there's no supported source, or flash is dominant

if (this.canPlaySource() == false || this.options.flashIsDominant) {


.tube-css .vjs-controls {
  opacity: 1; color: #000;
  height: 25px;
  padding-left: 102px; /* Width of play button + margin */
  padding-right: 83px; /* Width of all the controls to the right of the progress control + margins */

  background-color: #ccc;
  background: #fcfcfc -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#d0d0d0)) left top;
  background: #fcfcfc -moz-linear-gradient(top,  #fcfcfc,  #d0d0d0) left top;
}

.tube-css .vjs-controls > li {
  height: 23px; margin: 0; background: none;
  border: 1px solid #b1b1b1; border-left-color: #eee;
  border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0;
  box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;
}

/* Placement of Control Items */
.tube-css .vjs-controls > li.vjs-play-control       { width: 25px; left: 0; }
.tube-css .vjs-controls > li.vjs-progress-control   { width: 100%; position: relative; }
.tube-css .vjs-controls > li.vjs-time-control       { width: 75px; left: 27px; }
.tube-css .vjs-controls > li.vjs-volume-control     { width: 50px; right: 30px; }
.tube-css .vjs-controls > li.vjs-fullscreen-control { width: 30px; right: 0; }

/* Removing borders on time & progress to join them */
.tube-css .vjs-controls > li.vjs-progress-control { border-left: none; }
.tube-css .vjs-controls > li.vjs-time-control { border-right: none; }

/* Play/Pause
-------------------------------------------------------------------------------- */
.tube-css .vjs-controls > li:first-child { margin-left: 0; border-left-color: #b1b1b1; }
.tube-css .vjs-play-control.vjs-play span { border-left-color: #333; border-top-width: 7px; border-left-width: 13px; border-bottom-width: 7px; margin: 5px 0 0 7px; }
.tube-css .vjs-play-control.vjs-pause span { height: 14px; margin: 5px auto 0; border-left: 4px solid #333; border-right: 4px solid #333; }
.tube-css .vjs-play-control.vjs-play:hover span { border-left-color: #CF1A1A; }
.tube-css .vjs-play-control.vjs-pause:hover span { border-left-color: #CF1A1A; border-right-color: #CF1A1A; }

/* Time Display
-------------------------------------------------------------------------------- */
.tube-css .vjs-controls .vjs-time-control { font-size: 11px; }
.tube-css .vjs-controls .vjs-time-control span { line-height: 25px; /* Centering vertically */ }

/* Progress
-------------------------------------------------------------------------------- */
.tube-css .vjs-progress-holder {
  margin-right: 10px;
  background-color: #b1b1b1;
  background: #b1b1b1 -webkit-gradient(linear, left top, left bottom, from(#b1b1b1), to(#cacaca)) left top;
  background: #b1b1b1 -moz-linear-gradient(top,  #b1b1b1,  #cacaca) left top;
  border-color: #CACACA; border-bottom-color: #eaeaea;
  border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0;
}
.tube-css .vjs-progress-control .vjs-load-progress { background: #C89191; border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; }
.tube-css .vjs-progress-control .vjs-play-progress { background: #f33; background: -webkit-gradient(linear, left top, left bottom, from(#f33), to(#CF1A1A)); background: -moz-linear-gradient(top,  #f33,  #CF1A1A); -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; }

/* Volume
-------------------------------------------------------------------------------- */
.tube-css .vjs-volume-control ul { padding: 3px 0 0 0; }
.tube-css .vjs-volume-control ul li { border-bottom-color: #ccc; }
/* Volume icon color */
.tube-css .vjs-volume-control ul li.vjs-volume-level-on { border-color: #333; }
/* Volume icon hovering color */
.tube-css .vjs-volume-control:hover ul li.vjs-volume-level-on { border-color: #CF1A1A; }

/* Fullscreen
-------------------------------------------------------------------------------- */
.tube-css .vjs-fullscreen-control ul { margin: 4px 0 0 8px; }
/* Fullscreen icon color */
.tube-css .vjs-fullscreen-control ul li:nth-child(3), .tube-css .vjs-fullscreen-control ul li:nth-child(4), .tube-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(1), .tube-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(2) {
  border-bottom-color: #333;
}
.tube-css .vjs-fullscreen-control ul li:nth-child(1), .tube-css .vjs-fullscreen-control ul li:nth-child(2), .tube-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(3), .tube-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(4) {
  border-top-color: #333;
}
/* Fullscreen icon hovering color */
.tube-css .vjs-fullscreen-control:hover ul li:nth-child(3), .tube-css .vjs-fullscreen-control:hover ul li:nth-child(4), .tube-css.vjs-fullscreen:hover .vjs-fullscreen-control ul li:nth-child(1), .tube-css.vjs-fullscreen:hover .vjs-fullscreen-control ul li:nth-child(2) {
  border-bottom-color: #CF1A1A;
}
.tube-css .vjs-fullscreen-control:hover ul li:nth-child(1), .tube-css .vjs-fullscreen-control:hover ul li:nth-child(2), .tube-css.vjs-fullscreen:hover .vjs-fullscreen-control ul li:nth-child(3), .tube-css.vjs-fullscreen:hover .vjs-fullscreen-control ul li:nth-child(4) {
  border-top-color: #CF1A1A;
}


// Functions not specific to video or VideoJS and could be replaced with a library like jQuery

if (element.className.split(/\s+/).lastIndexOf(classToAdd) == -1) { element.className = element.className == "" ? classToAdd : element.className + " " + classToAdd; }

keep keep keep replace keep keep keep keep keep

// Functions not specific to video or VideoJS and could probably be replaced with a library like jQuery


// If videos is undefined or "All", set up all videos with the video-js class

// If videos is not an array, add to an array

keep keep keep keep keep replace keep keep keep keep

} else if (typeof videos != 'object' || videos.nodeType == 1) {


.vim-css .vjs-controls {
  height: 50px; opacity: 0.9; color: #fff;
  padding-left: 85px; /* Width of play button + margin */
  padding-right: 160px; /* Width of all the controls to the right of the progress control + margins */
}
.vim-css .vjs-controls > li {
  height: 32px; width: 25px; margin: 8px 0 0 0; padding: 0; text-align: center; background: rgba(23, 35, 34, 0.746094);
  border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0;
  box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;
}
/* Placement of Control Items */
.vim-css .vjs-controls > li.vjs-play-control       { width: 65px; left: 10px; }
.vim-css .vjs-controls > li.vjs-progress-control   { width: 100%; position: relative; }
.vim-css .vjs-controls > li.vjs-time-control       { width: 75px; right: 85px; }
.vim-css .vjs-controls > li.vjs-volume-control     { width: 50px; right: 35px; }
.vim-css .vjs-controls > li.vjs-fullscreen-control { width: 25px; right: 10px; }

/* Play/Pause
-------------------------------------------------------------------------------- */
.vim-css .vjs-controls .vjs-play-control { margin: 0; height: 40px;  border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; }
.vim-css .vjs-play-control.vjs-play span { border-left-color: #fff; border-top-width: 9px; border-left-width: 18px; border-bottom-width: 9px; margin: 11px 0 0 24px; }
.vim-css .vjs-play-control:hover { background: #00ADEF; }
.vim-css .vjs-play-control.vjs-pause span { width: 5px; height: 18px; margin: 5px auto 0; border-left: 5px solid #fff; border-right: 5px solid #fff; margin: 11px 0 0 24px; }

/* Progress
-------------------------------------------------------------------------------- */
.vim-css .vjs-controls .vjs-progress-control { border-radius: 5px 0 0 5px; -webkit-border-radius: 5px 0 0 5px; -moz-border-radius: 5px 0 0 5px; }
.vim-css .vjs-progress-control .vjs-progress-holder { height: 8px; padding: 1px; margin: 10px 5px 0 10px; border-color: #666666; border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; }
.vim-css .vjs-progress-control .vjs-play-progress { height: 8px; background: #00ADEF; border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; }
.vim-css .vjs-progress-control .vjs-load-progress { height: 8px; background: #898F8F; border-radius: 0; -webkit-border-radius: 0; -moz-border-radius: 0; }

/* Time Display
-------------------------------------------------------------------------------- */
.vim-css .vjs-controls .vjs-time-control { font-size: 11px; }
.vim-css .vjs-controls .vjs-time-control span { line-height: 32px; /* Centering vertically */ }

/* Volume
-------------------------------------------------------------------------------- */
.vim-css .vjs-volume-control ul { padding: 7px 0 0 5px; width: 30px; }
.vim-css .vjs-volume-control ul li {
  float: left; margin: 0 2px 0 0; padding: 0; list-style: none; width: 3px; height: 3px; border-bottom: 12px solid #666666;
  -webkit-transition: all 100ms linear; -moz-transition: all 100ms linear;
}
.vim-css .vjs-volume-control ul li.vjs-volume-level-on { border-color: #00ADEF; }
.vim-css .vjs-volume-control ul li:hover { height: 0; border-bottom-width: 15px; }

/* Fullscreen
-------------------------------------------------------------------------------- */
.vim-css .vjs-fullscreen-control ul { margin: 10px 0 0 0; }
.vim-css .vjs-controls .vjs-fullscreen-control { border-radius: 0 5px 5px 0; -webkit-border-radius: 0 5px 5px 0; -moz-border-radius: 0 5px 5px 0; }
/* Making default fullscreen icon smaller */
.vim-css .vjs-fullscreen-control ul li:nth-child(1) { margin: 0 4px 4px 0; border: none; border-top: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.vim-css .vjs-fullscreen-control ul li:nth-child(2) { border: none; border-top: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.vim-css .vjs-fullscreen-control ul li:nth-child(3) { clear: both; margin: 0 4px 0 0; border: none; border-bottom: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.vim-css .vjs-fullscreen-control ul li:nth-child(4) { border: none; border-bottom: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.vim-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(1) { border: none; border-bottom: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.vim-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(2) { border: none; border-bottom: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
.vim-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(3) { border: none; border-top: 4px solid #fff; border-left: 4px solid rgba(0,0,0,0); }
.vim-css.vjs-fullscreen .vjs-fullscreen-control ul li:nth-child(4) { border: none; border-top: 4px solid #fff; border-right: 4px solid rgba(0,0,0,0); }
/* Fullscreen control hovering */
.vim-css .vjs-fullscreen-control:hover ul li:nth-child(3), .vim-css .vjs-fullscreen-control:hover ul li:nth-child(4), .vim-css.vjs-fullscreen .vjs-fullscreen-control:hover ul li:nth-child(1), .vim-css.vjs-fullscreen .vjs-fullscreen-control:hover ul li:nth-child(2) { border-bottom-color: #00ADEF; }
.vim-css .vjs-fullscreen-control:hover ul li:nth-child(1), .vim-css .vjs-fullscreen-control:hover ul li:nth-child(2), .vim-css.vjs-fullscreen .vjs-fullscreen-control:hover ul li:nth-child(3), .vim-css.vjs-fullscreen .vjs-fullscreen-control:hover ul li:nth-child(4) { border-top-color: #00ADEF; }


// jQuery Plugin
if (window.jQuery) {
(function($) {
$.fn.VideoJS = function(options) {
this.each(function() {
VideoJS.setup(this, options);
});
return this;
};
})(jQuery);
}


if (!data.isTouchEvent && 'button' in e && e.button > 0) return;

if (data.isTouched && data.isMoved) return;

// change target el for shadow root componenet

const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';

if (swipingClassHasValue && e.target && e.target.shadowRoot && event.path && event.path[0]) {

// change target el for shadow root component

import { getWindow, getDocument } from 'ssr-window';
import $ from '../../utils/dom';
import { bindModuleMethods } from '../../utils/utils';

const HashNavigation = {
  onHashCange() {
    const swiper = this;
    const document = getDocument();
    swiper.emit('hashChange');
    const newHash = document.location.hash.replace('#', '');
    const activeSlideHash = swiper.slides.eq(swiper.activeIndex).attr('data-hash');
    if (newHash !== activeSlideHash) {
      const newIndex = swiper.$wrapperEl
        .children(`.${swiper.params.slideClass}[data-hash="${newHash}"]`)
        .index();
      if (typeof newIndex === 'undefined') return;
      swiper.slideTo(newIndex);
    }
  },
  setHash() {
    const swiper = this;
    const window = getWindow();
    const document = getDocument();
    if (!swiper.hashNavigation.initialized || !swiper.params.hashNavigation.enabled) return;
    if (
      swiper.params.hashNavigation.replaceState &&
      window.history &&
      window.history.replaceState
    ) {
      window.history.replaceState(
        null,
        null,
        `#${swiper.slides.eq(swiper.activeIndex).attr('data-hash')}` || '',
      );
      swiper.emit('hashSet');
    } else {
      const slide = swiper.slides.eq(swiper.activeIndex);
      const hash = slide.attr('data-hash') || slide.attr('data-history');
      document.location.hash = hash || '';
      swiper.emit('hashSet');
    }
  },
  init() {
    const swiper = this;
    const document = getDocument();
    const window = getWindow();
    if (
      !swiper.params.hashNavigation.enabled ||
      (swiper.params.history && swiper.params.history.enabled)
    )
      return;
    swiper.hashNavigation.initialized = true;
    const hash = document.location.hash.replace('#', '');
    if (hash) {
      const speed = 0;
      for (let i = 0, length = swiper.slides.length; i < length; i += 1) {
        const slide = swiper.slides.eq(i);
        const slideHash = slide.attr('data-hash') || slide.attr('data-history');
        if (slideHash === hash && !slide.hasClass(swiper.params.slideDuplicateClass)) {
          const index = slide.index();
          swiper.slideTo(index, speed, swiper.params.runCallbacksOnInit, true);
        }
      }
    }
    if (swiper.params.hashNavigation.watchState) {
      $(window).on('hashchange', swiper.hashNavigation.onHashCange);
    }
  },
  destroy() {
    const swiper = this;
    const window = getWindow();
    if (swiper.params.hashNavigation.watchState) {
      $(window).off('hashchange', swiper.hashNavigation.onHashCange);
    }
  },
};
export default {
  name: 'hash-navigation',
  params: {
    hashNavigation: {
      enabled: false,
      replaceState: false,
      watchState: false,
    },
  },
  create() {
    const swiper = this;
    bindModuleMethods(swiper, {
      hashNavigation: {
        initialized: false,
        ...HashNavigation,
      },
    });
  },
  on: {
    init(swiper) {
      if (swiper.params.hashNavigation.enabled) {
        swiper.hashNavigation.init();
      }
    },
    destroy(swiper) {
      if (swiper.params.hashNavigation.enabled) {
        swiper.hashNavigation.destroy();
      }
    },
    'transitionEnd _freeModeNoMomentumRelease': (swiper) => {
      if (swiper.hashNavigation.initialized) {
        swiper.hashNavigation.setHash();
      }
    },
    slideChange(swiper) {
      if (swiper.hashNavigation.initialized && swiper.params.cssMode) {
        swiper.hashNavigation.setHash();
      }
    },
  },
};


/* eslint no-param-reassign: "off" */
import { getDocument } from 'ssr-window';
import $ from '../../utils/dom';
import { extend, now, deleteProps } from '../../utils/utils';
import { getSupport } from '../../utils/get-support';
import { getDevice } from '../../utils/get-device';
import { getBrowser } from '../../utils/get-browser';

import Resize from '../../modules/resize/resize';
import Observer from '../../modules/observer/observer';

import modular from './modular';
import eventsEmitter from './events-emitter';

import update from './update/index';
import translate from './translate/index';
import transition from './transition/index';
import slide from './slide/index';
import loop from './loop/index';
import grabCursor from './grab-cursor/index';
import manipulation from './manipulation/index';
import events from './events/index';
import breakpoints from './breakpoints/index';
import classes from './classes/index';
import images from './images/index';
import checkOverflow from './check-overflow/index';

import defaults from './defaults';

const prototypes = {
  modular,
  eventsEmitter,
  update,
  translate,
  transition,
  slide,
  loop,
  grabCursor,
  manipulation,
  events,
  breakpoints,
  checkOverflow,
  classes,
  images,
};

const extendedDefaults = {};

class Swiper {
  constructor(...args) {
    let el;
    let params;
    if (
      args.length === 1 &&
      args[0].constructor &&
      Object.prototype.toString.call(args[0]).slice(8, -1) === 'Object'
    ) {
      params = args[0];
    } else {
      [el, params] = args;
    }
    if (!params) params = {};

    params = extend({}, params);
    if (el && !params.el) params.el = el;

    if (params.el && $(params.el).length > 1) {
      const swipers = [];
      $(params.el).each((containerEl) => {
        const newParams = extend({}, params, { el: containerEl });
        swipers.push(new Swiper(newParams));
      });
      return swipers;
    }

    // Swiper Instance
    const swiper = this;
    swiper.__swiper__ = true;
    swiper.support = getSupport();
    swiper.device = getDevice({ userAgent: params.userAgent });
    swiper.browser = getBrowser();

    swiper.eventsListeners = {};
    swiper.eventsAnyListeners = [];

    if (typeof swiper.modules === 'undefined') {
      swiper.modules = {};
    }
    Object.keys(swiper.modules).forEach((moduleName) => {
      const module = swiper.modules[moduleName];
      if (module.params) {
        const moduleParamName = Object.keys(module.params)[0];
        const moduleParams = module.params[moduleParamName];
        if (typeof moduleParams !== 'object' || moduleParams === null) return;
        if (
          ['navigation', 'pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 &&
          params[moduleParamName] === true
        ) {
          params[moduleParamName] = { auto: true };
        }
        if (!(moduleParamName in params && 'enabled' in moduleParams)) return;
        if (params[moduleParamName] === true) {
          params[moduleParamName] = { enabled: true };
        }
        if (
          typeof params[moduleParamName] === 'object' &&
          !('enabled' in params[moduleParamName])
        ) {
          params[moduleParamName].enabled = true;
        }
        if (!params[moduleParamName]) params[moduleParamName] = { enabled: false };
      }
    });

    // Extend defaults with modules params
    const swiperParams = extend({}, defaults);
    swiper.useParams(swiperParams);

    // Extend defaults with passed params
    swiper.params = extend({}, swiperParams, extendedDefaults, params);
    swiper.originalParams = extend({}, swiper.params);
    swiper.passedParams = extend({}, params);

    // add event listeners
    if (swiper.params && swiper.params.on) {
      Object.keys(swiper.params.on).forEach((eventName) => {
        swiper.on(eventName, swiper.params.on[eventName]);
      });
    }
    if (swiper.params && swiper.params.onAny) {
      swiper.onAny(swiper.params.onAny);
    }

    // Save Dom lib
    swiper.$ = $;

    // Extend Swiper
    extend(swiper, {
      enabled: swiper.params.enabled,
      el,

      // Classes
      classNames: [],

      // Slides
      slides: $(),
      slidesGrid: [],
      snapGrid: [],
      slidesSizesGrid: [],

      // isDirection
      isHorizontal() {
        return swiper.params.direction === 'horizontal';
      },
      isVertical() {
        return swiper.params.direction === 'vertical';
      },

      // Indexes
      activeIndex: 0,
      realIndex: 0,

      //
      isBeginning: true,
      isEnd: false,

      // Props
      translate: 0,
      previousTranslate: 0,
      progress: 0,
      velocity: 0,
      animating: false,

      // Locks
      allowSlideNext: swiper.params.allowSlideNext,
      allowSlidePrev: swiper.params.allowSlidePrev,

      // Touch Events
      touchEvents: (function touchEvents() {
        const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
        let desktop = ['mousedown', 'mousemove', 'mouseup'];
        if (swiper.support.pointerEvents) {
          desktop = ['pointerdown', 'pointermove', 'pointerup'];
        }
        swiper.touchEventsTouch = {
          start: touch[0],
          move: touch[1],
          end: touch[2],
          cancel: touch[3],
        };
        swiper.touchEventsDesktop = {
          start: desktop[0],
          move: desktop[1],
          end: desktop[2],
        };
        return swiper.support.touch || !swiper.params.simulateTouch
          ? swiper.touchEventsTouch
          : swiper.touchEventsDesktop;
      })(),
      touchEventsData: {
        isTouched: undefined,
        isMoved: undefined,
        allowTouchCallbacks: undefined,
        touchStartTime: undefined,
        isScrolling: undefined,
        currentTranslate: undefined,
        startTranslate: undefined,
        allowThresholdMove: undefined,
        // Form elements to match
        focusableElements: swiper.params.focusableElements,
        // Last click time
        lastClickTime: now(),
        clickTimeout: undefined,
        // Velocities
        velocities: [],
        allowMomentumBounce: undefined,
        isTouchEvent: undefined,
        startMoving: undefined,
      },

      // Clicks
      allowClick: true,

      // Touches
      allowTouchMove: swiper.params.allowTouchMove,

      touches: {
        startX: 0,
        startY: 0,
        currentX: 0,
        currentY: 0,
        diff: 0,
      },

      // Images
      imagesToLoad: [],
      imagesLoaded: 0,
    });

    // Install Modules
    swiper.useModules();

    swiper.emit('_swiper');

    // Init
    if (swiper.params.init) {
      swiper.init();
    }

    // Return app instance
    return swiper;
  }

  enable() {
    const swiper = this;
    if (swiper.enabled) return;
    swiper.enabled = true;
    if (swiper.params.grabCursor) {
      swiper.setGrabCursor();
    }
    swiper.emit('enable');
  }

  disable() {
    const swiper = this;
    if (!swiper.enabled) return;
    swiper.enabled = false;
    if (swiper.params.grabCursor) {
      swiper.unsetGrabCursor();
    }
    swiper.emit('disable');
  }

  setProgress(progress, speed) {
    const swiper = this;
    progress = Math.min(Math.max(progress, 0), 1);
    const min = swiper.minTranslate();
    const max = swiper.maxTranslate();
    const current = (max - min) * progress + min;
    swiper.translateTo(current, typeof speed === 'undefined' ? 0 : speed);
    swiper.updateActiveIndex();
    swiper.updateSlidesClasses();
  }

  emitContainerClasses() {
    const swiper = this;
    if (!swiper.params._emitClasses || !swiper.el) return;
    const classes = swiper.el.className.split(' ').filter((className) => {
      return (
        className.indexOf('swiper-container') === 0 ||
        className.indexOf(swiper.params.containerModifierClass) === 0
      );
    });
    swiper.emit('_containerClasses', classes.join(' '));
  }

  getSlideClasses(slideEl) {
    const swiper = this;

    return slideEl.className
      .split(' ')
      .filter((className) => {
        return (
          className.indexOf('swiper-slide') === 0 ||
          className.indexOf(swiper.params.slideClass) === 0
        );
      })
      .join(' ');
  }

  emitSlidesClasses() {
    const swiper = this;
    if (!swiper.params._emitClasses || !swiper.el) return;
    const updates = [];
    swiper.slides.each((slideEl) => {
      const classNames = swiper.getSlideClasses(slideEl);
      updates.push({ slideEl, classNames });
      swiper.emit('_slideClass', slideEl, classNames);
    });
    swiper.emit('_slideClasses', updates);
  }

  slidesPerViewDynamic() {
    const swiper = this;
    const { params, slides, slidesGrid, size: swiperSize, activeIndex } = swiper;
    let spv = 1;
    if (params.centeredSlides) {
      let slideSize = slides[activeIndex].swiperSlideSize;
      let breakLoop;
      for (let i = activeIndex + 1; i < slides.length; i += 1) {
        if (slides[i] && !breakLoop) {
          slideSize += slides[i].swiperSlideSize;
          spv += 1;
          if (slideSize > swiperSize) breakLoop = true;
        }
      }
      for (let i = activeIndex - 1; i >= 0; i -= 1) {
        if (slides[i] && !breakLoop) {
          slideSize += slides[i].swiperSlideSize;
          spv += 1;
          if (slideSize > swiperSize) breakLoop = true;
        }
      }
    } else {
      for (let i = activeIndex + 1; i < slides.length; i += 1) {
        if (slidesGrid[i] - slidesGrid[activeIndex] < swiperSize) {
          spv += 1;
        }
      }
    }
    return spv;
  }

  update() {
    const swiper = this;
    if (!swiper || swiper.destroyed) return;
    const { snapGrid, params } = swiper;
    // Breakpoints
    if (params.breakpoints) {
      swiper.setBreakpoint();
    }
    swiper.updateSize();
    swiper.updateSlides();
    swiper.updateProgress();
    swiper.updateSlidesClasses();

    function setTranslate() {
      const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;
      const newTranslate = Math.min(
        Math.max(translateValue, swiper.maxTranslate()),
        swiper.minTranslate(),
      );
      swiper.setTranslate(newTranslate);
      swiper.updateActiveIndex();
      swiper.updateSlidesClasses();
    }
    let translated;
    if (swiper.params.freeMode) {
      setTranslate();
      if (swiper.params.autoHeight) {
        swiper.updateAutoHeight();
      }
    } else {
      if (
        (swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) &&
        swiper.isEnd &&
        !swiper.params.centeredSlides
      ) {
        translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
      } else {
        translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
      }
      if (!translated) {
        setTranslate();
      }
    }
    if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
      swiper.checkOverflow();
    }
    swiper.emit('update');
  }

  changeDirection(newDirection, needUpdate = true) {
    const swiper = this;
    const currentDirection = swiper.params.direction;
    if (!newDirection) {
      // eslint-disable-next-line
      newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
    }
    if (
      newDirection === currentDirection ||
      (newDirection !== 'horizontal' && newDirection !== 'vertical')
    ) {
      return swiper;
    }

    swiper.$el
      .removeClass(`${swiper.params.containerModifierClass}${currentDirection}`)
      .addClass(`${swiper.params.containerModifierClass}${newDirection}`);
    swiper.emitContainerClasses();

    swiper.params.direction = newDirection;

    swiper.slides.each((slideEl) => {
      if (newDirection === 'vertical') {
        slideEl.style.width = '';
      } else {
        slideEl.style.height = '';
      }
    });

    swiper.emit('changeDirection');
    if (needUpdate) swiper.update();

    return swiper;
  }

  mount(el) {
    const swiper = this;
    if (swiper.mounted) return true;

    // Find el
    const $el = $(el || swiper.params.el);
    el = $el[0];

    if (!el) {
      return false;
    }

    el.swiper = swiper;

    const getWrapperSelector = () => {
      return `.${(swiper.params.wrapperClass || '').trim().split(' ').join('.')}`;
    };

    const getWrapper = () => {
      if (el && el.shadowRoot && el.shadowRoot.querySelector) {
        const res = $(el.shadowRoot.querySelector(getWrapperSelector()));
        // Children needs to return slot items
        res.children = (options) => $el.children(options);
        return res;
      }
      return $el.children(getWrapperSelector());
    };
    // Find Wrapper
    let $wrapperEl = getWrapper();
    if ($wrapperEl.length === 0 && swiper.params.createElements) {
      const document = getDocument();
      const wrapper = document.createElement('div');
      $wrapperEl = $(wrapper);
      wrapper.className = swiper.params.wrapperClass;
      $el.append(wrapper);
      $el.children(`.${swiper.params.slideClass}`).each((slideEl) => {
        $wrapperEl.append(slideEl);
      });
    }

    extend(swiper, {
      $el,
      el,
      $wrapperEl,
      wrapperEl: $wrapperEl[0],
      mounted: true,

      // RTL
      rtl: el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl',
      rtlTranslate:
        swiper.params.direction === 'horizontal' &&
        (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
      wrongRTL: $wrapperEl.css('display') === '-webkit-box',
    });

    return true;
  }

  init(el) {
    const swiper = this;
    if (swiper.initialized) return swiper;

    const mounted = swiper.mount(el);
    if (mounted === false) return swiper;

    swiper.emit('beforeInit');

    // Set breakpoint
    if (swiper.params.breakpoints) {
      swiper.setBreakpoint();
    }

    // Add Classes
    swiper.addClasses();

    // Create loop
    if (swiper.params.loop) {
      swiper.loopCreate();
    }

    // Update size
    swiper.updateSize();

    // Update slides
    swiper.updateSlides();

    if (swiper.params.watchOverflow) {
      swiper.checkOverflow();
    }

    // Set Grab Cursor
    if (swiper.params.grabCursor && swiper.enabled) {
      swiper.setGrabCursor();
    }

    if (swiper.params.preloadImages) {
      swiper.preloadImages();
    }

    // Slide To Initial Slide
    if (swiper.params.loop) {
      swiper.slideTo(
        swiper.params.initialSlide + swiper.loopedSlides,
        0,
        swiper.params.runCallbacksOnInit,
        false,
        true,
      );
    } else {
      swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
    }

    // Attach events
    swiper.attachEvents();

    // Init Flag
    swiper.initialized = true;

    // Emit
    swiper.emit('init');
    swiper.emit('afterInit');

    return swiper;
  }

  destroy(deleteInstance = true, cleanStyles = true) {
    const swiper = this;
    const { params, $el, $wrapperEl, slides } = swiper;

    if (typeof swiper.params === 'undefined' || swiper.destroyed) {
      return null;
    }

    swiper.emit('beforeDestroy');

    // Init Flag
    swiper.initialized = false;

    // Detach events
    swiper.detachEvents();

    // Destroy loop
    if (params.loop) {
      swiper.loopDestroy();
    }

    // Cleanup styles
    if (cleanStyles) {
      swiper.removeClasses();
      $el.removeAttr('style');
      $wrapperEl.removeAttr('style');
      if (slides && slides.length) {
        slides
          .removeClass(
            [
              params.slideVisibleClass,
              params.slideActiveClass,
              params.slideNextClass,
              params.slidePrevClass,
            ].join(' '),
          )
          .removeAttr('style')
          .removeAttr('data-swiper-slide-index');
      }
    }

    swiper.emit('destroy');

    // Detach emitter events
    Object.keys(swiper.eventsListeners).forEach((eventName) => {
      swiper.off(eventName);
    });

    if (deleteInstance !== false) {
      swiper.$el[0].swiper = null;
      deleteProps(swiper);
    }
    swiper.destroyed = true;

    return null;
  }

  static extendDefaults(newDefaults) {
    extend(extendedDefaults, newDefaults);
  }

  static get extendedDefaults() {
    return extendedDefaults;
  }

  static get defaults() {
    return defaults;
  }

  static installModule(module) {
    if (!Swiper.prototype.modules) Swiper.prototype.modules = {};
    const name = module.name || `${Object.keys(Swiper.prototype.modules).length}_${now()}`;
    Swiper.prototype.modules[name] = module;
  }

  static use(module) {
    if (Array.isArray(module)) {
      module.forEach((m) => Swiper.installModule(m));
      return Swiper;
    }
    Swiper.installModule(module);
    return Swiper;
  }
}

Object.keys(prototypes).forEach((prototypeGroup) => {
  Object.keys(prototypes[prototypeGroup]).forEach((protoMethod) => {
    Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
  });
});

Swiper.use([Resize, Observer]);

export default Swiper;


/* eslint no-unused-vars: "off" */
export default function slideReset(speed = this.params.speed, runCallbacks = true, internal) {
  const swiper = this;
  return swiper.slideTo(swiper.activeIndex, speed, runCallbacks, internal);
}


// eslint-disable-next-line
import Swiper from '../../core';
import { needsNavigation, needsPagination, needsScrollbar } from './utils';

function initSwiper(swiperParams) {
  return new Swiper(swiperParams);
}

function mountSwiper({ el, nextEl, prevEl, paginationEl, scrollbarEl, swiper }, swiperParams) {
  if (needsNavigation(swiperParams) && nextEl && prevEl) {
    swiper.params.navigation.nextEl = nextEl;
    swiper.originalParams.navigation.nextEl = nextEl;
    swiper.params.navigation.prevEl = prevEl;
    swiper.originalParams.navigation.prevEl = prevEl;
  }
  if (needsPagination(swiperParams) && paginationEl) {
    swiper.params.pagination.el = paginationEl;
    swiper.originalParams.pagination.el = paginationEl;
  }
  if (needsScrollbar(swiperParams) && scrollbarEl) {
    swiper.params.scrollbar.el = scrollbarEl;
    swiper.originalParams.scrollbar.el = scrollbarEl;
  }
  swiper.init(el);
}

export { initSwiper, mountSwiper };


import { bindModuleMethods } from '../../utils/utils';

keep keep keep keep replace keep keep keep


const pkg = require('../package.json');

const date = {
  day: new Date().getDate(),
  month:
    'January February March April May June July August September October November December'.split(
      ' ',
    )[new Date().getMonth()],
  year: new Date().getFullYear(),
};

module.exports = (name = null) =>
  `${`
/**
 * Swiper ${name ? `${name} ` : ''}${pkg.version}
 * ${pkg.description}
 * ${pkg.homepage}
 *
 * Copyright 2014-${date.year} ${pkg.author}
 *
 * Released under the ${pkg.license} License
 *
 * Released on: ${date.month} ${date.day}, ${date.year}
 */
`.trim()}\n`;


import setGrabCursor from './setGrabCursor';
import unsetGrabCursor from './unsetGrabCursor';

export default {
  setGrabCursor,
  unsetGrabCursor,
};


keep keep keep replace keep keep keep keep

import { getWindow, getDocument } from 'ssr-window';
import $ from '../../../utils/dom';
import { extend, now } from '../../../utils/utils';

export default function onTouchStart(event) {
  const swiper = this;
  const document = getDocument();
  const window = getWindow();

  const data = swiper.touchEventsData;
  const { params, touches, enabled } = swiper;
  if (!enabled) return;

  if (swiper.animating && params.preventInteractionOnTransition) {
    return;
  }
  let e = event;
  if (e.originalEvent) e = e.originalEvent;
  let $targetEl = $(e.target);

  if (params.touchEventsTarget === 'wrapper') {
    if (!$targetEl.closest(swiper.wrapperEl).length) return;
  }
  data.isTouchEvent = e.type === 'touchstart';
  if (!data.isTouchEvent && 'which' in e && e.which === 3) return;
  if (!data.isTouchEvent && 'button' in e && e.button > 0) return;
  if (data.isTouched && data.isMoved) return;

  // change target el for shadow root componenet
  const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
  if (swipingClassHasValue && e.target && e.target.shadowRoot && event.path && event.path[0]) {
    $targetEl = $(event.path[0]);
  }

  if (
    params.noSwiping &&
    $targetEl.closest(
      params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`,
    )[0]
  ) {
    swiper.allowClick = true;
    return;
  }

  if (params.swipeHandler) {
    if (!$targetEl.closest(params.swipeHandler)[0]) return;
  }

  touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
  touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
  const startX = touches.currentX;
  const startY = touches.currentY;

  // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore

  const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;
  const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;
  if (
    edgeSwipeDetection &&
    (startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)
  ) {
    if (edgeSwipeDetection === 'prevent') {
      event.preventDefault();
    } else {
      return;
    }
  }

  extend(data, {
    isTouched: true,
    isMoved: false,
    allowTouchCallbacks: true,
    isScrolling: undefined,
    startMoving: undefined,
  });

  touches.startX = startX;
  touches.startY = startY;
  data.touchStartTime = now();
  swiper.allowClick = true;
  swiper.updateSize();
  swiper.swipeDirection = undefined;
  if (params.threshold > 0) data.allowThresholdMove = false;
  if (e.type !== 'touchstart') {
    let preventDefault = true;
    if ($targetEl.is(data.focusableElements)) preventDefault = false;
    if (
      document.activeElement &&
      $(document.activeElement).is(data.focusableElements) &&
      document.activeElement !== $targetEl[0]
    ) {
      document.activeElement.blur();
    }

    const shouldPreventDefault =
      preventDefault && swiper.allowTouchMove && params.touchStartPreventDefault;
    if (
      (params.touchStartForcePreventDefault || shouldPreventDefault) &&
      !$targetEl[0].isContentEditable
    ) {
      e.preventDefault();
    }
  }
  swiper.emit('touchStart', e);
}


contact_links:
  - name: 🙏 Open Collective
    url: https://opencollective.com/swiper/
    about: Love Swiper? Please consider supporting us via Open Collective.
  - name: 📃 Documentation Issue
    url: https://github.com/nolimits4web/swiper-website/issues/new
    about: Issues with Swiper website