PageSourceSearch

https://steerbidder.com/_static/??-eJyVjs0OwjAMg1+ILUwaYhfEo6AsjVi…CwSAxA+cjGO1Wuq0KZPzTVduvNwGo7d0PdP1EtZig==

js steerbidder.com collected 2026-09-26 03:44:51 UTC 215,313 bytes, 5,155 lines download raw bytes

1(()=>{const e=document.querySelectorAll(".coblocks-animate");if("IntersectionObserver"in window){const t=new IntersectionObserver((e=>{e.forEach((e=>{e.isIntersecting&&(e.target.classList.add(e.target.dataset.coblocksAnimation),t.unobserve(e.target))}))}),{threshold:[.15]});e.forEach((e=>{t.observe(e)}))}else e.forEach((e=>{e.classList.remove("coblocks-animate"),delete e.dataset.coblocksAnimation}))})();;
2/*!
3* FitVids 1.1
4*
5* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
6* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
7* Released under the WTFPL license - http://sam.zoy.org/wtfpl/
8*
9*/
10(function( $ ){
11
12  "use strict";
13
14  $.fn.fitVids = function( options ) {
15    var settings = {
16      customSelector: null
17    };
18
19    if(!document.getElementById('fit-vids-style')) {
20      // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
21      var head = document.head || document.getElementsByTagName('head')[0];
22      var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
23      var div = document.createElement('div');
24      div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
25      head.appendChild(div.childNodes[1]);
26    }
27
28    if ( options ) {
29      $.extend( settings, options );
30    }
31
32    return this.each(function(){
33      var selectors = [
34        "iframe[src*='player.vimeo.com']",
35        "iframe[src*='youtube.com']",
36        "iframe[src*='youtube-nocookie.com']",
37        "iframe[src*='kickstarter.com'][src*='video.html']",
38        "object",
39        "embed"
40      ];
41
42      if (settings.customSelector) {
43        selectors.push(settings.customSelector);
44      }
45
46      var $allVideos = $(this).find(selectors.join(','));
47      $allVideos = $allVideos.not("object object"); // SwfObj conflict patch
48
49      $allVideos.each(function(){
50        var $this = $(this);
51        if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
52        var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
53            width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
54            aspectRatio = height / width;
55        if(!$this.attr('id')){
56          var videoID = 'fitvid' + Math.floor(Math.random()*999999);
57          $this.attr('id', videoID);
58        }
59        $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%");
60        $this.removeAttr('height').removeAttr('width');
61      });
62    });
63  };
64// Works with either jQuery or Zepto
65})( window.jQuery || window.Zepto );
66/*
67 * jQuery FlexSlider v2.2.0
68 * Copyright 2012 WooThemes
69 * Contributing Author: Tyler Smith
70 */
71;
72(function ($) {
73
74  //FlexSlider: Object Instance
75  $.flexslider = function(el, options) {
76    var slider = $(el);
77
78    // making variables public
79    slider.vars = $.extend({}, $.flexslider.defaults, options);
80
81    var namespace = slider.vars.namespace,
82        msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
83        touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch,
84        // depricating this idea, as devices are being released with both of these events
85        //eventType = (touch) ? "touchend" : "click",
86        eventType = "click touchend MSPointerUp",
87        watchedEvent = "",
88        watchedEventClearTimer,
89        vertical = slider.vars.direction === "vertical",
90        reverse = slider.vars.reverse,
91        carousel = (slider.vars.itemWidth > 0),
92        fade = slider.vars.animation === "fade",
93        asNav = slider.vars.asNavFor !== "",
94        methods = {},
95        focused = true;
96
97    // Store a reference to the slider object
98    $.data(el, "flexslider", slider);
99
100    // Private slider methods
101    methods = {
102      init: function() {
103        slider.animating = false;
104        // Get current slide and make sure it is a number
105        slider.currentSlide = parseInt( ( slider.vars.startAt ? slider.vars.startAt : 0) );
106        if ( isNaN( slider.currentSlide ) ) slider.currentSlide = 0;
107        slider.animatingTo = slider.currentSlide;
108        slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last);
109        slider.containerSelector = slider.vars.selector.substr(0,slider.vars.selector.search(' '));
110        slider.slides = $(slider.vars.selector, slider);
111        slider.container = $(slider.containerSelector, slider);
112        slider.count = slider.slides.length;
113        // SYNC:
114        slider.syncExists = $(slider.vars.sync).length > 0;
115        // SLIDE:
116        if (slider.vars.animation === "slide") slider.vars.animation = "swing";
117        slider.prop = (vertical) ? "top" : "marginLeft";
118        slider.args = {};
119        // SLIDESHOW:
120        slider.manualPause = false;
121        slider.stopped = false;
122        //PAUSE WHEN INVISIBLE
123        slider.started = false;
124        slider.startTimeout = null;
125        // TOUCH/USECSS:
126        slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() {
127          var obj = document.createElement('div'),
128              props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
129          for (var i in props) {
130            if ( obj.style[ props[i] ] !== undefined ) {
131              slider.pfx = props[i].replace('Perspective','').toLowerCase();
132              slider.prop = "-" + slider.pfx + "-transform";
133              return true;
134            }
135          }
136          return false;
137        }());
138        // CONTROLSCONTAINER:
139        if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer);
140        // MANUAL:
141        if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls);
142
143        // RANDOMIZE:
144        if (slider.vars.randomize) {
145          slider.slides.sort(function() { return (Math.round(Math.random())-0.5); });
146          slider.container.empty().append(slider.slides);
147        }
148
149        slider.doMath();
150
151        // INIT
152        slider.setup("init");
153
154        // CONTROLNAV:
155        if (slider.vars.controlNav) methods.controlNav.setup();
156
157        // DIRECTIONNAV:
158        if (slider.vars.directionNav) methods.directionNav.setup();
159
160        // KEYBOARD:
161        if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) {
162          $(document).bind('keyup', function(event) {
163            var keycode = event.keyCode;
164            if (!slider.animating && (keycode === 39 || keycode === 37)) {
165              var target = (keycode === 39) ? slider.getTarget('next') :
166                           (keycode === 37) ? slider.getTarget('prev') : false;
167              slider.flexAnimate(target, slider.vars.pauseOnAction);
168            }
169          });
170        }
171        // MOUSEWHEEL:
172        if (slider.vars.mousewheel) {
173          slider.bind('mousewheel', function(event, delta, deltaX, deltaY) {
174            event.preventDefault();
175            var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev');
176            slider.flexAnimate(target, slider.vars.pauseOnAction);
177          });
178        }
179
180        // PAUSEPLAY
181        if (slider.vars.pausePlay) methods.pausePlay.setup();
182
183        //PAUSE WHEN INVISIBLE
184        if (slider.vars.slideshow && slider.vars.pauseInvisible) methods.pauseInvisible.init();
185
186        // SLIDSESHOW
187        if (slider.vars.slideshow) {
188          if (slider.vars.pauseOnHover) {
189            slider.hover(function() {
190              if (!slider.manualPlay && !slider.manualPause) slider.pause();
191            }, function() {
192              if (!slider.manualPause && !slider.manualPlay && !slider.stopped) slider.play();
193            });
194          }
195          // initialize animation
196          //If we're visible, or we don't use PageVisibility API
vendor: 16,379 bytes, lines 197-565
197          if(!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) {
198            (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play();
199          }
200        }
201
202        // ASNAV:
203        if (asNav) methods.asNav.setup();
204
205        // TOUCH
206        if (touch && slider.vars.touch) methods.touch();
207
208        // FADE&&SMOOTHHEIGHT || SLIDE:
209        if (!fade || (fade && slider.vars.smoothHeight)) $(window).bind("resize orientationchange focus", methods.resize);
210
211        slider.find("img").attr("draggable", "false");
212
213        // API: start() Callback
214        setTimeout(function(){
215          slider.vars.start(slider);
216        }, 200);
217      },
218      asNav: {
219        setup: function() {
220          slider.asNav = true;
221          slider.animatingTo = Math.floor(slider.currentSlide/slider.move);
222          slider.currentItem = slider.currentSlide;
223          slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide");
224          if(!msGesture){
225              slider.slides.click(function(e){
226                e.preventDefault();
227                var $slide = $(this),
228                    target = $slide.index();
229                var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
230                if( posFromLeft <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) {
231                  slider.flexAnimate(slider.getTarget("prev"), true);
232                } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) {
233                  slider.direction = (slider.currentItem < target) ? "next" : "prev";
234                  slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
235                }
236              });
237          }else{
238              el._slider = slider;
239              slider.slides.each(function (){
240                  var that = this;
241                  that._gesture = new MSGesture();
242                  that._gesture.target = that;
243                  that.addEventListener("MSPointerDown", function (e){
244                      e.preventDefault();
245                      if(e.currentTarget._gesture)
246                          e.currentTarget._gesture.addPointer(e.pointerId);
247                  }, false);
248                  that.addEventListener("MSGestureTap", function (e){
249                      e.preventDefault();
250                      var $slide = $(this),
251                          target = $slide.index();
252                      if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) {
253                          slider.direction = (slider.currentItem < target) ? "next" : "prev";
254                          slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
255                      }
256                  });
257              });
258          }
259        }
260      },
261      controlNav: {
262        setup: function() {
263          if (!slider.manualControls) {
264            methods.controlNav.setupPaging();
265          } else { // MANUALCONTROLS:
266            methods.controlNav.setupManual();
267          }
268        },
269        setupPaging: function() {
270          var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging',
271              j = 1,
272              item,
273              slide;
274
275          slider.controlNavScaffold = $('<ol class="'+ namespace + 'control-nav ' + namespace + type + '"></ol>');
276
277          if (slider.pagingCount > 1) {
278            for (var i = 0; i < slider.pagingCount; i++) {
279              slide = slider.slides.eq(i);
280              item = (slider.vars.controlNav === "thumbnails") ? '<img src="' + slide.attr( 'data-thumb' ) + '"/>' : '<a>' + j + '</a>';
281              if ( 'thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions ) {
282                var captn = slide.attr( 'data-thumbcaption' );
283                if ( '' != captn && undefined != captn ) item += '<span class="' + namespace + 'caption">' + captn + '</span>';
284              }
285              slider.controlNavScaffold.append('<li>' + item + '</li>');
286              j++;
287            }
288          }
289
290          // CONTROLSCONTAINER:
291          (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold);
292          methods.controlNav.set();
293
294          methods.controlNav.active();
295
296          slider.controlNavScaffold.delegate('a, img', eventType, function(event) {
297            event.preventDefault();
298
299            if (watchedEvent === "" || watchedEvent === event.type) {
300              var $this = $(this),
301                  target = slider.controlNav.index($this);
302
303              if (!$this.hasClass(namespace + 'active')) {
304                slider.direction = (target > slider.currentSlide) ? "next" : "prev";
305                slider.flexAnimate(target, slider.vars.pauseOnAction);
306              }
307            }
308
309            // setup flags to prevent event duplication
310            if (watchedEvent === "") {
311              watchedEvent = event.type;
312            }
313            methods.setToClearWatchedEvent();
314
315          });
316        },
317        setupManual: function() {
318          slider.controlNav = slider.manualControls;
319          methods.controlNav.active();
320
321          slider.controlNav.bind(eventType, function(event) {
322            event.preventDefault();
323
324            if (watchedEvent === "" || watchedEvent === event.type) {
325              var $this = $(this),
326                  target = slider.controlNav.index($this);
327
328              if (!$this.hasClass(namespace + 'active')) {
329                (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev";
330                slider.flexAnimate(target, slider.vars.pauseOnAction);
331              }
332            }
333
334            // setup flags to prevent event duplication
335            if (watchedEvent === "") {
336              watchedEvent = event.type;
337            }
338            methods.setToClearWatchedEvent();
339          });
340        },
341        set: function() {
342          var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a';
343          slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider);
344        },
345        active: function() {
346          slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active");
347        },
348        update: function(action, pos) {
349          if (slider.pagingCount > 1 && action === "add") {
350            slider.controlNavScaffold.append($('<li><a>' + slider.count + '</a></li>'));
351          } else if (slider.pagingCount === 1) {
352            slider.controlNavScaffold.find('li').remove();
353          } else {
354            slider.controlNav.eq(pos).closest('li').remove();
355          }
356          methods.controlNav.set();
357          (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active();
358        }
359      },
360      directionNav: {
361        setup: function() {
362          var directionNavScaffold = $('<ul class="' + namespace + 'direction-nav"><li><a class="' + namespace + 'prev" href="#">' + slider.vars.prevText + '</a></li><li><a class="' + namespace + 'next" href="#">' + slider.vars.nextText + '</a></li></ul>');
363
364          // CONTROLSCONTAINER:
365          if (slider.controlsContainer) {
366            $(slider.controlsContainer).append(directionNavScaffold);
367            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer);
368          } else {
369            slider.append(directionNavScaffold);
370            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider);
371          }
372
373          methods.directionNav.update();
374
375          slider.directionNav.bind(eventType, function(event) {
376            event.preventDefault();
377            var target;
378
379            if (watchedEvent === "" || watchedEvent === event.type) {
380              target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev');
381              slider.flexAnimate(target, slider.vars.pauseOnAction);
382            }
383
384            // setup flags to prevent event duplication
385            if (watchedEvent === "") {
386              watchedEvent = event.type;
387            }
388            methods.setToClearWatchedEvent();
389          });
390        },
391        update: function() {
392          var disabledClass = namespace + 'disabled';
393          if (slider.pagingCount === 1) {
394            slider.directionNav.addClass(disabledClass).attr('tabindex', '-1');
395          } else if (!slider.vars.animationLoop) {
396            if (slider.animatingTo === 0) {
397              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1');
398            } else if (slider.animatingTo === slider.last) {
399              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1');
400            } else {
401              slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
402            }
403          } else {
404            slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
405          }
406        }
407      },
408      pausePlay: {
409        setup: function() {
410          var pausePlayScaffold = $('<div class="' + namespace + 'pauseplay"><a></a></div>');
411
412          // CONTROLSCONTAINER:
413          if (slider.controlsContainer) {
414            slider.controlsContainer.append(pausePlayScaffold);
415            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer);
416          } else {
417            slider.append(pausePlayScaffold);
418            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider);
419          }
420
421          methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play');
422
423          slider.pausePlay.bind(eventType, function(event) {
424            event.preventDefault();
425
426            if (watchedEvent === "" || watchedEvent === event.type) {
427              if ($(this).hasClass(namespace + 'pause')) {
428                slider.manualPause = true;
429                slider.manualPlay = false;
430                slider.pause();
431              } else {
432                slider.manualPause = false;
433                slider.manualPlay = true;
434                slider.play();
435              }
436            }
437
438            // setup flags to prevent event duplication
439            if (watchedEvent === "") {
440              watchedEvent = event.type;
441            }
442            methods.setToClearWatchedEvent();
443          });
444        },
445        update: function(state) {
446          (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText);
447        }
448      },
449      touch: function() {
450        var startX,
451          startY,
452          offset,
453          cwidth,
454          dx,
455          startT,
456          scrolling = false,
457          localX = 0,
458          localY = 0,
459          accDx = 0;
460
461        if(!msGesture){
462            el.addEventListener('touchstart', onTouchStart, false);
463
464            function onTouchStart(e) {
465              if (slider.animating) {
466                e.preventDefault();
467              } else if ( ( window.navigator.msPointerEnabled ) || e.touches.length === 1 ) {
468                slider.pause();
469                // CAROUSEL:
470                cwidth = (vertical) ? slider.h : slider. w;
471                startT = Number(new Date());
472                // CAROUSEL:
473
474                // Local vars for X and Y points.
475                localX = e.touches[0].pageX;
476                localY = e.touches[0].pageY;
477
478                offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
479                         (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
480                         (carousel && slider.currentSlide === slider.last) ? slider.limit :
481                         (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
482                         (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
483                startX = (vertical) ? localY : localX;
484                startY = (vertical) ? localX : localY;
485
486                el.addEventListener('touchmove', onTouchMove, false);
487                el.addEventListener('touchend', onTouchEnd, false);
488              }
489            }
490
491            function onTouchMove(e) {
492              // Local vars for X and Y points.
493
494              localX = e.touches[0].pageX;
495              localY = e.touches[0].pageY;
496
497              dx = (vertical) ? startX - localY : startX - localX;
498              scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY));
499
500              var fxms = 500;
501
502              if ( ! scrolling || Number( new Date() ) - startT > fxms ) {
503                e.preventDefault();
504                if (!fade && slider.transitions) {
505                  if (!slider.vars.animationLoop) {
506                    dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1);
507                  }
508                  slider.setProps(offset + dx, "setTouch");
509                }
510              }
511            }
512
513            function onTouchEnd(e) {
514              // finish the touch by undoing the touch session
515              el.removeEventListener('touchmove', onTouchMove, false);
516
517              if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
518                var updateDx = (reverse) ? -dx : dx,
519                    target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
520
521                if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
522                  slider.flexAnimate(target, slider.vars.pauseOnAction);
523                } else {
524                  if (!fade) slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true);
525                }
526              }
527              el.removeEventListener('touchend', onTouchEnd, false);
528
529              startX = null;
530              startY = null;
531              dx = null;
532              offset = null;
533            }
534        }else{
535            el.style.msTouchAction = "none";
536            el._gesture = new MSGesture();
537            el._gesture.target = el;
538            el.addEventListener("MSPointerDown", onMSPointerDown, false);
539            el._slider = slider;
540            el.addEventListener("MSGestureChange", onMSGestureChange, false);
541            el.addEventListener("MSGestureEnd", onMSGestureEnd, false);
542
543            function onMSPointerDown(e){
544                e.stopPropagation();
545                if (slider.animating) {
546                    e.preventDefault();
547                }else{
548                    slider.pause();
549                    el._gesture.addPointer(e.pointerId);
550                    accDx = 0;
551                    cwidth = (vertical) ? slider.h : slider. w;
552                    startT = Number(new Date());
553                    // CAROUSEL:
554
555                    offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
556                        (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
557                            (carousel && slider.currentSlide === slider.last) ? slider.limit :
558                                (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
559                                    (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
560                }
561            }
562
563            function onMSGestureChange(e) {
564                e.stopPropagation();
565                var slider = e.target._slider;
566                if(!slider){
567                    return;
568                }
569                var transX = -e.translationX,
570                    transY = -e.translationY;
571
572                //Accumulate translations.
573                accDx = accDx + ((vertical) ? transY : transX);
574                dx = accDx;
575                scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY));
576
577                if(e.detail === e.MSGESTURE_FLAG_INERTIA){
578                    setImmediate(function (){
579                        el._gesture.stop();
580                    });
581
582                    return;
583                }
584
585                if (!scrolling || Number(new Date()) - startT > 500) {
586                    e.preventDefault();
587                    if (!fade && slider.transitions) {
588                        if (!slider.vars.animationLoop) {
589                            dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1);
590                        }
591                        slider.setProps(offset + dx, "setTouch");
592                    }
593                }
594            }
595
596            function onMSGestureEnd(e) {
597                e.stopPropagation();
598                var slider = e.target._slider;
599                if(!slider){
600                    return;
601                }
602                if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
603                    var updateDx = (reverse) ? -dx : dx,
604                        target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
605
606                    if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
607                        slider.flexAnimate(target, slider.vars.pauseOnAction);
608                    } else {
609                        if (!fade) slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true);
610                    }
611                }
612
613                startX = null;
614                startY = null;
615                dx = null;
616                offset = null;
617                accDx = 0;
618            }
619        }
620      },
621      resize: function() {
622        if (!slider.animating && slider.is(':visible')) {
623          if (!carousel) slider.doMath();
624
625          if (fade) {
626            // SMOOTH HEIGHT:
627            methods.smoothHeight();
628          } else if (carousel) { //CAROUSEL:
629            slider.slides.width(slider.computedW);
630            slider.update(slider.pagingCount);
631            slider.setProps();
632          }
633          else if (vertical) { //VERTICAL:
634            slider.viewport.height(slider.h);
635            slider.setProps(slider.h, "setTotal");
636          } else {
637            // SMOOTH HEIGHT:
638            if (slider.vars.smoothHeight) methods.smoothHeight();
639            slider.newSlides.width(slider.computedW);
640            slider.setProps(slider.computedW, "setTotal");
641          }
642        }
643      },
644      smoothHeight: function(dur) {
645        if (!vertical || fade) {
646          var $obj = (fade) ? slider : slider.viewport;
647          (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).height()}, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height());
648        }
649      },
650      sync: function(action) {
651        var $obj = $(slider.vars.sync).data("flexslider"),
652            target = slider.animatingTo;
653
654        switch (action) {
655          case "animate": $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); break;
656          case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break;
657          case "pause": $obj.pause(); break;
658        }
659      },
660      pauseInvisible: {
661        visProp: null,
662        init: function() {
663          var prefixes = ['webkit','moz','ms','o'];
664
665          if ('hidden' in document) return 'hidden';
666          for (var i = 0; i < prefixes.length; i++) {
667            if ((prefixes[i] + 'Hidden') in document)
668            methods.pauseInvisible.visProp = prefixes[i] + 'Hidden';
669          }
670          if (methods.pauseInvisible.visProp) {
671            var evtname = methods.pauseInvisible.visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
672            document.addEventListener(evtname, function() {
673              if (methods.pauseInvisible.isHidden()) {
674                if(slider.startTimeout) clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible
675                else slider.pause(); //Or just pause
676              }
677              else {
678                if(slider.started) slider.play(); //Initiated before, just play
679                else (slider.vars.initDelay > 0) ? setTimeout(slider.play, slider.vars.initDelay) : slider.play(); //Didn't init before: simply init or wait for it
680              }
681            });
682          }
683        },
684        isHidden: function() {
685          return document[methods.pauseInvisible.visProp] || false;
686        }
687      },
688      setToClearWatchedEvent: function() {
689        clearTimeout(watchedEventClearTimer);
690        watchedEventClearTimer = setTimeout(function() {
691          watchedEvent = "";
692        }, 3000);
693      }
694    }
695
696    // public methods
697    slider.flexAnimate = function(target, pause, override, withSync, fromNav) {
698      if (!slider.vars.animationLoop && target !== slider.currentSlide) {
699        slider.direction = (target > slider.currentSlide) ? "next" : "prev";
700      }
701
702      if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev";
703
vendor: 5,333 bytes, lines 704-816
704      if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) {
705        if (asNav && withSync) {
706          var master = $(slider.vars.asNavFor).data('flexslider');
707          slider.atEnd = target === 0 || target === slider.count - 1;
708          master.flexAnimate(target, true, false, true, fromNav);
709          slider.direction = (slider.currentItem < target) ? "next" : "prev";
710          master.direction = slider.direction;
711
712          if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) {
713            slider.currentItem = target;
714            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
715            target = Math.floor(target/slider.visible);
716          } else {
717            slider.currentItem = target;
718            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
719            return false;
720          }
721        }
722
723        slider.animating = true;
724        slider.animatingTo = target;
725
726        // SLIDESHOW:
727        if (pause) slider.pause();
728
729        // API: before() animation Callback
730        slider.vars.before(slider);
731
732        // SYNC:
733        if (slider.syncExists && !fromNav) methods.sync("animate");
734
735        // CONTROLNAV
736        if (slider.vars.controlNav) methods.controlNav.active();
737
738        // !CAROUSEL:
739        // CANDIDATE: slide active class (for add/remove slide)
740        if (!carousel) slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide');
741
742        // INFINITE LOOP:
743        // CANDIDATE: atEnd
744        slider.atEnd = target === 0 || target === slider.last;
745
746        // DIRECTIONNAV:
747        if (slider.vars.directionNav) methods.directionNav.update();
748
749        if (target === slider.last) {
750          // API: end() of cycle Callback
751          slider.vars.end(slider);
752          // SLIDESHOW && !INFINITE LOOP:
753          if (!slider.vars.animationLoop) slider.pause();
754        }
755
756        // SLIDE:
757        if (!fade) {
758          var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW,
759              margin, slideString, calcNext;
760
761          // INFINITE LOOP / REVERSE:
762          if (carousel) {
763            //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin;
764            margin = slider.vars.itemMargin;
765            calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo;
766            slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext;
767          } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") {
768            slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0;
769          } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") {
770            slideString = (reverse) ? 0 : (slider.count + 1) * dimension;
771          } else {
772            slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension;
773          }
774          slider.setProps(slideString, "", slider.vars.animationSpeed);
775          if (slider.transitions) {
776            if (!slider.vars.animationLoop || !slider.atEnd) {
777              slider.animating = false;
778              slider.currentSlide = slider.animatingTo;
779            }
780            slider.container.unbind("webkitTransitionEnd transitionend");
781            slider.container.bind("webkitTransitionEnd transitionend", function() {
782              slider.wrapup(dimension);
783            });
784          } else {
785            slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){
786              slider.wrapup(dimension);
787            });
788          }
789        } else { // FADE:
790          if (!touch) {
791            //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing);
792            //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
793
794            slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing);
795            slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
796
797          } else {
798            slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
799            slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
800            slider.wrapup(dimension);
801          }
802        }
803        // SMOOTH HEIGHT:
804        if (slider.vars.smoothHeight) methods.smoothHeight(slider.vars.animationSpeed);
805      }
806    }
807    slider.wrapup = function(dimension) {
808      // SLIDE:
809      if (!fade && !carousel) {
810        if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) {
811          slider.setProps(dimension, "jumpEnd");
812        } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) {
813          slider.setProps(dimension, "jumpStart");
814        }
815      }
816      slider.animating = false;
817      slider.currentSlide = slider.animatingTo;
818      // API: after() animation Callback
819      slider.vars.after(slider);
820    }
821
822    // SLIDESHOW:
823    slider.animateSlides = function() {
824      if (!slider.animating && focused ) slider.flexAnimate(slider.getTarget("next"));
825    }
826    // SLIDESHOW:
827    slider.pause = function() {
828      clearInterval(slider.animatedSlides);
829      slider.animatedSlides = null;
830      slider.playing = false;
831      // PAUSEPLAY:
832      if (slider.vars.pausePlay) methods.pausePlay.update("play");
833      // SYNC:
834      if (slider.syncExists) methods.sync("pause");
835    }
836    // SLIDESHOW:
837    slider.play = function() {
838      if (slider.playing) clearInterval(slider.animatedSlides);
839      slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed);
840      slider.started = slider.playing = true;
841      // PAUSEPLAY:
842      if (slider.vars.pausePlay) methods.pausePlay.update("pause");
843      // SYNC:
844      if (slider.syncExists) methods.sync("play");
845    }
846    // STOP:
847    slider.stop = function () {
848      slider.pause();
849      slider.stopped = true;
850    }
851    slider.canAdvance = function(target, fromNav) {
852      // ASNAV:
853      var last = (asNav) ? slider.pagingCount - 1 : slider.last;
854      return (fromNav) ? true :
855             (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true :
856             (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false :
857             (target === slider.currentSlide && !asNav) ? false :
858             (slider.vars.animationLoop) ? true :
859             (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false :
860             (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false :
861             true;
862    }
863    slider.getTarget = function(dir) {
864      slider.direction = dir;
865      if (dir === "next") {
866        return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1;
867      } else {
868        return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1;
869      }
870    }
871
872    // SLIDE:
873    slider.setProps = function(pos, special, dur) {
874      var target = (function() {
875        var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo,
876            posCalc = (function() {
877              if (carousel) {
878                return (special === "setTouch") ? pos :
879                       (reverse && slider.animatingTo === slider.last) ? 0 :
880                       (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
881                       (slider.animatingTo === slider.last) ? slider.limit : posCheck;
882              } else {
883                switch (special) {
884                  case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos;
885                  case "setTouch": return (reverse) ? pos : pos;
886                  case "jumpEnd": return (reverse) ? pos : slider.count * pos;
887                  case "jumpStart": return (reverse) ? slider.count * pos : pos;
888                  default: return pos;
889                }
890              }
891            }());
892
893            return (posCalc * -1) + "px";
894          }());
895
896      if (slider.transitions) {
897        target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)";
898        dur = (dur !== undefined) ? (dur/1000) + "s" : "0s";
899        slider.container.css("-" + slider.pfx + "-transition-duration", dur);
900      }
901
902      slider.args[slider.prop] = target;
903      if (slider.transitions || dur === undefined) slider.container.css(slider.args);
904    }
905
906    slider.setup = function(type) {
907      // SLIDE:
908      if (!fade) {
909        var sliderOffset, arr;
910
911        if (type === "init") {
912          slider.viewport = $('<div class="' + namespace + 'viewport"></div>').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container);
913          // INFINITE LOOP:
914          slider.cloneCount = 0;
915          slider.cloneOffset = 0;
916          // REVERSE:
917          if (reverse) {
918            arr = $.makeArray(slider.slides).reverse();
919            slider.slides = $(arr);
920            slider.container.empty().append(slider.slides);
921          }
922        }
923        // INFINITE LOOP && !CAROUSEL:
924        if (slider.vars.animationLoop && !carousel) {
925          slider.cloneCount = 2;
926          slider.cloneOffset = 1;
927          // clear out old clones
928          if (type !== "init") slider.container.find('.clone').remove();
929          slider.container.append(slider.slides.first().clone().addClass('clone').attr('aria-hidden', 'true')).prepend(sli
vendor: 10,363 bytes, lines 929-1133
929der.slides.last().clone().addClass('clone').attr('aria-hidden', 'true'));
930        }
931        slider.newSlides = $(slider.vars.selector, slider);
932
933        sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset;
934        // VERTICAL:
935        if (vertical && !carousel) {
936          slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%");
937          setTimeout(function(){
938            slider.newSlides.css({"display": "block"});
939            slider.doMath();
940            slider.viewport.height(slider.h);
941            slider.setProps(sliderOffset * slider.h, "init");
942          }, (type === "init") ? 100 : 0);
943        } else {
944          slider.container.width((slider.count + slider.cloneCount) * 200 + "%");
945          slider.setProps(sliderOffset * slider.computedW, "init");
946          setTimeout(function(){
947            slider.doMath();
948            slider.newSlides.css({"width": slider.computedW, "float": "left", "display": "block"});
949            // SMOOTH HEIGHT:
950            if (slider.vars.smoothHeight) methods.smoothHeight();
951          }, (type === "init") ? 100 : 0);
952        }
953      } else { // FADE:
954        slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"});
955        if (type === "init") {
956          if (!touch) {
957            //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing);
958            slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing);
959          } else {
960            slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2});
961          }
962        }
963        // SMOOTH HEIGHT:
964        if (slider.vars.smoothHeight) methods.smoothHeight();
965      }
966      // !CAROUSEL:
967      // CANDIDATE: active slide
968      if (!carousel) slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide");
969    }
970
971
972    slider.doMath = function() {
973      var slide = slider.slides.first(),
974          slideMargin = slider.vars.itemMargin,
975          minItems = slider.vars.minItems,
976          maxItems = slider.vars.maxItems;
977
978      slider.w = (slider.viewport===undefined) ? slider.width() : slider.viewport.width();
979      slider.h = slide.height();
980      slider.boxPadding = slide.outerWidth() - slide.width();
981
982      // CAROUSEL:
983      if (carousel) {
984        slider.itemT = slider.vars.itemWidth + slideMargin;
985        slider.minW = (minItems) ? minItems * slider.itemT : slider.w;
986        slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w;
987        slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1)))/minItems :
988                       (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1)))/maxItems :
989                       (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth;
990
991        slider.visible = Math.floor(slider.w/(slider.itemW));
992        slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible;
993        slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1);
994        slider.last =  slider.pagingCount - 1;
995        slider.limit = (slider.pagingCount === 1) ? 0 :
996                       (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin;
997      } else {
998        slider.itemW = slider.w;
999        slider.pagingCount = slider.count;
1000        slider.last = slider.count - 1;
1001      }
1002      slider.computedW = slider.itemW - slider.boxPadding;
1003    }
1004
1005
1006    slider.update = function(pos, action) {
1007      slider.doMath();
1008
1009      // update currentSlide and slider.animatingTo if necessary
1010      if (!carousel) {
1011        if (pos < slider.currentSlide) {
1012          slider.currentSlide += 1;
1013        } else if (pos <= slider.currentSlide && pos !== 0) {
1014          slider.currentSlide -= 1;
1015        }
1016        slider.animatingTo = slider.currentSlide;
1017      }
1018
1019      // update controlNav
1020      if (slider.vars.controlNav && !slider.manualControls) {
1021        if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) {
1022          methods.controlNav.update("add");
1023        } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) {
1024          if (carousel && slider.currentSlide > slider.last) {
1025            slider.currentSlide -= 1;
1026            slider.animatingTo -= 1;
1027          }
1028          methods.controlNav.update("remove", slider.last);
1029        }
1030      }
1031      // update directionNav
1032      if (slider.vars.directionNav) methods.directionNav.update();
1033
1034    }
1035
1036    slider.addSlide = function(obj, pos) {
1037      var $obj = $(obj);
1038
1039      slider.count += 1;
1040      slider.last = slider.count - 1;
1041
1042      // append new slide
1043      if (vertical && reverse) {
1044        (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj);
1045      } else {
1046        (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj);
1047      }
1048
1049      // update currentSlide, animatingTo, controlNav, and directionNav
1050      slider.update(pos, "add");
1051
1052      // update slider.slides
1053      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1054      // re-setup the slider to accomdate new slide
1055      slider.setup();
1056
1057      //FlexSlider: added() Callback
1058      slider.vars.added(slider);
1059    }
1060    slider.removeSlide = function(obj) {
1061      var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj;
1062
1063      // update count
1064      slider.count -= 1;
1065      slider.last = slider.count - 1;
1066
1067      // remove slide
1068      if (isNaN(obj)) {
1069        $(obj, slider.slides).remove();
1070      } else {
1071        (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove();
1072      }
1073
1074      // update currentSlide, animatingTo, controlNav, and directionNav
1075      slider.doMath();
1076      slider.update(pos, "remove");
1077
1078      // update slider.slides
1079      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1080      // re-setup the slider to accomdate new slide
1081      slider.setup();
1082
1083      // FlexSlider: removed() Callback
1084      slider.vars.removed(slider);
1085    }
1086
1087    //FlexSlider: Initialize
1088    methods.init();
1089  }
1090
1091  // Ensure the slider isn't focussed if the window loses focus.
1092  $( window ).blur( function ( e ) {
1093    focused = false;
1094  }).focus( function ( e ) {
1095    focused = true;
1096  });
1097
1098  //FlexSlider: Default Settings
1099  $.flexslider.defaults = {
1100    namespace: "flex-",             //{NEW} String: Prefix string attached to the class of every element generated by the plugin
1101    selector: ".slides > li",       //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
1102    animation: "fade",              //String: Select your animation type, "fade" or "slide"
1103    easing: "swing",                //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
1104    direction: "horizontal",        //String: Select the sliding direction, "horizontal" or "vertical"
1105    reverse: false,                 //{NEW} Boolean: Reverse the animation direction
1106    animationLoop: true,            //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end
1107    smoothHeight: false,            //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
1108    startAt: 0,                     //Integer: The slide that the slider should start on. Array notation (0 = first slide)
1109    slideshow: true,                //Boolean: Animate slider automatically
1110    slideshowSpeed: 7000,           //Integer: Set the speed of the slideshow cycling, in milliseconds
1111    animationSpeed: 600,            //Integer: Set the speed of animations, in milliseconds
1112    initDelay: 0,                   //{NEW} Integer: Set an initialization delay, in milliseconds
1113    randomize: false,               //Boolean: Randomize slide order
1114    thumbCaptions: false,           //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav.
1115
1116    // Usability features
1117    pauseOnAction: true,            //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
1118    pauseOnHover: false,            //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
1119    pauseInvisible: true,   		//{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
1120    useCSS: true,                   //{NEW} Boolean: Slider will use CSS3 transitions if available
1121    touch: true,                    //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
1122    video: false,                   //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
1123
1124    // Primary Controls
1125    controlNav: true,               //Boolean: Create navigation for paging control of each clide? Note: Leave true for manualControls usage
1126    directionNav: true,             //Boolean: Create navigation for previous/next navigation? (true/false)
1127    prevText: "Previous",           //String: Set the text for the "previous" directionNav item
1128    nextText: "Next",               //String: Set the text for the "next" directionNav item
1129
1130    // Secondary Navigation
1131    keyboard: true,                 //Boolean: Allow slider navigating via keyboard left/right keys
1132    multipleKeyboard: false,        //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
1133    mousewheel: false,              //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
1134    pausePlay: false,               //Boolean: Create pause/play dynamic element
1135    pauseText: "Pause",             //String: Set the text for the "pause" pausePlay item
1136    playText: "Play",               //String: Set the text for the "play" pausePlay item
1137
1138    // Special properties
1139    controlsContainer: "",          //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
1140    manualControls: "",             //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
1141    sync: "",                       //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
1142    asNavFor: "",                   //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
1143
1144    // Carousel Options
1145    itemWidth: 0,                   //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
1146    itemMargin: 0,                  //{NEW} Integer: Margin between carousel items.
1147    minItems: 1,                    //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
1148    maxItems: 0,                    //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
1149    move: 0,                        //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items.
1150    allowOneSlide: true,           //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide
1151
1152    // Callback API
1153    start: function(){},            //Callback: function(slider) - Fires when the slider loads the first slide
1154    before: function(){},           //Callback: function(slider) - Fires asynchronously with each slider animation
1155    after: function(){},            //Callback: function(slider) - Fires after each slider animation completes
1156    end: function(){},              //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
1157    added: function(){},            //{NEW} Callback: function(slider) - Fires after a slide is added
1158    removed: function(){}           //{NEW} Callback: function(slider) - Fires after a slide is removed
1159  }
1160
1161
1162  //FlexSlider: Plugin Function
1163  $.fn.flexslider = function(options) {
1164    if (options === undefined) options = {};
1165
1166    if (typeof options === "object") {
1167      return this.each(function() {
1168        var $this = $(this),
1169            selector = (options.selector) ? options.selector : ".slides > li",
1170            $slides = $this.find(selector);
1171
1172      if ( ( $slides.length === 1 && options.allowOneSlide === true ) || $slides.length === 0 ) {
1173          $slides.fadeIn(400);
1174          if (options.start) options.start($this);
1175        } else if ($this.data('flexslider') === undefined) {
1176          new $.flexslider(this, options);
1177        }
1178      });
1179    } else {
1180      // Helper strings to quickly perform functions on the slider
1181      var $slider = $(this).data('flexslider');
1182      switch (options) {
1183        case "play": $slider.play(); break;
1184        case "pause": $slider.pause(); break;
1185        case "stop": $slider.stop(); break;
1186        case "next": $slider.flexAnimate($slider.getTarget("next"), true); break;
1187        case "prev":
1188        case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break;
1189        default: if (typeof options === "number") $slider.flexAnimate(options, true);
1190      }
1191    }
1192  }
1193})(jQuery);
1194
1195/*
1196 * jPlayer Plugin for jQuery JavaScript Library
1197 * http://www.jplayer.org
1198 *
1199 * Copyright (c) 2009 - 2014 Happyworm Ltd
1200 * Licensed under the MIT license.
1201 * http://opensource.org/licenses/MIT
1202 *
1203 * Author: Mark J Panaghiston
1204 * Version: 2.6.1
1205 * Date: 3rd April 2014
1206 */
1207
1208/* Code verified using http://www.jshint.com/ */
1209/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false, smarttabs:true */
1210/*global define:false, ActiveXObject:false, alert:false */
1211
1212/* Support for Zepto 1.0 compiled with optional data module.
1213 * For AMD support, you will need to manually switch the 2 lines in the code below.
1214 * Search terms: "jQuery Switch" and "Zepto Switch"
1215 */
1216
1217(function (root, factory) {
1218	if (typeof define === 'function' && define.amd) {
1219		// AMD. Register as an anonymous module.
1220		define(['jquery'], factory); // jQuery Switch
1221		// define(['zepto'], factory); // Zepto Switch
1222	} else {
1223		// Browser globals
1224		if(root.jQuery) { // Use jQuery if available
1225			factory(root.jQuery);
1226		} else { // Otherwise, use Zepto
1227			factory(root.Zepto);
1228		}
1229	}
1230}(this, function ($, undefined) {
1231
1232	// Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge - Tweaked $.data(this,XYZ) to $(this).data(XYZ) for Zepto
1233	$.fn.jPlayer = function( options ) {
1234		var name = "jPlayer";
1235		var isMethodCall = typeof options === "string",
1236			args = Array.prototype.slice.call( arguments, 1 ),
1237			returnValue = this;
1238
1239		// allow multiple hashes to be passed on init
1240		options = !isMethodCall && args.length ?
1241			$.extend.apply( null, [ true, options ].concat(args) ) :
1242			options;
1243
1244		// prevent calls to internal methods
1245		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
1246			return returnValue;
1247		}
1248
1249		if ( isMethodCall ) {
1250			this.each(function() {
1251				var instance = $(this).data( name ),
1252					methodValue = instance && $.isFunction( instance[options] ) ?
1253						instance[ options ].apply( instance, args ) :
1254						instance;
1255				if ( methodValue !== instance && methodValue !== undefined ) {
1256					returnValue = methodValue;
1257					return false;
vendor: 18,260 bytes, lines 1258-1796
1258				}
1259			});
1260		} else {
1261			this.each(function() {
1262				var instance = $(this).data( name );
1263				if ( instance ) {
1264					// instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface.
1265					instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm.
1266				} else {
1267					$(this).data( name, new $.jPlayer( options, this ) );
1268				}
1269			});
1270		}
1271
1272		return returnValue;
1273	};
1274
1275	$.jPlayer = function( options, element ) {
1276		// allow instantiation without initializing for simple inheritance
1277		if ( arguments.length ) {
1278			this.element = $(element);
1279			this.options = $.extend(true, {},
1280				this.options,
1281				options
1282			);
1283			var self = this;
1284			this.element.bind( "remove.jPlayer", function() {
1285				self.destroy();
1286			});
1287			this._init();
1288		}
1289	};
1290	// End of: (Adapted from jquery.ui.widget.js (1.8.7))
1291
1292	// Zepto is missing one of the animation methods.
1293	if(typeof $.fn.stop !== 'function') {
1294		$.fn.stop = function() {};
1295	}
1296
1297	// Emulated HTML5 methods and properties
1298	$.jPlayer.emulateMethods = "load play pause";
1299	$.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate";
1300	$.jPlayer.emulateOptions = "muted volume";
1301
1302	// Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec
1303	$.jPlayer.reservedEvent = "ready flashreset resize repeat error warning";
1304
1305	// Events generated by jPlayer
1306	$.jPlayer.event = {};
1307	$.each(
1308		[
1309			'ready',
1310			'setmedia', // Fires when the media is set
1311			'flashreset', // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature.
1312			'resize', // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed.
1313			'repeat', // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface.
1314			'click', // Occurs when the user clicks on one of the following: poster image, html video, flash video.
1315			'error', // Event error code in event.jPlayer.error.type. See $.jPlayer.error
1316			'warning', // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning
1317
1318			// Other events match HTML5 spec.
1319			'loadstart',
1320			'progress',
1321			'suspend',
1322			'abort',
1323			'emptied',
1324			'stalled',
1325			'play',
1326			'pause',
1327			'loadedmetadata',
1328			'loadeddata',
1329			'waiting',
1330			'playing',
1331			'canplay',
1332			'canplaythrough',
1333			'seeking',
1334			'seeked',
1335			'timeupdate',
1336			'ended',
1337			'ratechange',
1338			'durationchange',
1339			'volumechange'
1340		],
1341		function() {
1342			$.jPlayer.event[ this ] = 'jPlayer_' + this;
1343		}
1344	);
1345
1346	$.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action.
1347		"loadstart",
1348		// "progress", // jPlayer uses internally before bubbling.
1349		// "suspend", // jPlayer uses internally before bubbling.
1350		"abort",
1351		// "error", // jPlayer uses internally before bubbling.
1352		"emptied",
1353		"stalled",
1354		// "play", // jPlayer uses internally before bubbling.
1355		// "pause", // jPlayer uses internally before bubbling.
1356		"loadedmetadata",
1357		"loadeddata",
1358		// "waiting", // jPlayer uses internally before bubbling.
1359		// "playing", // jPlayer uses internally before bubbling.
1360		"canplay",
1361		"canplaythrough"
1362		// "seeking", // jPlayer uses internally before bubbling.
1363		// "seeked", // jPlayer uses internally before bubbling.
1364		// "timeupdate", // jPlayer uses internally before bubbling.
1365		// "ended", // jPlayer uses internally before bubbling.
1366		// "ratechange" // jPlayer uses internally before bubbling.
1367		// "durationchange" // jPlayer uses internally before bubbling.
1368		// "volumechange" // jPlayer uses internally before bubbling.
1369	];
1370
1371	$.jPlayer.pause = function() {
1372		$.each($.jPlayer.prototype.instances, function(i, element) {
1373			if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
1374				element.jPlayer("pause");
1375			}
1376		});
1377	};
1378
1379	// Default for jPlayer option.timeFormat
1380	$.jPlayer.timeFormat = {
1381		showHour: false,
1382		showMin: true,
1383		showSec: true,
1384		padHour: false,
1385		padMin: true,
1386		padSec: true,
1387		sepHour: ":",
1388		sepMin: ":",
1389		sepSec: ""
1390	};
1391	var ConvertTime = function() {
1392		this.init();
1393	};
1394	ConvertTime.prototype = {
1395		init: function() {
1396			this.options = {
1397				timeFormat: $.jPlayer.timeFormat
1398			};
1399		},
1400		time: function(s) { // function used on jPlayer.prototype._convertTime to enable per instance options.
1401			s = (s && typeof s === 'number') ? s : 0;
1402
1403			var myTime = new Date(s * 1000),
1404				hour = myTime.getUTCHours(),
1405				min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60,
1406				sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60,
1407				strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour,
1408				strMin = (this.options.timeFormat.padMin && min < 10) ? "0" + min : min,
1409				strSec = (this.options.timeFormat.padSec && sec < 10) ? "0" + sec : sec,
1410				strTime = "";
1411
1412			strTime += this.options.timeFormat.showHour ? strHour + this.options.timeFormat.sepHour : "";
1413			strTime += this.options.timeFormat.showMin ? strMin + this.options.timeFormat.sepMin : "";
1414			strTime += this.options.timeFormat.showSec ? strSec + this.options.timeFormat.sepSec : "";
1415
1416			return strTime;
1417		}
1418	};
1419	var myConvertTime = new ConvertTime();
1420	$.jPlayer.convertTime = function(s) {
1421		return myConvertTime.time(s);
1422	};
1423
1424	// Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit.
1425	$.jPlayer.uaBrowser = function( userAgent ) {
1426		var ua = userAgent.toLowerCase();
1427
1428		// Useragent RegExp
1429		var rwebkit = /(webkit)[ \/]([\w.]+)/;
1430		var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
1431		var rmsie = /(msie) ([\w.]+)/;
1432		var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
1433
1434		var match = rwebkit.exec( ua ) ||
1435			ropera.exec( ua ) ||
1436			rmsie.exec( ua ) ||
1437			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
1438			[];
1439
1440		return { browser: match[1] || "", version: match[2] || "0" };
1441	};
1442
1443	// Platform sniffer for detecting mobile devices
1444	$.jPlayer.uaPlatform = function( userAgent ) {
1445		var ua = userAgent.toLowerCase();
1446
1447		// Useragent RegExp
1448		var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/;
1449		var rtablet = /(ipad|playbook)/;
1450		var randroid = /(android)/;
1451		var rmobile = /(mobile)/;
1452
1453		var platform = rplatform.exec( ua ) || [];
1454		var tablet = rtablet.exec( ua ) ||
1455			!rmobile.exec( ua ) && randroid.exec( ua ) ||
1456			[];
1457
1458		if(platform[1]) {
1459			platform[1] = platform[1].replace(/\s/g, "_"); // Change whitespace to underscore. Enables dot notation.
1460		}
1461
1462		return { platform: platform[1] || "", tablet: tablet[1] || "" };
1463	};
1464
1465	$.jPlayer.browser = {
1466	};
1467	$.jPlayer.platform = {
1468	};
1469
1470	var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent);
1471	if ( browserMatch.browser ) {
1472		$.jPlayer.browser[ browserMatch.browser ] = true;
1473		$.jPlayer.browser.version = browserMatch.version;
1474	}
1475	var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent);
1476	if ( platformMatch.platform ) {
1477		$.jPlayer.platform[ platformMatch.platform ] = true;
1478		$.jPlayer.platform.mobile = !platformMatch.tablet;
1479		$.jPlayer.platform.tablet = !!platformMatch.tablet;
1480	}
1481
1482	// Internet Explorer (IE) Browser Document Mode Sniffer. Based on code at:
1483	// http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx#GetMode
1484	$.jPlayer.getDocMode = function() {
1485		var docMode;
1486		if ($.jPlayer.browser.msie) {
1487			if (document.documentMode) { // IE8 or later
1488				docMode = document.documentMode;
1489			} else { // IE 5-7
1490				docMode = 5; // Assume quirks mode unless proven otherwise
1491				if (document.compatMode) {
1492					if (document.compatMode === "CSS1Compat") {
1493						docMode = 7; // standards mode
1494					}
1495				}
1496			}
1497		}
1498		return docMode;
1499	};
1500	$.jPlayer.browser.documentMode = $.jPlayer.getDocMode();
1501
1502	$.jPlayer.nativeFeatures = {
1503		init: function() {
1504
1505			/* Fullscreen function naming influenced by W3C naming.
1506			 * No support for: Mozilla Proposal: https://wiki.mozilla.org/Gecko:FullScreenAPI
1507			 */
1508
1509			var d = document,
1510				v = d.createElement('video'),
1511				spec = {
1512					// http://www.w3.org/TR/fullscreen/
1513					w3c: [
1514						'fullscreenEnabled',
1515						'fullscreenElement',
1516						'requestFullscreen',
1517						'exitFullscreen',
1518						'fullscreenchange',
1519						'fullscreenerror'
1520					],
1521					// https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
1522					moz: [
1523						'mozFullScreenEnabled',
1524						'mozFullScreenElement',
1525						'mozRequestFullScreen',
1526						'mozCancelFullScreen',
1527						'mozfullscreenchange',
1528						'mozfullscreenerror'
1529					],
1530					// http://developer.apple.com/library/safari/#documentation/WebKit/Reference/ElementClassRef/Element/Element.html
1531					// http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
1532					webkit: [
1533						'',
1534						'webkitCurrentFullScreenElement',
1535						'webkitRequestFullScreen',
1536						'webkitCancelFullScreen',
1537						'webkitfullscreenchange',
1538						''
1539					],
1540					// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
1541					// https://developer.apple.com/library/safari/samplecode/HTML5VideoEventFlow/Listings/events_js.html#//apple_ref/doc/uid/DTS40010085-events_js-DontLinkElementID_5
1542					// Events: 'webkitbeginfullscreen' and 'webkitendfullscreen'
1543					webkitVideo: [
1544						'webkitSupportsFullscreen',
1545						'webkitDisplayingFullscreen',
1546						'webkitEnterFullscreen',
1547						'webkitExitFullscreen',
1548						'',
1549						''
1550					]
1551				},
1552				specOrder = [
1553					'w3c',
1554					'moz',
1555					'webkit',
1556					'webkitVideo'
1557				],
1558				fs, i, il;
1559
1560			this.fullscreen = fs = {
1561				support: {
1562					w3c: !!d[spec.w3c[0]],
1563					moz: !!d[spec.moz[0]],
1564					webkit: typeof d[spec.webkit[3]] === 'function',
1565					webkitVideo: typeof v[spec.webkitVideo[2]] === 'function'
1566				},
1567				used: {}
1568			};
1569
1570			// Store the name of the spec being used and as a handy boolean.
1571			for(i = 0, il = specOrder.length; i < il; i++) {
1572				var n = specOrder[i];
1573				if(fs.support[n]) {
1574					fs.spec = n;
1575					fs.used[n] = true;
1576					break;
1577				}
1578			}
1579
1580			if(fs.spec) {
1581				var s = spec[fs.spec];
1582				fs.api = {
1583					fullscreenEnabled: true,
1584					fullscreenElement: function(elem) {
1585						elem = elem ? elem : d; // Video element required for webkitVideo
1586						return elem[s[1]];
1587					},
1588					requestFullscreen: function(elem) {
1589						return elem[s[2]]();
1590					},
1591					exitFullscreen: function(elem) {
1592						elem = elem ? elem : d; // Video element required for webkitVideo
1593						return elem[s[3]]();
1594					}
1595				};
1596				fs.event = {
1597					fullscreenchange: s[4],
1598					fullscreenerror: s[5]
1599				};
1600			} else {
1601				fs.api = {
1602					fullscreenEnabled: false,
1603					fullscreenElement: function() {
1604						return null;
1605					},
1606					requestFullscreen: function() {},
1607					exitFullscreen: function() {}
1608				};
1609				fs.event = {};
1610			}
1611		}
1612	};
1613	$.jPlayer.nativeFeatures.init();
1614
1615	// The keyboard control system.
1616
1617	// The current jPlayer instance in focus.
1618	$.jPlayer.focus = null;
1619
1620	// The list of element node names to ignore with key controls.
1621	$.jPlayer.keyIgnoreElementNames = "INPUT TEXTAREA";
1622
1623	// The function that deals with key presses.
1624	var keyBindings = function(event) {
1625
1626		var f = $.jPlayer.focus,
1627			ignoreKey;
1628
1629		// A jPlayer instance must be in focus. ie., keyEnabled and the last one played.
1630		if(f) {
1631			// What generated the key press?
1632			$.each( $.jPlayer.keyIgnoreElementNames.split(/\s+/g), function(i, name) {
1633				// The strings should already be uppercase.
1634				if(event.target.nodeName.toUpperCase() === name.toUpperCase()) {
1635					ignoreKey = true;
1636					return false; // exit each.
1637				}
1638			});
1639			if(!ignoreKey) {
1640				// See if the key pressed matches any of the bindings.
1641				$.each(f.options.keyBindings, function(action, binding) {
1642					// The binding could be a null when the default has been disabled. ie., 1st clause in if()
1643					if(binding && event.which === binding.key && $.isFunction(binding.fn)) {
1644						event.preventDefault(); // Key being used by jPlayer, so prevent default operation.
1645						binding.fn(f);
1646						return false; // exit each.
1647					}
1648				});
1649			}
1650		}
1651	};
1652
1653	$.jPlayer.keys = function(en) {
1654		var event = "keydown.jPlayer";
1655		// Remove any binding, just in case enabled more than once.
1656		$(document.documentElement).unbind(event);
1657		if(en) {
1658			$(document.documentElement).bind(event, keyBindings);
1659		}
1660	};
1661
1662	// Enable the global key control handler ready for any jPlayer instance with the keyEnabled option enabled.
1663	$.jPlayer.keys(true);
1664
1665	$.jPlayer.prototype = {
1666		count: 0, // Static Variable: Change it via prototype.
1667		version: { // Static Object
1668			script: "2.6.1",
1669			needFlash: "2.6.0",
1670			flash: "unknown"
1671		},
1672		options: { // Instanced in $.jPlayer() constructor
1673			swfPath: "js", // Path to Jplayer.swf. Can be relative, absolute or server root relative.
1674			solution: "html, flash", // Valid solutions: html, flash. Order defines priority. 1st is highest,
1675			supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest,
1676			preload: 'metadata',  // HTML5 Spec values: none, metadata, auto.
1677			volume: 0.8, // The volume. Number 0 to 1.
1678			muted: false,
1679			remainingDuration: false, // When true, the remaining time is shown in the duration GUI element.
1680			toggleDuration: false, // When true, clicks on the duration toggle between the duration and remaining display.
1681			captureDuration: true, // When true, clicks on the duration are captured and no longer propagate up the DOM.
1682			playbackRate: 1,
1683			defaultPlaybackRate: 1,
1684			minPlaybackRate: 0.5,
1685			maxPlaybackRate: 4,
1686			wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu.
1687			backgroundColor: "#000000", // To define the jPlayer div and Flash background color.
1688			cssSelectorAncestor: "#jp_container_1",
1689			cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults.
1690				videoPlay: ".jp-video-play", // *
1691				play: ".jp-play",
1692				pause: ".jp-pause",
1693				stop: ".jp-stop",
1694				seekBar: ".jp-seek-bar",
1695				playBar: ".jp-play-bar",
1696				mute: ".jp-mute",
1697				unmute: ".jp-unmute",
1698				volumeBar: ".jp-volume-bar",
1699				volumeBarValue: ".jp-volume-bar-value",
1700				volumeMax: ".jp-volume-max",
1701				playbackRateBar: ".jp-playback-rate-bar",
1702				playbackRateBarValue: ".jp-playback-rate-bar-value",
1703				currentTime: ".jp-current-time",
1704				duration: ".jp-duration",
1705				title: ".jp-title",
1706				fullScreen: ".jp-full-screen", // *
1707				restoreScreen: ".jp-restore-screen", // *
1708				repeat: ".jp-repeat",
1709				repeatOff: ".jp-repeat-off",
1710				gui: ".jp-gui", // The interface used with autohide feature.
1711				noSolution: ".jp-no-solution" // For error feedback when jPlayer cannot find a solution.
1712			},
1713			smoothPlayBar: false, // Smooths the play bar transitions, which affects clicks and short media with big changes per second.
1714			fullScreen: false, // Native Full Screen
1715			fullWindow: false,
1716			autohide: {
1717				restored: false, // Controls the interface autohide feature.
1718				full: true, // Controls the interface autohide feature.
1719				fadeIn: 200, // Milliseconds. The period of the fadeIn anim.
1720				fadeOut: 600, // Milliseconds. The period of the fadeOut anim.
1721				hold: 1000 // Milliseconds. The period of the pause before autohide beings.
1722			},
1723			loop: false,
1724			repeat: function(event) { // The default jPlayer repeat event handler
1725				if(event.jPlayer.options.loop) {
1726					$(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
1727						$(this).jPlayer("play");
1728					});
1729				} else {
1730					$(this).unbind(".jPlayerRepeat");
1731				}
1732			},
1733			nativeVideoControls: {
1734				// Works well on standard browsers.
1735				// Phone and tablet browsers can have problems with the controls disappearing.
1736			},
1737			noFullWindow: {
1738				msie: /msie [0-6]\./,
1739				ipad: /ipad.*?os [0-4]\./,
1740				iphone: /iphone/,
1741				ipod: /ipod/,
1742				android_pad: /android [0-3]\.(?!.*?mobile)/,
1743				android_phone: /android.*?mobile/,
1744				blackberry: /blackberry/,
1745				windows_ce: /windows ce/,
1746				iemobile: /iemobile/,
1747				webos: /webos/
1748			},
1749			noVolume: {
1750				ipad: /ipad/,
1751				iphone: /iphone/,
1752				ipod: /ipod/,
1753				android_pad: /android(?!.*?mobile)/,
1754				android_phone: /android.*?mobile/,
1755				blackberry: /blackberry/,
1756				windows_ce: /windows ce/,
1757				iemobile: /iemobile/,
1758				webos: /webos/,
1759				playbook: /playbook/
1760			},
1761			timeFormat: {
1762				// Specific time format for this instance. The supported options are defined in $.jPlayer.timeFormat
1763				// For the undefined options we use the default from $.jPlayer.timeFormat
1764			},
1765			keyEnabled: false, // Enables keyboard controls.
1766			audioFullScreen: false, // Enables keyboard controls to enter full screen with audio media.
1767			keyBindings: { // The key control object, defining the key codes and the functions to execute.
1768				// The parameter, f = $.jPlayer.focus, will be checked truethy before attempting to call any of these functions.
1769				// Properties may be added to this object, in key/fn pairs, to enable other key controls. EG, for the playlist add-on.
1770				play: {
1771					key: 32, // space
1772					fn: function(f) {
1773						if(f.status.paused) {
1774							f.play();
1775						} else {
1776							f.pause();
1777						}
1778					}
1779				},
1780				fullScreen: {
1781					key: 13, // enter
1782					fn: function(f) {
1783						if(f.status.video || f.options.audioFullScreen) {
1784							f._setOption("fullScreen", !f.options.fullScreen);
1785						}
1786					}
1787				},
1788				muted: {
1789					key: 8, // backspace
1790					fn: function(f) {
1791						f._muted(!f.options.muted);
1792					}
1793				},
1794				volumeUp: {
1795					key: 38, // UP
1796					fn: function(f) {
1797						f.volume(f.options.volume + 0.1);
1798					}
1799				},
1800				volumeDown: {
1801					key: 40, // DOWN
1802					fn: function(f) {
1803						f.volume(f.options.volume - 0.1);
1804					}
1805				}
1806			},
1807			verticalVolume: false, // Calculate volume from the bottom of the volume bar. Default is from the left. Also volume affects either width or height.
1808			verticalPlaybackRate: false,
1809			globalVolume: false, // Set to make volume and muted changes affect all jPlayer instances with this option enabled
1810			idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \
1811			noConflict: "jQuery",
1812			emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element.
1813			consoleAlerts: true, // Alerts are sent to the console.log() instead of alert().
1814			errorAlerts: false,
1815			warningAlerts: false
1816		},
1817		optionsAudio: {
1818			size: {
1819				width: "0px",
1820				height: "0px",
1821				cssClass: ""
1822			},
1823			sizeFull: {
1824				width: "0px",
1825				height: "0px",
1826				cssClass: ""
1827			}
1828		},
1829		optionsVideo: {
1830			size: {
1831				width: "480px",
1832				height: "270px",
1833				cssClass: "jp-video-270p"
1834			},
1835			sizeFull: {
1836				width: "100%",
1837				height: "100%",
1838				cssClass: "jp-video-full"
1839			}
1840		},
1841		instances: {}, // Static Object
1842		status: { // Instanced in _init()
1843			src: "",
1844			media: {},
1845			paused: true,
1846			format: {},
1847			formatType: "",
1848			waitForPlay: true, // Same as waitForLoad except in case where preloading.
1849			waitForLoad: true,
1850			srcSet: false,
1851			video: false, // True if playing a video
1852			seekPercent: 0,
1853			currentPercentRelative: 0,
1854			currentPercentAbsolute: 0,
1855			currentTime: 0,
1856			duration: 0,
1857			remaining: 0,
1858			videoWidth: 0, // Intrinsic width of the video in pixels.
1859			videoHeight: 0, // Intrinsic height of the video in pixels.
1860			readyState: 0,
1861			networkState: 0,
1862			playbackRate: 1, // Warning - Now both an option and a status property
1863			ended: 0
1864
1865/*		Persistant status properties created dynamically at _init():
1866			width
1867			height
1868			cssClass
1869			nativeVideoControls
1870			noFullWindow
1871			noVolume
1872			playbackRateEnabled // Warning - Technically, we can have both Flash and HTML, so this might not be correct if the Flash is active. That is a niche case.
1873*/
1874		},
1875
1876		internal: { // Instanced in _init()
1877			ready: false
1878			// instance: undefined
1879			// domNode: undefined
1880			// htmlDlyCmdId: undefined
1881			// autohideId: undefined
1882			// cmdsIgnored
1883		},
1884		solution: { // Static Object: Defines the solutions built in jPlayer.
1885			html: true,
1886			flash: true
1887		},
1888		// 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"')
1889		format: { // Static Object
1890			mp3: {
1891				codec: 'audio/mpeg; codecs="mp3"',
1892				flashCanPlay: true,
1893				media: 'audio'
1894			},
1895			m4a: { // AAC / MP4
1896				codec: 'audio/mp4; codecs="mp4a.40.2"',
1897				flashCanPlay: true,
1898				media: 'audio'
1899			},
1900			m3u8a: { // AAC / MP4 / Apple HLS
1901				codec: 'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',
1902				flashCanPlay: false,
1903				media: 'audio'
1904			},
1905			m3ua: { // M3U
1906				codec: 'audio/mpegurl',
1907				flashCanPlay: false,
1908				media: 'audio'
1909			},
1910			oga: { // OGG
1911				codec: 'audio/ogg; codecs="vorbis, opus"',
1912				flashCanPlay: false,
1913				media: 'audio'
1914			},
1915			flac: { // FLAC
1916				codec: 'audio/x-flac',
1917				flashCanPlay: false,
1918				media: 'audio'
1919			},
1920			wav: { // PCM
1921				codec: 'audio/wav; codecs="1"',
1922				flashCanPlay: false,
1923				media: 'audio'
1924			},
1925			webma: { // WEBM
1926				codec: 'audio/webm; codecs="vorbis"',
1927				flashCanPlay: false,
1928				media: 'audio'
1929			},
1930			fla: { // FLV / F4A
1931				codec: 'audio/x-flv',
1932				flashCanPlay: true,
1933				media: 'audio'
1934			},
1935			rtmpa: { // RTMP AUDIO
1936				codec: 'audio/rtmp; codecs="rtmp"',
1937				flashCanPlay: true,
1938				media: 'audio'
1939			},
1940			m4v: { // H.264 / MP4
1941				codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
1942				flashCanPlay: true,
1943				media: 'video'
1944			},
1945			m3u8v: { // H.264 / AAC / MP4 / Apple HLS
1946				codec: 'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',
1947				flashCanPlay: false,
1948				media: 'video'
1949			},
1950			m3uv: { // M3U
1951				codec: 'audio/mpegurl',
1952				flashCanPlay: false,
1953				media: 'video'
1954			},
1955			ogv: { // OGG
1956				codec: 'video/ogg; codecs="theora, vorbis"',
vendor: 63,235 bytes, lines 1957-3733
1957				flashCanPlay: false,
1958				media: 'video'
1959			},
1960			webmv: { // WEBM
1961				codec: 'video/webm; codecs="vorbis, vp8"',
1962				flashCanPlay: false,
1963				media: 'video'
1964			},
1965			flv: { // FLV / F4V
1966				codec: 'video/x-flv',
1967				flashCanPlay: true,
1968				media: 'video'
1969			},
1970			rtmpv: { // RTMP VIDEO
1971				codec: 'video/rtmp; codecs="rtmp"',
1972				flashCanPlay: true,
1973				media: 'video'
1974			}
1975		},
1976		_init: function() {
1977			var self = this;
1978
1979			this.element.empty();
1980
1981			this.status = $.extend({}, this.status); // Copy static to unique instance.
1982			this.internal = $.extend({}, this.internal); // Copy static to unique instance.
1983
1984			// Initialize the time format
1985			this.options.timeFormat = $.extend({}, $.jPlayer.timeFormat, this.options.timeFormat);
1986
1987			// On iOS, assume commands will be ignored before user initiates them.
1988			this.internal.cmdsIgnored = $.jPlayer.platform.ipad || $.jPlayer.platform.iphone || $.jPlayer.platform.ipod;
1989
1990			this.internal.domNode = this.element.get(0);
1991
1992			// Add key bindings focus to 1st jPlayer instanced with key control enabled.
1993			if(this.options.keyEnabled && !$.jPlayer.focus) {
1994				$.jPlayer.focus = this;
1995			}
1996
1997			// A fix for Android where older (2.3) and even some 4.x devices fail to work when changing the *audio* SRC and then playing immediately.
1998			this.androidFix = {
1999				setMedia: false, // True when media set
2000				play: false, // True when a progress event will instruct the media to play
2001				pause: false, // True when a progress event will instruct the media to pause at a time.
2002				time: NaN // The play(time) parameter
2003			};
2004			if($.jPlayer.platform.android) {
2005				this.options.preload = this.options.preload !== 'auto' ? 'metadata' : 'auto'; // Default to metadata, but allow auto.
2006			}
2007
2008			this.formats = []; // Array based on supplied string option. Order defines priority.
2009			this.solutions = []; // Array based on solution string option. Order defines priority.
2010			this.require = {}; // Which media types are required: video, audio.
2011
2012			this.htmlElement = {}; // DOM elements created by jPlayer
2013			this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
2014			this.html.audio = {};
2015			this.html.video = {};
2016			this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
2017
2018			this.css = {};
2019			this.css.cs = {}; // Holds the css selector strings
2020			this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method)
2021
2022			this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+
2023
2024			this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds.
2025
2026			// Create the formats array, with prority based on the order of the supplied formats string
2027			$.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) {
2028				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
2029				if(self.format[format]) { // Check format is valid.
2030					var dupFound = false;
2031					$.each(self.formats, function(index2, value2) { // Check for duplicates
2032						if(format === value2) {
2033							dupFound = true;
2034							return false;
2035						}
2036					});
2037					if(!dupFound) {
2038						self.formats.push(format);
2039					}
2040				}
2041			});
2042
2043			// Create the solutions array, with prority based on the order of the solution string
2044			$.each(this.options.solution.toLowerCase().split(","), function(index1, value1) {
2045				var solution = value1.replace(/^\s+|\s+$/g, ""); //trim
2046				if(self.solution[solution]) { // Check solution is valid.
2047					var dupFound = false;
2048					$.each(self.solutions, function(index2, value2) { // Check for duplicates
2049						if(solution === value2) {
2050							dupFound = true;
2051							return false;
2052						}
2053					});
2054					if(!dupFound) {
2055						self.solutions.push(solution);
2056					}
2057				}
2058			});
2059
2060			this.internal.instance = "jp_" + this.count;
2061			this.instances[this.internal.instance] = this.element;
2062
2063			// Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms.
2064			if(!this.element.attr("id")) {
2065				this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count);
2066			}
2067
2068			this.internal.self = $.extend({}, {
2069				id: this.element.attr("id"),
2070				jq: this.element
2071			});
2072			this.internal.audio = $.extend({}, {
2073				id: this.options.idPrefix + "_audio_" + this.count,
2074				jq: undefined
2075			});
2076			this.internal.video = $.extend({}, {
2077				id: this.options.idPrefix + "_video_" + this.count,
2078				jq: undefined
2079			});
2080			this.internal.flash = $.extend({}, {
2081				id: this.options.idPrefix + "_flash_" + this.count,
2082				jq: undefined,
2083				swf: this.options.swfPath + (this.options.swfPath.toLowerCase().slice(-4) !== ".swf" ? (this.options.swfPath && this.options.swfPath.slice(-1) !== "/" ? "/" : "") + "Jplayer.swf" : "")
2084			});
2085			this.internal.poster = $.extend({}, {
2086				id: this.options.idPrefix + "_poster_" + this.count,
2087				jq: undefined
2088			});
2089
2090			// Register listeners defined in the constructor
2091			$.each($.jPlayer.event, function(eventName,eventType) {
2092				if(self.options[eventName] !== undefined) {
2093					self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace.
2094					self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading.
2095				}
2096			});
2097
2098			// Determine if we require solutions for audio, video or both media types.
2099			this.require.audio = false;
2100			this.require.video = false;
2101			$.each(this.formats, function(priority, format) {
2102				self.require[self.format[format].media] = true;
2103			});
2104
2105			// Now required types are known, finish the options default settings.
2106			if(this.require.video) {
2107				this.options = $.extend(true, {},
2108					this.optionsVideo,
2109					this.options
2110				);
2111			} else {
2112				this.options = $.extend(true, {},
2113					this.optionsAudio,
2114					this.options
2115				);
2116			}
2117			this._setSize(); // update status and jPlayer element size
2118
2119			// Determine the status for Blocklisted options.
2120			this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
2121			this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
2122			this.status.noVolume = this._uaBlocklist(this.options.noVolume);
2123
2124			// Create event handlers if native fullscreen is supported
2125			if($.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled) {
2126				this._fullscreenAddEventListeners();
2127			}
2128
2129			// The native controls are only for video and are disabled when audio is also used.
2130			this._restrictNativeVideoControls();
2131
2132			// Create the poster image.
2133			this.htmlElement.poster = document.createElement('img');
2134			this.htmlElement.poster.id = this.internal.poster.id;
2135			this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser.
2136				if(!self.status.video || self.status.waitForPlay) {
2137					self.internal.poster.jq.show();
2138				}
2139			};
2140			this.element.append(this.htmlElement.poster);
2141			this.internal.poster.jq = $("#" + this.internal.poster.id);
2142			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
2143			this.internal.poster.jq.hide();
2144			this.internal.poster.jq.bind("click.jPlayer", function() {
2145				self._trigger($.jPlayer.event.click);
2146			});
2147
2148			// Generate the required media elements
2149			this.html.audio.available = false;
2150			if(this.require.audio) { // If a supplied format is audio
2151				this.htmlElement.audio = document.createElement('audio');
2152				this.htmlElement.audio.id = this.internal.audio.id;
2153				this.html.audio.available = !!this.htmlElement.audio.canPlayType && this._testCanPlayType(this.htmlElement.audio); // Test is for IE9 on Win Server 2008.
2154			}
2155			this.html.video.available = false;
2156			if(this.require.video) { // If a supplied format is video
2157				this.htmlElement.video = document.createElement('video');
2158				this.htmlElement.video.id = this.internal.video.id;
2159				this.html.video.available = !!this.htmlElement.video.canPlayType && this._testCanPlayType(this.htmlElement.video); // Test is for IE9 on Win Server 2008.
2160			}
2161
2162			this.flash.available = this._checkForFlash(10.1);
2163
2164			this.html.canPlay = {};
2165			this.flash.canPlay = {};
2166			$.each(this.formats, function(priority, format) {
2167				self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec);
2168				self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available;
2169			});
2170			this.html.desired = false;
2171			this.flash.desired = false;
2172			$.each(this.solutions, function(solutionPriority, solution) {
2173				if(solutionPriority === 0) {
2174					self[solution].desired = true;
2175				} else {
2176					var audioCanPlay = false;
2177					var videoCanPlay = false;
2178					$.each(self.formats, function(formatPriority, format) {
2179						if(self[self.solutions[0]].canPlay[format]) { // The other solution can play
2180							if(self.format[format].media === 'video') {
2181								videoCanPlay = true;
2182							} else {
2183								audioCanPlay = true;
2184							}
2185						}
2186					});
2187					self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay);
2188				}
2189			});
2190			// This is what jPlayer will support, based on solution and supplied.
2191			this.html.support = {};
2192			this.flash.support = {};
2193			$.each(this.formats, function(priority, format) {
2194				self.html.support[format] = self.html.canPlay[format] && self.html.desired;
2195				self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired;
2196			});
2197			// If jPlayer is supporting any format in a solution, then the solution is used.
2198			this.html.used = false;
2199			this.flash.used = false;
2200			$.each(this.solutions, function(solutionPriority, solution) {
2201				$.each(self.formats, function(formatPriority, format) {
2202					if(self[solution].support[format]) {
2203						self[solution].used = true;
2204						return false;
2205					}
2206				});
2207			});
2208
2209			// Init solution active state and the event gates to false.
2210			this._resetActive();
2211			this._resetGate();
2212
2213			// Set up the css selectors for the control and feedback entities.
2214			this._cssSelectorAncestor(this.options.cssSelectorAncestor);
2215
2216			// If neither html nor flash are being used by this browser, then media playback is not possible. Trigger an error event.
2217			if(!(this.html.used || this.flash.used)) {
2218				this._error( {
2219					type: $.jPlayer.error.NO_SOLUTION,
2220					context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}",
2221					message: $.jPlayer.errorMsg.NO_SOLUTION,
2222					hint: $.jPlayer.errorHint.NO_SOLUTION
2223				});
2224				if(this.css.jq.noSolution.length) {
2225					this.css.jq.noSolution.show();
2226				}
2227			} else {
2228				if(this.css.jq.noSolution.length) {
2229					this.css.jq.noSolution.hide();
2230				}
2231			}
2232
2233			// Add the flash solution if it is being used.
2234			if(this.flash.used) {
2235				var htmlObj,
2236				flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted;
2237
2238				// Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/
2239				// Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event.
2240
2241				if($.jPlayer.browser.msie && (Number($.jPlayer.browser.version) < 9 || $.jPlayer.browser.documentMode < 9)) {
2242					var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>';
2243
2244					var paramStr = [
2245						'<param name="movie" value="' + this.internal.flash.swf + '" />',
2246						'<param name="FlashVars" value="' + flashVars + '" />',
2247						'<param name="allowScriptAccess" value="always" />',
2248						'<param name="bgcolor" value="' + this.options.backgroundColor + '" />',
2249						'<param name="wmode" value="' + this.options.wmode + '" />'
2250					];
2251
2252					htmlObj = document.createElement(objStr);
2253					for(var i=0; i < paramStr.length; i++) {
2254						htmlObj.appendChild(document.createElement(paramStr[i]));
2255					}
2256				} else {
2257					var createParam = function(el, n, v) {
2258						var p = document.createElement("param");
2259						p.setAttribute("name", n);
2260						p.setAttribute("value", v);
2261						el.appendChild(p);
2262					};
2263
2264					htmlObj = document.createElement("object");
2265					htmlObj.setAttribute("id", this.internal.flash.id);
2266					htmlObj.setAttribute("name", this.internal.flash.id);
2267					htmlObj.setAttribute("data", this.internal.flash.swf);
2268					htmlObj.setAttribute("type", "application/x-shockwave-flash");
2269					htmlObj.setAttribute("width", "1"); // Non-zero
2270					htmlObj.setAttribute("height", "1"); // Non-zero
2271					htmlObj.setAttribute("tabindex", "-1");
2272					createParam(htmlObj, "flashvars", flashVars);
2273					createParam(htmlObj, "allowscriptaccess", "always");
2274					createParam(htmlObj, "bgcolor", this.options.backgroundColor);
2275					createParam(htmlObj, "wmode", this.options.wmode);
2276				}
2277
2278				this.element.append(htmlObj);
2279				this.internal.flash.jq = $(htmlObj);
2280			}
2281
2282			// Setup playbackRate ability before using _addHtmlEventListeners()
2283			if(this.html.used && !this.flash.used) { // If only HTML
2284				// Using the audio element capabilities for playbackRate. ie., Assuming video element is the same.
2285				this.status.playbackRateEnabled = this._testPlaybackRate('audio');
2286			} else {
2287				this.status.playbackRateEnabled = false;
2288			}
2289
2290			this._updatePlaybackRate();
2291
2292			// Add the HTML solution if being used.
2293			if(this.html.used) {
2294
2295				// The HTML Audio handlers
2296				if(this.html.audio.available) {
2297					this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio);
2298					this.element.append(this.htmlElement.audio);
2299					this.internal.audio.jq = $("#" + this.internal.audio.id);
2300				}
2301
2302				// The HTML Video handlers
2303				if(this.html.video.available) {
2304					this._addHtmlEventListeners(this.htmlElement.video, this.html.video);
2305					this.element.append(this.htmlElement.video);
2306					this.internal.video.jq = $("#" + this.internal.video.id);
2307					if(this.status.nativeVideoControls) {
2308						this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
2309					} else {
2310						this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS
2311					}
2312					this.internal.video.jq.bind("click.jPlayer", function() {
2313						self._trigger($.jPlayer.event.click);
2314					});
2315				}
2316			}
2317
2318			// Create the bridge that emulates the HTML Media element on the jPlayer DIV
2319			if( this.options.emulateHtml ) {
2320				this._emulateHtmlBridge();
2321			}
2322
2323			if(this.html.used && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms.
2324				setTimeout( function() {
2325					self.internal.ready = true;
2326					self.version.flash = "n/a";
2327					self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
2328					self._trigger($.jPlayer.event.ready);
2329				}, 100);
2330			}
2331
2332			// Initialize the interface components with the options.
2333			this._updateNativeVideoControls();
2334			// The other controls are now setup in _cssSelectorAncestor()
2335			if(this.css.jq.videoPlay.length) {
2336				this.css.jq.videoPlay.hide();
2337			}
2338
2339			$.jPlayer.prototype.count++; // Change static variable via prototype.
2340		},
2341		destroy: function() {
2342			// MJP: The background change remains. Would need to store the original to restore it correctly.
2343			// MJP: The jPlayer element's size change remains.
2344
2345			// Clear the media to reset the GUI and stop any downloads. Streams on some browsers had persited. (Chrome)
2346			this.clearMedia();
2347			// Remove the size/sizeFull cssClass from the cssSelectorAncestor
2348			this._removeUiClass();
2349			// Remove the times from the GUI
2350			if(this.css.jq.currentTime.length) {
2351				this.css.jq.currentTime.text("");
2352			}
2353			if(this.css.jq.duration.length) {
2354				this.css.jq.duration.text("");
2355			}
2356			// Remove any bindings from the interface controls.
2357			$.each(this.css.jq, function(fn, jq) {
2358				// Check selector is valid before trying to execute method.
2359				if(jq.length) {
2360					jq.unbind(".jPlayer");
2361				}
2362			});
2363			// Remove the click handlers for $.jPlayer.event.click
2364			this.internal.poster.jq.unbind(".jPlayer");
2365			if(this.internal.video.jq) {
2366				this.internal.video.jq.unbind(".jPlayer");
2367			}
2368			// Remove the fullscreen event handlers
2369			this._fullscreenRemoveEventListeners();
2370			// Remove key bindings
2371			if(this === $.jPlayer.focus) {
2372				$.jPlayer.focus = null;
2373			}
2374			// Destroy the HTML bridge.
2375			if(this.options.emulateHtml) {
2376				this._destroyHtmlBridge();
2377			}
2378			this.element.removeData("jPlayer"); // Remove jPlayer data
2379			this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor
2380			this.element.empty(); // Remove the inserted child elements
2381
2382			delete this.instances[this.internal.instance]; // Clear the instance on the static instance object
2383		},
2384		enable: function() { // Plan to implement
2385			// options.disabled = false
2386		},
2387		disable: function () { // Plan to implement
2388			// options.disabled = true
2389		},
2390		_testCanPlayType: function(elem) {
2391			// IE9 on Win Server 2008 did not implement canPlayType(), but it has the property.
2392			try {
2393				elem.canPlayType(this.format.mp3.codec); // The type is irrelevant.
2394				return true;
2395			} catch(err) {
2396				return false;
2397			}
2398		},
2399		_testPlaybackRate: function(type) {
2400			// type: String 'audio' or 'video'
2401			var el, rate = 0.5;
2402			type = typeof type === 'string' ? type : 'audio';
2403			el = document.createElement(type);
2404			// Wrapping in a try/catch, just in case older HTML5 browsers throw and error.
2405			try {
2406				if('playbackRate' in el) {
2407					el.playbackRate = rate;
2408					return el.playbackRate === rate;
2409				} else {
2410					return false;
2411				}
2412			} catch(err) {
2413				return false;
2414			}
2415		},
2416		_uaBlocklist: function(list) {
2417			// list : object with properties that are all regular expressions. Property names are irrelevant.
2418			// Returns true if the user agent is matched in list.
2419			var	ua = navigator.userAgent.toLowerCase(),
2420				block = false;
2421
2422			$.each(list, function(p, re) {
2423				if(re && re.test(ua)) {
2424					block = true;
2425					return false; // exit $.each.
2426				}
2427			});
2428			return block;
2429		},
2430		_restrictNativeVideoControls: function() {
2431			// Fallback to noFullWindow when nativeVideoControls is true and audio media is being used. Affects when both media types are used.
2432			if(this.require.audio) {
2433				if(this.status.nativeVideoControls) {
2434					this.status.nativeVideoControls = false;
2435					this.status.noFullWindow = true;
2436				}
2437			}
2438		},
2439		_updateNativeVideoControls: function() {
2440			if(this.html.video.available && this.html.used) {
2441				// Turn the HTML Video controls on/off
2442				this.htmlElement.video.controls = this.status.nativeVideoControls;
2443				// Show/hide the jPlayer GUI.
2444				this._updateAutohide();
2445				// For when option changed. The poster image is not updated, as it is dealt with in setMedia(). Acceptable degradation since seriously doubt these options will change on the fly. Can again review later.
2446				if(this.status.nativeVideoControls && this.require.video) {
2447					this.internal.poster.jq.hide();
2448					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
2449				} else if(this.status.waitForPlay && this.status.video) {
2450					this.internal.poster.jq.show();
2451					this.internal.video.jq.css({'width': '0px', 'height': '0px'});
2452				}
2453			}
2454		},
2455		_addHtmlEventListeners: function(mediaElement, entity) {
2456			var self = this;
2457			mediaElement.preload = this.options.preload;
2458			mediaElement.muted = this.options.muted;
2459			mediaElement.volume = this.options.volume;
2460
2461			if(this.status.playbackRateEnabled) {
2462				mediaElement.defaultPlaybackRate = this.options.defaultPlaybackRate;
2463				mediaElement.playbackRate = this.options.playbackRate;
2464			}
2465
2466			// Create the event listeners
2467			// Only want the active entity to affect jPlayer and bubble events.
2468			// Using entity.gate so that object is referenced and gate property always current
2469
2470			mediaElement.addEventListener("progress", function() {
2471				if(entity.gate) {
2472					if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
2473						self.internal.cmdsIgnored = false;
2474					}
2475					self.androidFix.setMedia = false; // Disable the fix after the first progress event.
2476					if(self.androidFix.play) { // Play Android audio - performing the fix.
2477						self.androidFix.play = false;
2478						self.play(self.androidFix.time);
2479					}
2480					if(self.androidFix.pause) { // Pause Android audio at time - performing the fix.
2481						self.androidFix.pause = false;
2482						self.pause(self.androidFix.time);
2483					}
2484					self._getHtmlStatus(mediaElement);
2485					self._updateInterface();
2486					self._trigger($.jPlayer.event.progress);
2487				}
2488			}, false);
2489			mediaElement.addEventListener("timeupdate", function() {
2490				if(entity.gate) {
2491					self._getHtmlStatus(mediaElement);
2492					self._updateInterface();
2493					self._trigger($.jPlayer.event.timeupdate);
2494				}
2495			}, false);
2496			mediaElement.addEventListener("durationchange", function() {
2497				if(entity.gate) {
2498					self._getHtmlStatus(mediaElement);
2499					self._updateInterface();
2500					self._trigger($.jPlayer.event.durationchange);
2501				}
2502			}, false);
2503			mediaElement.addEventListener("play", function() {
2504				if(entity.gate) {
2505					self._updateButtons(true);
2506					self._html_checkWaitForPlay(); // So the native controls update this variable and puts the hidden interface in the correct state. Affects toggling native controls.
2507					self._trigger($.jPlayer.event.play);
2508				}
2509			}, false);
2510			mediaElement.addEventListener("playing", function() {
2511				if(entity.gate) {
2512					self._updateButtons(true);
2513					self._seeked();
2514					self._trigger($.jPlayer.event.playing);
2515				}
2516			}, false);
2517			mediaElement.addEventListener("pause", function() {
2518				if(entity.gate) {
2519					self._updateButtons(false);
2520					self._trigger($.jPlayer.event.pause);
2521				}
2522			}, false);
2523			mediaElement.addEventListener("waiting", function() {
2524				if(entity.gate) {
2525					self._seeking();
2526					self._trigger($.jPlayer.event.waiting);
2527				}
2528			}, false);
2529			mediaElement.addEventListener("seeking", function() {
2530				if(entity.gate) {
2531					self._seeking();
2532					self._trigger($.jPlayer.event.seeking);
2533				}
2534			}, false);
2535			mediaElement.addEventListener("seeked", function() {
2536				if(entity.gate) {
2537					self._seeked();
2538					self._trigger($.jPlayer.event.seeked);
2539				}
2540			}, false);
2541			mediaElement.addEventListener("volumechange", function() {
2542				if(entity.gate) {
2543					// Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control.
2544					// However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though.
2545					self.options.volume = mediaElement.volume;
2546					self.options.muted = mediaElement.muted;
2547					self._updateMute();
2548					self._updateVolume();
2549					self._trigger($.jPlayer.event.volumechange);
2550				}
2551			}, false);
2552			mediaElement.addEventListener("ratechange", function() {
2553				if(entity.gate) {
2554					self.options.defaultPlaybackRate = mediaElement.defaultPlaybackRate;
2555					self.options.playbackRate = mediaElement.playbackRate;
2556					self._updatePlaybackRate();
2557					self._trigger($.jPlayer.event.ratechange);
2558				}
2559			}, false);
2560			mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture.
2561				if(entity.gate) {
2562					self._seeked();
2563					self._trigger($.jPlayer.event.suspend);
2564				}
2565			}, false);
2566			mediaElement.addEventListener("ended", function() {
2567				if(entity.gate) {
2568					// Order of the next few commands are important. Change the time and then pause.
2569					// Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored.
2570					if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo.
2571						self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.)
2572					}
2573					self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback.
2574					self._updateButtons(false);
2575					self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full.
2576					self._updateInterface();
2577					self._trigger($.jPlayer.event.ended);
2578				}
2579			}, false);
2580			mediaElement.addEventListener("error", function() {
2581				if(entity.gate) {
2582					self._updateButtons(false);
2583					self._seeked();
2584					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
2585						clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
2586						self.status.waitForLoad = true; // Allows the load operation to try again.
2587						self.status.waitForPlay = true; // Reset since a play was captured.
2588						if(self.status.video && !self.status.nativeVideoControls) {
2589							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
2590						}
2591						if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
2592							self.internal.poster.jq.show();
2593						}
2594						if(self.css.jq.videoPlay.length) {
2595							self.css.jq.videoPlay.show();
2596						}
2597						self._error( {
2598							type: $.jPlayer.error.URL,
2599							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
2600							message: $.jPlayer.errorMsg.URL,
2601							hint: $.jPlayer.errorHint.URL
2602						});
2603					}
2604				}
2605			}, false);
2606			// Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer.
2607			$.each($.jPlayer.htmlEvent, function(i, eventType) {
2608				mediaElement.addEventListener(this, function() {
2609					if(entity.gate) {
2610						self._trigger($.jPlayer.event[eventType]);
2611					}
2612				}, false);
2613			});
2614		},
2615		_getHtmlStatus: function(media, override) {
2616			var ct = 0, cpa = 0, sp = 0, cpr = 0;
2617
2618			// Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct.
2619			// Fixes the initial duration bug in BB OS7, where the media.duration is infinity and displays as NaN:NaN due to Date() using inifity.
2620			if(isFinite(media.duration)) {
2621				this.status.duration = media.duration;
2622			}
2623
2624			ct = media.currentTime;
2625			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
2626			if((typeof media.seekable === "object") && (media.seekable.length > 0)) {
2627				sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100;
2628				cpr = (this.status.duration > 0) ? 100 * media.currentTime / media.seekable.end(media.seekable.length-1) : 0; // Duration conditional for iOS duration bug. ie., seekable.end is a NaN in that case.
2629			} else {
2630				sp = 100;
2631				cpr = cpa;
2632			}
2633
2634			if(override) {
2635				ct = 0;
2636				cpr = 0;
2637				cpa = 0;
2638			}
2639
2640			this.status.seekPercent = sp;
2641			this.status.currentPercentRelative = cpr;
2642			this.status.currentPercentAbsolute = cpa;
2643			this.status.currentTime = ct;
2644
2645			this.status.remaining = this.status.duration - this.status.currentTime;
2646
2647			this.status.videoWidth = media.videoWidth;
2648			this.status.videoHeight = media.videoHeight;
2649
2650			this.status.readyState = media.readyState;
2651			this.status.networkState = media.networkState;
2652			this.status.playbackRate = media.playbackRate;
2653			this.status.ended = media.ended;
2654		},
2655		_resetStatus: function() {
2656			this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset.
2657		},
2658		_trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType
2659			var event = $.Event(eventType);
2660			event.jPlayer = {};
2661			event.jPlayer.version = $.extend({}, this.version);
2662			event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy
2663			event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy
2664			event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy
2665			event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy
2666			if(error) {
2667				event.jPlayer.error = $.extend({}, error);
2668			}
2669			if(warning) {
2670				event.jPlayer.warning = $.extend({}, warning);
2671			}
2672			this.element.trigger(event);
2673		},
2674		jPlayerFlashEvent: function(eventType, status) { // Called from Flash
2675			if(eventType === $.jPlayer.event.ready) {
2676				if(!this.internal.ready) {
2677					this.internal.ready = true;
2678					this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore.
2679
2680					this.version.flash = status.version;
2681					if(this.version.needFlash !== this.version.flash) {
2682						this._error( {
2683							type: $.jPlayer.error.VERSION,
2684							context: this.version.flash,
2685							message: $.jPlayer.errorMsg.VERSION + this.version.flash,
2686							hint: $.jPlayer.errorHint.VERSION
2687						});
2688					}
2689					this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
2690					this._trigger(eventType);
2691				} else {
2692					// This condition occurs if the Flash is hidden and then shown again.
2693					// Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen.
2694
2695					// Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used.
2696					if(this.flash.gate) {
2697
2698						// Send the current status to the Flash now that it is ready (available) again.
2699						if(this.status.srcSet) {
2700
2701							// Need to read original status before issuing the setMedia command.
2702							var	currentTime = this.status.currentTime,
2703								paused = this.status.paused;
2704
2705							this.setMedia(this.status.media);
2706							this.volumeWorker(this.options.volume);
2707							if(currentTime > 0) {
2708								if(paused) {
2709									this.pause(currentTime);
2710								} else {
2711									this.play(currentTime);
2712								}
2713							}
2714						}
2715						this._trigger($.jPlayer.event.flashreset);
2716					}
2717				}
2718			}
2719			if(this.flash.gate) {
2720				switch(eventType) {
2721					case $.jPlayer.event.progress:
2722						this._getFlashStatus(status);
2723						this._updateInterface();
2724						this._trigger(eventType);
2725						break;
2726					case $.jPlayer.event.timeupdate:
2727						this._getFlashStatus(status);
2728						this._updateInterface();
2729						this._trigger(eventType);
2730						break;
2731					case $.jPlayer.event.play:
2732						this._seeked();
2733						this._updateButtons(true);
2734						this._trigger(eventType);
2735						break;
2736					case $.jPlayer.event.pause:
2737						this._updateButtons(false);
2738						this._trigger(eventType);
2739						break;
2740					case $.jPlayer.event.ended:
2741						this._updateButtons(false);
2742						this._trigger(eventType);
2743						break;
2744					case $.jPlayer.event.click:
2745						this._trigger(eventType); // This could be dealt with by the default
2746						break;
2747					case $.jPlayer.event.error:
2748						this.status.waitForLoad = true; // Allows the load operation to try again.
2749						this.status.waitForPlay = true; // Reset since a play was captured.
2750						if(this.status.video) {
2751							this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
2752						}
2753						if(this._validString(this.status.media.poster)) {
2754							this.internal.poster.jq.show();
2755						}
2756						if(this.css.jq.videoPlay.length && this.status.video) {
2757							this.css.jq.videoPlay.show();
2758						}
2759						if(this.status.video) { // Set up for another try. Execute before error event.
2760							this._flash_setVideo(this.status.media);
2761						} else {
2762							this._flash_setAudio(this.status.media);
2763						}
2764						this._updateButtons(false);
2765						this._error( {
2766							type: $.jPlayer.error.URL,
2767							context:status.src,
2768							message: $.jPlayer.errorMsg.URL,
2769							hint: $.jPlayer.errorHint.URL
2770						});
2771						break;
2772					case $.jPlayer.event.seeking:
2773						this._seeking();
2774						this._trigger(eventType);
2775						break;
2776					case $.jPlayer.event.seeked:
2777						this._seeked();
2778						this._trigger(eventType);
2779						break;
2780					case $.jPlayer.event.ready:
2781						// The ready event is handled outside the switch statement.
2782						// Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia.
2783						break;
2784					default:
2785						this._trigger(eventType);
2786				}
2787			}
2788			return false;
2789		},
2790		_getFlashStatus: function(status) {
2791			this.status.seekPercent = status.seekPercent;
2792			this.status.currentPercentRelative = status.currentPercentRelative;
2793			this.status.currentPercentAbsolute = status.currentPercentAbsolute;
2794			this.status.currentTime = status.currentTime;
2795			this.status.duration = status.duration;
2796			this.status.remaining = status.duration - status.currentTime;
2797
2798			this.status.videoWidth = status.videoWidth;
2799			this.status.videoHeight = status.videoHeight;
2800
2801			// The Flash does not generate this information in this release
2802			this.status.readyState = 4; // status.readyState;
2803			this.status.networkState = 0; // status.networkState;
2804			this.status.playbackRate = 1; // status.playbackRate;
2805			this.status.ended = false; // status.ended;
2806		},
2807		_updateButtons: function(playing) {
2808			if(playing === undefined) {
2809				playing = !this.status.paused;
2810			} else {
2811				this.status.paused = !playing;
2812			}
2813			if(this.css.jq.play.length && this.css.jq.pause.length) {
2814				if(playing) {
2815					this.css.jq.play.hide();
2816					this.css.jq.pause.show();
2817				} else {
2818					this.css.jq.play.show();
2819					this.css.jq.pause.hide();
2820				}
2821			}
2822			if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) {
2823				if(this.status.noFullWindow) {
2824					this.css.jq.fullScreen.hide();
2825					this.css.jq.restoreScreen.hide();
2826				} else if(this.options.fullWindow) {
2827					this.css.jq.fullScreen.hide();
2828					this.css.jq.restoreScreen.show();
2829				} else {
2830					this.css.jq.fullScreen.show();
2831					this.css.jq.restoreScreen.hide();
2832				}
2833			}
2834			if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) {
2835				if(this.options.loop) {
2836					this.css.jq.repeat.hide();
2837					this.css.jq.repeatOff.show();
2838				} else {
2839					this.css.jq.repeat.show();
2840					this.css.jq.repeatOff.hide();
2841				}
2842			}
2843		},
2844		_updateInterface: function() {
2845			if(this.css.jq.seekBar.length) {
2846				this.css.jq.seekBar.width(this.status.seekPercent+"%");
2847			}
2848			if(this.css.jq.playBar.length) {
2849				if(this.options.smoothPlayBar) {
2850					this.css.jq.playBar.stop().animate({
2851						width: this.status.currentPercentAbsolute+"%"
2852					}, 250, "linear");
2853				} else {
2854					this.css.jq.playBar.width(this.status.currentPercentRelative+"%");
2855				}
2856			}
2857			var currentTimeText = '';
2858			if(this.css.jq.currentTime.length) {
2859				currentTimeText = this._convertTime(this.status.currentTime);
2860				if(currentTimeText !== this.css.jq.currentTime.text()) {
2861					this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));
2862				}
2863			}
2864			var durationText = '',
2865				duration = this.status.duration,
2866				remaining = this.status.remaining;
2867			if(this.css.jq.duration.length) {
2868				if(typeof this.status.media.duration === 'string') {
2869					durationText = this.status.media.duration;
2870				} else {
2871					if(typeof this.status.media.duration === 'number') {
2872						duration = this.status.media.duration;
2873						remaining = duration - this.status.currentTime;
2874					}
2875					if(this.options.remainingDuration) {
2876						durationText = (remaining > 0 ? '-' : '') + this._convertTime(remaining);
2877					} else {
2878						durationText = this._convertTime(duration);
2879					}
2880				}
2881				if(durationText !== this.css.jq.duration.text()) {
2882					this.css.jq.duration.text(durationText);
2883				}
2884			}
2885		},
2886		_convertTime: ConvertTime.prototype.time,
2887		_seeking: function() {
2888			if(this.css.jq.seekBar.length) {
2889				this.css.jq.seekBar.addClass("jp-seeking-bg");
2890			}
2891		},
2892		_seeked: function() {
2893			if(this.css.jq.seekBar.length) {
2894				this.css.jq.seekBar.removeClass("jp-seeking-bg");
2895			}
2896		},
2897		_resetGate: function() {
2898			this.html.audio.gate = false;
2899			this.html.video.gate = false;
2900			this.flash.gate = false;
2901		},
2902		_resetActive: function() {
2903			this.html.active = false;
2904			this.flash.active = false;
2905		},
2906		_escapeHtml: function(s) {
2907			return s.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('"').join('&quot;');
2908		},
2909		_qualifyURL: function(url) {
2910			var el = document.createElement('div');
2911			el.innerHTML= '<a href="' + this._escapeHtml(url) + '">x</a>';
2912			return el.firstChild.href;
2913		},
2914		_absoluteMediaUrls: function(media) {
2915			var self = this;
2916			$.each(media, function(type, url) {
2917				if(url && self.format[type]) {
2918					media[type] = self._qualifyURL(url);
2919				}
2920			});
2921			return media;
2922		},
2923		setMedia: function(media) {
2924
2925			/*	media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats.
2926			 *	media.poster = String: Video poster URL.
2927			 *	media.track = Array: Of objects defining the track element: kind, src, srclang, label, def.
2928			 *	media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often.
2929			 */
2930
2931			var	self = this,
2932				supported = false,
2933				posterChanged = this.status.media.poster !== media.poster; // Compare before reset. Important for OSX Safari as this.htmlElement.poster.src is absolute, even if original poster URL was relative.
2934
2935			this._resetMedia();
2936			this._resetGate();
2937			this._resetActive();
2938
2939			// Clear the Android Fix.
2940			this.androidFix.setMedia = false;
2941			this.androidFix.play = false;
2942			this.androidFix.pause = false;
2943
2944			// Convert all media URLs to absolute URLs.
2945			media = this._absoluteMediaUrls(media);
2946
2947			$.each(this.formats, function(formatPriority, format) {
2948				var isVideo = self.format[format].media === 'video';
2949				$.each(self.solutions, function(solutionPriority, solution) {
2950					if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format.
2951						var isHtml = solution === 'html';
2952
2953						if(isVideo) {
2954							if(isHtml) {
2955								self.html.video.gate = true;
2956								self._html_setVideo(media);
2957								self.html.active = true;
2958							} else {
2959								self.flash.gate = true;
2960								self._flash_setVideo(media);
2961								self.flash.active = true;
2962							}
2963							if(self.css.jq.videoPlay.length) {
2964								self.css.jq.videoPlay.show();
2965							}
2966							self.status.video = true;
2967						} else {
2968							if(isHtml) {
2969								self.html.audio.gate = true;
2970								self._html_setAudio(media);
2971								self.html.active = true;
2972
2973								// Setup the Android Fix - Only for HTML audio.
2974								if($.jPlayer.platform.android) {
2975									self.androidFix.setMedia = true;
2976								}
2977							} else {
2978								self.flash.gate = true;
2979								self._flash_setAudio(media);
2980								self.flash.active = true;
2981							}
2982							if(self.css.jq.videoPlay.length) {
2983								self.css.jq.videoPlay.hide();
2984							}
2985							self.status.video = false;
2986						}
2987
2988						supported = true;
2989						return false; // Exit $.each
2990					}
2991				});
2992				if(supported) {
2993					return false; // Exit $.each
2994				}
2995			});
2996
2997			if(supported) {
2998				if(!(this.status.nativeVideoControls && this.html.video.gate)) {
2999					// Set poster IMG if native video controls are not being used
3000					// Note: With IE the IMG onload event occurs immediately when cached.
3001					// Note: Poster hidden by default in _resetMedia()
3002					if(this._validString(media.poster)) {
3003						if(posterChanged) { // Since some browsers do not generate img onload event.
3004							this.htmlElement.poster.src = media.poster;
3005						} else {
3006							this.internal.poster.jq.show();
3007						}
3008					}
3009				}
3010				if(this.css.jq.title.length) {
3011					if(typeof media.title === 'string') {
3012						this.css.jq.title.html(media.title);
3013						if(this.htmlElement.audio) {
3014							this.htmlElement.audio.setAttribute('title', media.title);
3015						}
3016						if(this.htmlElement.video) {
3017							this.htmlElement.video.setAttribute('title', media.title);
3018						}
3019					}
3020				}
3021				this.status.srcSet = true;
3022				this.status.media = $.extend({}, media);
3023				this._updateButtons(false);
3024				this._updateInterface();
3025				this._trigger($.jPlayer.event.setmedia);
3026			} else { // jPlayer cannot support any formats provided in this browser
3027				// Send an error event
3028				this._error( {
3029					type: $.jPlayer.error.NO_SUPPORT,
3030					context: "{supplied:'" + this.options.supplied + "'}",
3031					message: $.jPlayer.errorMsg.NO_SUPPORT,
3032					hint: $.jPlayer.errorHint.NO_SUPPORT
3033				});
3034			}
3035		},
3036		_resetMedia: function() {
3037			this._resetStatus();
3038			this._updateButtons(false);
3039			this._updateInterface();
3040			this._seeked();
3041			this.internal.poster.jq.hide();
3042
3043			clearTimeout(this.internal.htmlDlyCmdId);
3044
3045			if(this.html.active) {
3046				this._html_resetMedia();
3047			} else if(this.flash.active) {
3048				this._flash_resetMedia();
3049			}
3050		},
3051		clearMedia: function() {
3052			this._resetMedia();
3053
3054			if(this.html.active) {
3055				this._html_clearMedia();
3056			} else if(this.flash.active) {
3057				this._flash_clearMedia();
3058			}
3059
3060			this._resetGate();
3061			this._resetActive();
3062		},
3063		load: function() {
3064			if(this.status.srcSet) {
3065				if(this.html.active) {
3066					this._html_load();
3067				} else if(this.flash.active) {
3068					this._flash_load();
3069				}
3070			} else {
3071				this._urlNotSetError("load");
3072			}
3073		},
3074		focus: function() {
3075			if(this.options.keyEnabled) {
3076				$.jPlayer.focus = this;
3077			}
3078		},
3079		play: function(time) {
3080			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
3081			if(this.status.srcSet) {
3082				this.focus();
3083				if(this.html.active) {
3084					this._html_play(time);
3085				} else if(this.flash.active) {
3086					this._flash_play(time);
3087				}
3088			} else {
3089				this._urlNotSetError("play");
3090			}
3091		},
3092		videoPlay: function() { // Handles clicks on the play button over the video poster
3093			this.play();
3094		},
3095		pause: function(time) {
3096			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
3097			if(this.status.srcSet) {
3098				if(this.html.active) {
3099					this._html_pause(time);
3100				} else if(this.flash.active) {
3101					this._flash_pause(time);
3102				}
3103			} else {
3104				this._urlNotSetError("pause");
3105			}
3106		},
3107		tellOthers: function(command, conditions) {
3108			var self = this,
3109				hasConditions = typeof conditions === 'function',
3110				args = Array.prototype.slice.call(arguments); // Convert arguments to an Array.
3111
3112			if(typeof command !== 'string') { // Ignore, since no command.
3113				return; // Return undefined to maintain chaining.
3114			}
3115			if(hasConditions) {
3116				args.splice(1, 1); // Remove the conditions from the arguments
3117			}
3118
3119			$.each(this.instances, function() {
3120				// Remember that "this" is the instance's "element" in the $.each() loop.
3121				if(self.element !== this) { // Do not tell my instance.
3122					if(!hasConditions || conditions.call(this.data("jPlayer"), self)) {
3123						this.jPlayer.apply(this, args);
3124					}
3125				}
3126			});
3127		},
3128		pauseOthers: function(time) {
3129			this.tellOthers("pause", function() {
3130				// In the conditions function, the "this" context is the other instance's jPlayer object.
3131				return this.status.srcSet;
3132			}, time);
3133		},
3134		stop: function() {
3135			if(this.status.srcSet) {
3136				if(this.html.active) {
3137					this._html_pause(0);
3138				} else if(this.flash.active) {
3139					this._flash_pause(0);
3140				}
3141			} else {
3142				this._urlNotSetError("stop");
3143			}
3144		},
3145		playHead: function(p) {
3146			p = this._limitValue(p, 0, 100);
3147			if(this.status.srcSet) {
3148				if(this.html.active) {
3149					this._html_playHead(p);
3150				} else if(this.flash.active) {
3151					this._flash_playHead(p);
3152				}
3153			} else {
3154				this._urlNotSetError("playHead");
3155			}
3156		},
3157		_muted: function(muted) {
3158			this.mutedWorker(muted);
3159			if(this.options.globalVolume) {
3160				this.tellOthers("mutedWorker", function() {
3161					// Check the other instance has global volume enabled.
3162					return this.options.globalVolume;
3163				}, muted);
3164			}
3165		},
3166		mutedWorker: function(muted) {
3167			this.options.muted = muted;
3168			if(this.html.used) {
3169				this._html_setProperty('muted', muted);
3170			}
3171			if(this.flash.used) {
3172				this._flash_mute(muted);
3173			}
3174
3175			// The HTML solution generates this event from the media element itself.
3176			if(!this.html.video.gate && !this.html.audio.gate) {
3177				this._updateMute(muted);
3178				this._updateVolume(this.options.volume);
3179				this._trigger($.jPlayer.event.volumechange);
3180			}
3181		},
3182		mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted).
3183			mute = mute === undefined ? true : !!mute;
3184			this._muted(mute);
3185		},
3186		unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted).
3187			unmute = unmute === undefined ? true : !!unmute;
3188			this._muted(!unmute);
3189		},
3190		_updateMute: function(mute) {
3191			if(mute === undefined) {
3192				mute = this.options.muted;
3193			}
3194			if(this.css.jq.mute.length && this.css.jq.unmute.length) {
3195				if(this.status.noVolume) {
3196					this.css.jq.mute.hide();
3197					this.css.jq.unmute.hide();
3198				} else if(mute) {
3199					this.css.jq.mute.hide();
3200					this.css.jq.unmute.show();
3201				} else {
3202					this.css.jq.mute.show();
3203					this.css.jq.unmute.hide();
3204				}
3205			}
3206		},
3207		volume: function(v) {
3208			this.volumeWorker(v);
3209			if(this.options.globalVolume) {
3210				this.tellOthers("volumeWorker", function() {
3211					// Check the other instance has global volume enabled.
3212					return this.options.globalVolume;
3213				}, v);
3214			}
3215		},
3216		volumeWorker: function(v) {
3217			v = this._limitValue(v, 0, 1);
3218			this.options.volume = v;
3219
3220			if(this.html.used) {
3221				this._html_setProperty('volume', v);
3222			}
3223			if(this.flash.used) {
3224				this._flash_volume(v);
3225			}
3226
3227			// The HTML solution generates this event from the media element itself.
3228			if(!this.html.video.gate && !this.html.audio.gate) {
3229				this._updateVolume(v);
3230				this._trigger($.jPlayer.event.volumechange);
3231			}
3232		},
3233		volumeBar: function(e) { // Handles clicks on the volumeBar
3234			if(this.css.jq.volumeBar.length) {
3235				// Using $(e.currentTarget) to enable multiple volume bars
3236				var $bar = $(e.currentTarget),
3237					offset = $bar.offset(),
3238					x = e.pageX - offset.left,
3239					w = $bar.width(),
3240					y = $bar.height() - e.pageY + offset.top,
3241					h = $bar.height();
3242				if(this.options.verticalVolume) {
3243					this.volume(y/h);
3244				} else {
3245					this.volume(x/w);
3246				}
3247			}
3248			if(this.options.muted) {
3249				this._muted(false);
3250			}
3251		},
3252		_updateVolume: function(v) {
3253			if(v === undefined) {
3254				v = this.options.volume;
3255			}
3256			v = this.options.muted ? 0 : v;
3257
3258			if(this.status.noVolume) {
3259				if(this.css.jq.volumeBar.length) {
3260					this.css.jq.volumeBar.hide();
3261				}
3262				if(this.css.jq.volumeBarValue.length) {
3263					this.css.jq.volumeBarValue.hide();
3264				}
3265				if(this.css.jq.volumeMax.length) {
3266					this.css.jq.volumeMax.hide();
3267				}
3268			} else {
3269				if(this.css.jq.volumeBar.length) {
3270					this.css.jq.volumeBar.show();
3271				}
3272				if(this.css.jq.volumeBarValue.length) {
3273					this.css.jq.volumeBarValue.show();
3274					this.css.jq.volumeBarValue[this.options.verticalVolume ? "height" : "width"]((v*100)+"%");
3275				}
3276				if(this.css.jq.volumeMax.length) {
3277					this.css.jq.volumeMax.show();
3278				}
3279			}
3280		},
3281		volumeMax: function() { // Handles clicks on the volume max
3282			this.volume(1);
3283			if(this.options.muted) {
3284				this._muted(false);
3285			}
3286		},
3287		_cssSelectorAncestor: function(ancestor) {
3288			var self = this;
3289			this.options.cssSelectorAncestor = ancestor;
3290			this._removeUiClass();
3291			this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+
3292			if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning.
3293				this._warning( {
3294					type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
3295					context: ancestor,
3296					message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.",
3297					hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
3298				});
3299			}
3300			this._addUiClass();
3301			$.each(this.options.cssSelector, function(fn, cssSel) {
3302				self._cssSelector(fn, cssSel);
3303			});
3304
3305			// Set the GUI to the current state.
3306			this._updateInterface();
3307			this._updateButtons();
3308			this._updateAutohide();
3309			this._updateVolume();
3310			this._updateMute();
3311		},
3312		_cssSelector: function(fn, cssSel) {
3313			var self = this;
3314			if(typeof cssSel === 'string') {
3315				if($.jPlayer.prototype.options.cssSelector[fn]) {
3316					if(this.css.jq[fn] && this.css.jq[fn].length) {
3317						this.css.jq[fn].unbind(".jPlayer");
3318					}
3319					this.options.cssSelector[fn] = cssSel;
3320					this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel;
3321
3322					if(cssSel) { // Checks for empty string
3323						this.css.jq[fn] = $(this.css.cs[fn]);
3324					} else {
3325						this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set.
3326					}
3327
3328					if(this.css.jq[fn].length && this[fn]) {
3329						var handler = function(e) {
3330							e.preventDefault();
3331							self[fn](e);
3332							$(this).blur();
3333						};
3334						this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace
3335					}
3336
3337					if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one.
3338						this._warning( {
3339							type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
3340							context: this.css.cs[fn],
3341							message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.",
3342							hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
3343						});
3344					}
3345				} else {
3346					this._warning( {
3347						type: $.jPlayer.warning.CSS_SELECTOR_METHOD,
3348						context: fn,
3349						message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD,
3350						hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD
3351					});
3352				}
3353			} else {
3354				this._warning( {
3355					type: $.jPlayer.warning.CSS_SELECTOR_STRING,
3356					context: cssSel,
3357					message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING,
3358					hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING
3359				});
3360			}
3361		},
3362		duration: function(e) {
3363			if(this.options.toggleDuration) {
3364				if(this.options.captureDuration) {
3365					e.stopPropagation();
3366				}
3367				this._setOption("remainingDuration", !this.options.remainingDuration);
3368			}
3369		},
3370		seekBar: function(e) { // Handles clicks on the seekBar
3371			if(this.css.jq.seekBar.length) {
3372				// Using $(e.currentTarget) to enable multiple seek bars
3373				var $bar = $(e.currentTarget),
3374					offset = $bar.offset(),
3375					x = e.pageX - offset.left,
3376					w = $bar.width(),
3377					p = 100 * x / w;
3378				this.playHead(p);
3379			}
3380		},
3381		playbackRate: function(pbr) {
3382			this._setOption("playbackRate", pbr);
3383		},
3384		playbackRateBar: function(e) { // Handles clicks on the playbackRateBar
3385			if(this.css.jq.playbackRateBar.length) {
3386				// Using $(e.currentTarget) to enable multiple playbackRate bars
3387				var $bar = $(e.currentTarget),
3388					offset = $bar.offset(),
3389					x = e.pageX - offset.left,
3390					w = $bar.width(),
3391					y = $bar.height() - e.pageY + offset.top,
3392					h = $bar.height(),
3393					ratio, pbr;
3394				if(this.options.verticalPlaybackRate) {
3395					ratio = y/h;
3396				} else {
3397					ratio = x/w;
3398				}
3399				pbr = ratio * (this.options.maxPlaybackRate - this.options.minPlaybackRate) + this.options.minPlaybackRate;
3400				this.playbackRate(pbr);
3401			}
3402		},
3403		_updatePlaybackRate: function() {
3404			var pbr = this.options.playbackRate,
3405				ratio = (pbr - this.options.minPlaybackRate) / (this.options.maxPlaybackRate - this.options.minPlaybackRate);
3406			if(this.status.playbackRateEnabled) {
3407				if(this.css.jq.playbackRateBar.length) {
3408					this.css.jq.playbackRateBar.show();
3409				}
3410				if(this.css.jq.playbackRateBarValue.length) {
3411					this.css.jq.playbackRateBarValue.show();
3412					this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate ? "height" : "width"]((ratio*100)+"%");
3413				}
3414			} else {
3415				if(this.css.jq.playbackRateBar.length) {
3416					this.css.jq.playbackRateBar.hide();
3417				}
3418				if(this.css.jq.playbackRateBarValue.length) {
3419					this.css.jq.playbackRateBarValue.hide();
3420				}
3421			}
3422		},
3423		repeat: function() { // Handle clicks on the repeat button
3424			this._loop(true);
3425		},
3426		repeatOff: function() { // Handle clicks on the repeatOff button
3427			this._loop(false);
3428		},
3429		_loop: function(loop) {
3430			if(this.options.loop !== loop) {
3431				this.options.loop = loop;
3432				this._updateButtons();
3433				this._trigger($.jPlayer.event.repeat);
3434			}
3435		},
3436
3437		// Options code adapted from ui.widget.js (1.8.7).  Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1.
3438		option: function(key, value) {
3439			var options = key;
3440
3441			 // Enables use: options().  Returns a copy of options object
3442			if ( arguments.length === 0 ) {
3443				return $.extend( true, {}, this.options );
3444			}
3445
3446			if(typeof key === "string") {
3447				var keys = key.split(".");
3448
3449				 // Enables use: options("someOption")  Returns a copy of the option. Supports dot notation.
3450				if(value === undefined) {
3451
3452					var opt = $.extend(true, {}, this.options);
3453					for(var i = 0; i < keys.length; i++) {
3454						if(opt[keys[i]] !== undefined) {
3455							opt = opt[keys[i]];
3456						} else {
3457							this._warning( {
3458								type: $.jPlayer.warning.OPTION_KEY,
3459								context: key,
3460								message: $.jPlayer.warningMsg.OPTION_KEY,
3461								hint: $.jPlayer.warningHint.OPTION_KEY
3462							});
3463							return undefined;
3464						}
3465					}
3466					return opt;
3467				}
3468
3469				 // Enables use: options("someOptionObject", someObject}).  Creates: {someOptionObject:someObject}
3470				 // Enables use: options("someOption", someValue).  Creates: {someOption:someValue}
3471				 // Enables use: options("someOptionObject.someOption", someValue).  Creates: {someOptionObject:{someOption:someValue}}
3472
3473				options = {};
3474				var opts = options;
3475
3476				for(var j = 0; j < keys.length; j++) {
3477					if(j < keys.length - 1) {
3478						opts[keys[j]] = {};
3479						opts = opts[keys[j]];
3480					} else {
3481						opts[keys[j]] = value;
3482					}
3483				}
3484			}
3485
3486			 // Otherwise enables use: options(optionObject).  Uses original object (the key)
3487
3488			this._setOptions(options);
3489
3490			return this;
3491		},
3492		_setOptions: function(options) {
3493			var self = this;
3494			$.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth.
3495				self._setOption(key, value);
3496			});
3497
3498			return this;
3499		},
3500		_setOption: function(key, value) {
3501			var self = this;
3502
3503			// The ability to set options is limited at this time.
3504
3505			switch(key) {
3506				case "volume" :
3507					this.volume(value);
3508					break;
3509				case "muted" :
3510					this._muted(value);
3511					break;
3512				case "globalVolume" :
3513					this.options[key] = value;
3514					break;
3515				case "cssSelectorAncestor" :
3516					this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor.
3517					break;
3518				case "cssSelector" :
3519					$.each(value, function(fn, cssSel) {
3520						self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks.
3521					});
3522					break;
3523				case "playbackRate" :
3524					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
3525					if(this.html.used) {
3526						this._html_setProperty('playbackRate', value);
3527					}
3528					this._updatePlaybackRate();
3529					break;
3530				case "defaultPlaybackRate" :
3531					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
3532					if(this.html.used) {
3533						this._html_setProperty('defaultPlaybackRate', value);
3534					}
3535					this._updatePlaybackRate();
3536					break;
3537				case "minPlaybackRate" :
3538					this.options[key] = value = this._limitValue(value, 0.1, this.options.maxPlaybackRate - 0.1);
3539					this._updatePlaybackRate();
3540					break;
3541				case "maxPlaybackRate" :
3542					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate + 0.1, 16);
3543					this._updatePlaybackRate();
3544					break;
3545				case "fullScreen" :
3546					if(this.options[key] !== value) { // if changed
3547						var wkv = $.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;
3548						if(!wkv || wkv && !this.status.waitForPlay) {
3549							if(!wkv) { // No sensible way to unset option on these devices.
3550								this.options[key] = value;
3551							}
3552							if(value) {
3553								this._requestFullscreen();
3554							} else {
3555								this._exitFullscreen();
3556							}
3557							if(!wkv) {
3558								this._setOption("fullWindow", value);
3559							}
3560						}
3561					}
3562					break;
3563				case "fullWindow" :
3564					if(this.options[key] !== value) { // if changed
3565						this._removeUiClass();
3566						this.options[key] = value;
3567						this._refreshSize();
3568					}
3569					break;
3570				case "size" :
3571					if(!this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
3572						this._removeUiClass();
3573					}
3574					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3575					this._refreshSize();
3576					break;
3577				case "sizeFull" :
3578					if(this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
3579						this._removeUiClass();
3580					}
3581					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3582					this._refreshSize();
3583					break;
3584				case "autohide" :
3585					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3586					this._updateAutohide();
3587					break;
3588				case "loop" :
3589					this._loop(value);
3590					break;
3591				case "remainingDuration" :
3592					this.options[key] = value;
3593					this._updateInterface();
3594					break;
3595				case "toggleDuration" :
3596					this.options[key] = value;
3597					break;
3598				case "nativeVideoControls" :
3599					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3600					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
3601					this._restrictNativeVideoControls();
3602					this._updateNativeVideoControls();
3603					break;
3604				case "noFullWindow" :
3605					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3606					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); // Need to check again as noFullWindow can depend on this flag and the restrict() can override it.
3607					this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
3608					this._restrictNativeVideoControls();
3609					this._updateButtons();
3610					break;
3611				case "noVolume" :
3612					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3613					this.status.noVolume = this._uaBlocklist(this.options.noVolume);
3614					this._updateVolume();
3615					this._updateMute();
3616					break;
3617				case "emulateHtml" :
3618					if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already.
3619						this.options[key] = value;
3620						if(value) {
3621							this._emulateHtmlBridge();
3622						} else {
3623							this._destroyHtmlBridge();
3624						}
3625					}
3626					break;
3627				case "timeFormat" :
3628					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
3629					break;
3630				case "keyEnabled" :
3631					this.options[key] = value;
3632					if(!value && this === $.jPlayer.focus) {
3633						$.jPlayer.focus = null;
3634					}
3635					break;
3636				case "keyBindings" :
3637					this.options[key] = $.extend(true, {}, this.options[key], value); // store a merged DEEP copy of it, incase not all properties changed.
3638					break;
3639				case "audioFullScreen" :
3640					this.options[key] = value;
3641					break;
3642			}
3643
3644			return this;
3645		},
3646		// End of: (Options code adapted from ui.widget.js)
3647
3648		_refreshSize: function() {
3649			this._setSize(); // update status and jPlayer element size
3650			this._addUiClass(); // update the ui class
3651			this._updateSize(); // update internal sizes
3652			this._updateButtons();
3653			this._updateAutohide();
3654			this._trigger($.jPlayer.event.resize);
3655		},
3656		_setSize: function() {
3657			// Determine the current size from the options
3658			if(this.options.fullWindow) {
3659				this.status.width = this.options.sizeFull.width;
3660				this.status.height = this.options.sizeFull.height;
3661				this.status.cssClass = this.options.sizeFull.cssClass;
3662			} else {
3663				this.status.width = this.options.size.width;
3664				this.status.height = this.options.size.height;
3665				this.status.cssClass = this.options.size.cssClass;
3666			}
3667
3668			// Set the size of the jPlayer area.
3669			this.element.css({'width': this.status.width, 'height': this.status.height});
3670		},
3671		_addUiClass: function() {
3672			if(this.ancestorJq.length) {
3673				this.ancestorJq.addClass(this.status.cssClass);
3674			}
3675		},
3676		_removeUiClass: function() {
3677			if(this.ancestorJq.length) {
3678				this.ancestorJq.removeClass(this.status.cssClass);
3679			}
3680		},
3681		_updateSize: function() {
3682			// The poster uses show/hide so can simply resize it.
3683			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
3684
3685			// Video html or flash resized if necessary at this time, or if native video controls being used.
3686			if(!this.status.waitForPlay && this.html.active && this.status.video || this.html.video.available && this.html.used && this.status.nativeVideoControls) {
3687				this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
3688			}
3689			else if(!this.status.waitForPlay && this.flash.active && this.status.video) {
3690				this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
3691			}
3692		},
3693		_updateAutohide: function() {
3694			var	self = this,
3695				event = "mousemove.jPlayer",
3696				namespace = ".jPlayerAutohide",
3697				eventType = event + namespace,
3698				handler = function() {
3699					self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() {
3700						clearTimeout(self.internal.autohideId);
3701						self.internal.autohideId = setTimeout( function() {
3702							self.css.jq.gui.fadeOut(self.options.autohide.fadeOut);
3703						}, self.options.autohide.hold);
3704					});
3705				};
3706
3707			if(this.css.jq.gui.length) {
3708
3709				// End animations first so that its callback is executed now.
3710				// Otherwise an in progress fadeIn animation still has the callback to fadeOut again.
3711				this.css.jq.gui.stop(true, true);
3712
3713				// Removes the fadeOut operation from the fadeIn callback.
3714				clearTimeout(this.internal.autohideId);
3715
3716				this.element.unbind(namespace);
3717				this.css.jq.gui.unbind(namespace);
3718
3719				if(!this.status.nativeVideoControls) {
3720					if(this.options.fullWindow && this.options.autohide.full || !this.options.fullWindow && this.options.autohide.restored) {
3721						this.element.bind(eventType, handler);
3722						this.css.jq.gui.bind(eventType, handler);
3723						this.css.jq.gui.hide();
3724					} else {
3725						this.css.jq.gui.show();
3726					}
3727				} else {
3728					this.css.jq.gui.hide();
3729				}
3730			}
3731		},
3732		fullScreen: function() {
3733			this._setOption("fullScreen", true);
vendor: 8,794 bytes, lines 3733-3995
3733
3734		},
3735		restoreScreen: function() {
3736			this._setOption("fullScreen", false);
3737		},
3738		_fullscreenAddEventListeners: function() {
3739			var self = this,
3740				fs = $.jPlayer.nativeFeatures.fullscreen;
3741
3742			if(fs.api.fullscreenEnabled) {
3743				if(fs.event.fullscreenchange) {
3744					// Create the event handler function and store it for removal.
3745					if(typeof this.internal.fullscreenchangeHandler !== 'function') {
3746						this.internal.fullscreenchangeHandler = function() {
3747							self._fullscreenchange();
3748						};
3749					}
3750					document.addEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
3751				}
3752				// No point creating handler for fullscreenerror.
3753				// Either logic avoids fullscreen occurring (w3c/moz), or their is no event on the browser (webkit).
3754			}
3755		},
3756		_fullscreenRemoveEventListeners: function() {
3757			var fs = $.jPlayer.nativeFeatures.fullscreen;
3758			if(this.internal.fullscreenchangeHandler) {
3759				document.removeEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
3760			}
3761		},
3762		_fullscreenchange: function() {
3763			// If nothing is fullscreen, then we cannot be in fullscreen mode.
3764			if(this.options.fullScreen && !$.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()) {
3765				this._setOption("fullScreen", false);
3766			}
3767		},
3768		_requestFullscreen: function() {
3769			// Either the container or the jPlayer div
3770			var e = this.ancestorJq.length ? this.ancestorJq[0] : this.element[0],
3771				fs = $.jPlayer.nativeFeatures.fullscreen;
3772
3773			// This method needs the video element. For iOS and Android.
3774			if(fs.used.webkitVideo) {
3775				e = this.htmlElement.video;
3776			}
3777
3778			if(fs.api.fullscreenEnabled) {
3779				fs.api.requestFullscreen(e);
3780			}
3781		},
3782		_exitFullscreen: function() {
3783
3784			var fs = $.jPlayer.nativeFeatures.fullscreen,
3785				e;
3786
3787			// This method needs the video element. For iOS and Android.
3788			if(fs.used.webkitVideo) {
3789				e = this.htmlElement.video;
3790			}
3791
3792			if(fs.api.fullscreenEnabled) {
3793				fs.api.exitFullscreen(e);
3794			}
3795		},
3796		_html_initMedia: function(media) {
3797			// Remove any existing track elements
3798			var $media = $(this.htmlElement.media).empty();
3799
3800			// Create any track elements given with the media, as an Array of track Objects.
3801			$.each(media.track || [], function(i,v) {
3802				var track = document.createElement('track');
3803				track.setAttribute("kind", v.kind ? v.kind : "");
3804				track.setAttribute("src", v.src ? v.src : "");
3805				track.setAttribute("srclang", v.srclang ? v.srclang : "");
3806				track.setAttribute("label", v.label ? v.label : "");
3807				if(v.def) {
3808					track.setAttribute("default", v.def);
3809				}
3810				$media.append(track);
3811			});
3812
3813			this.htmlElement.media.src = this.status.src;
3814
3815			if(this.options.preload !== 'none') {
3816				this._html_load(); // See function for comments
3817			}
3818			this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution.
3819		},
3820		_html_setFormat: function(media) {
3821			var self = this;
3822			// Always finds a format due to checks in setMedia()
3823			$.each(this.formats, function(priority, format) {
3824				if(self.html.support[format] && media[format]) {
3825					self.status.src = media[format];
3826					self.status.format[format] = true;
3827					self.status.formatType = format;
3828					return false;
3829				}
3830			});
3831		},
3832		_html_setAudio: function(media) {
3833			this._html_setFormat(media);
3834			this.htmlElement.media = this.htmlElement.audio;
3835			this._html_initMedia(media);
3836		},
3837		_html_setVideo: function(media) {
3838			this._html_setFormat(media);
3839			if(this.status.nativeVideoControls) {
3840				this.htmlElement.video.poster = this._validString(media.poster) ? media.poster : "";
3841			}
3842			this.htmlElement.media = this.htmlElement.video;
3843			this._html_initMedia(media);
3844		},
3845		_html_resetMedia: function() {
3846			if(this.htmlElement.media) {
3847				if(this.htmlElement.media.id === this.internal.video.id && !this.status.nativeVideoControls) {
3848					this.internal.video.jq.css({'width':'0px', 'height':'0px'});
3849				}
3850				this.htmlElement.media.pause();
3851			}
3852		},
3853		_html_clearMedia: function() {
3854			if(this.htmlElement.media) {
3855				this.htmlElement.media.src = "about:blank";
3856				// The following load() is only required for Firefox 3.6 (PowerMacs).
3857				// Recent HTMl5 browsers only require the src change. Due to changes in W3C spec and load() effect.
3858				this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress.
3859			}
3860		},
3861		_html_load: function() {
3862			// This function remains to allow the early HTML5 browsers to work, such as Firefox 3.6
3863			// A change in the W3C spec for the media.load() command means that this is no longer necessary.
3864			// This command should be removed and actually causes minor undesirable effects on some browsers. Such as loading the whole file and not only the metadata.
3865			if(this.status.waitForLoad) {
3866				this.status.waitForLoad = false;
3867				this.htmlElement.media.load();
3868			}
3869			clearTimeout(this.internal.htmlDlyCmdId);
3870		},
3871		_html_play: function(time) {
3872			var self = this,
3873				media = this.htmlElement.media;
3874
3875			this.androidFix.pause = false; // Cancel the pause fix.
3876
3877			this._html_load(); // Loads if required and clears any delayed commands.
3878
3879			// Setup the Android Fix.
3880			if(this.androidFix.setMedia) {
3881				this.androidFix.play = true;
3882				this.androidFix.time = time;
3883
3884			} else if(!isNaN(time)) {
3885
3886				// Attempt to play it, since iOS has been ignoring commands
3887				if(this.internal.cmdsIgnored) {
3888					media.play();
3889				}
3890
3891				try {
3892					// !media.seekable is for old HTML5 browsers, like Firefox 3.6.
3893					// Checking seekable.length is important for iOS6 to work with setMedia().play(time)
3894					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
3895						media.currentTime = time;
3896						media.play();
3897					} else {
3898						throw 1;
3899					}
3900				} catch(err) {
3901					this.internal.htmlDlyCmdId = setTimeout(function() {
3902						self.play(time);
3903					}, 250);
3904					return; // Cancel execution and wait for the delayed command.
3905				}
3906			} else {
3907				media.play();
3908			}
3909			this._html_checkWaitForPlay();
3910		},
3911		_html_pause: function(time) {
3912			var self = this,
3913				media = this.htmlElement.media;
3914
3915			this.androidFix.play = false; // Cancel the play fix.
3916
3917			if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
3918				this._html_load(); // Loads if required and clears any delayed commands.
3919			} else {
3920				clearTimeout(this.internal.htmlDlyCmdId);
3921			}
3922
3923			// Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime.
3924			media.pause();
3925
3926			// Setup the Android Fix.
3927			if(this.androidFix.setMedia) {
3928				this.androidFix.pause = true;
3929				this.androidFix.time = time;
3930
3931			} else if(!isNaN(time)) {
3932				try {
3933					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
3934						media.currentTime = time;
3935					} else {
3936						throw 1;
3937					}
3938				} catch(err) {
3939					this.internal.htmlDlyCmdId = setTimeout(function() {
3940						self.pause(time);
3941					}, 250);
3942					return; // Cancel execution and wait for the delayed command.
3943				}
3944			}
3945			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3946				this._html_checkWaitForPlay();
3947			}
3948		},
3949		_html_playHead: function(percent) {
3950			var self = this,
3951				media = this.htmlElement.media;
3952
3953			this._html_load(); // Loads if required and clears any delayed commands.
3954
3955			// This playHead() method needs a refactor to apply the android fix.
3956
3957			try {
3958				if(typeof media.seekable === "object" && media.seekable.length > 0) {
3959					media.currentTime = percent * media.seekable.end(media.seekable.length-1) / 100;
3960				} else if(media.duration > 0 && !isNaN(media.duration)) {
3961					media.currentTime = percent * media.duration / 100;
3962				} else {
3963					throw "e";
3964				}
3965			} catch(err) {
3966				this.internal.htmlDlyCmdId = setTimeout(function() {
3967					self.playHead(percent);
3968				}, 250);
3969				return; // Cancel execution and wait for the delayed command.
3970			}
3971			if(!this.status.waitForLoad) {
3972				this._html_checkWaitForPlay();
3973			}
3974		},
3975		_html_checkWaitForPlay: function() {
3976			if(this.status.waitForPlay) {
3977				this.status.waitForPlay = false;
3978				if(this.css.jq.videoPlay.length) {
3979					this.css.jq.videoPlay.hide();
3980				}
3981				if(this.status.video) {
3982					this.internal.poster.jq.hide();
3983					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
3984				}
3985			}
3986		},
3987		_html_setProperty: function(property, value) {
3988			if(this.html.audio.available) {
3989				this.htmlElement.audio[property] = value;
3990			}
3991			if(this.html.video.available) {
3992				this.htmlElement.video[property] = value;
3993			}
3994		},
3995		_
vendor: 12,159 bytes, lines 3995-4341
3995flash_setAudio: function(media) {
3996			var self = this;
3997			try {
3998				// Always finds a format due to checks in setMedia()
3999				$.each(this.formats, function(priority, format) {
4000					if(self.flash.support[format] && media[format]) {
4001						switch (format) {
4002							case "m4a" :
4003							case "fla" :
4004								self._getMovie().fl_setAudio_m4a(media[format]);
4005								break;
4006							case "mp3" :
4007								self._getMovie().fl_setAudio_mp3(media[format]);
4008								break;
4009							case "rtmpa":
4010								self._getMovie().fl_setAudio_rtmp(media[format]);
4011								break;
4012						}
4013						self.status.src = media[format];
4014						self.status.format[format] = true;
4015						self.status.formatType = format;
4016						return false;
4017					}
4018				});
4019
4020				if(this.options.preload === 'auto') {
4021					this._flash_load();
4022					this.status.waitForLoad = false;
4023				}
4024			} catch(err) { this._flashError(err); }
4025		},
4026		_flash_setVideo: function(media) {
4027			var self = this;
4028			try {
4029				// Always finds a format due to checks in setMedia()
4030				$.each(this.formats, function(priority, format) {
4031					if(self.flash.support[format] && media[format]) {
4032						switch (format) {
4033							case "m4v" :
4034							case "flv" :
4035								self._getMovie().fl_setVideo_m4v(media[format]);
4036								break;
4037							case "rtmpv":
4038								self._getMovie().fl_setVideo_rtmp(media[format]);
4039								break;
4040						}
4041						self.status.src = media[format];
4042						self.status.format[format] = true;
4043						self.status.formatType = format;
4044						return false;
4045					}
4046				});
4047
4048				if(this.options.preload === 'auto') {
4049					this._flash_load();
4050					this.status.waitForLoad = false;
4051				}
4052			} catch(err) { this._flashError(err); }
4053		},
4054		_flash_resetMedia: function() {
4055			this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE.
4056			this._flash_pause(NaN);
4057		},
4058		_flash_clearMedia: function() {
4059			try {
4060				this._getMovie().fl_clearMedia();
4061			} catch(err) { this._flashError(err); }
4062		},
4063		_flash_load: function() {
4064			try {
4065				this._getMovie().fl_load();
4066			} catch(err) { this._flashError(err); }
4067			this.status.waitForLoad = false;
4068		},
4069		_flash_play: function(time) {
4070			try {
4071				this._getMovie().fl_play(time);
4072			} catch(err) { this._flashError(err); }
4073			this.status.waitForLoad = false;
4074			this._flash_checkWaitForPlay();
4075		},
4076		_flash_pause: function(time) {
4077			try {
4078				this._getMovie().fl_pause(time);
4079			} catch(err) { this._flashError(err); }
4080			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
4081				this.status.waitForLoad = false;
4082				this._flash_checkWaitForPlay();
4083			}
4084		},
4085		_flash_playHead: function(p) {
4086			try {
4087				this._getMovie().fl_play_head(p);
4088			} catch(err) { this._flashError(err); }
4089			if(!this.status.waitForLoad) {
4090				this._flash_checkWaitForPlay();
4091			}
4092		},
4093		_flash_checkWaitForPlay: function() {
4094			if(this.status.waitForPlay) {
4095				this.status.waitForPlay = false;
4096				if(this.css.jq.videoPlay.length) {
4097					this.css.jq.videoPlay.hide();
4098				}
4099				if(this.status.video) {
4100					this.internal.poster.jq.hide();
4101					this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
4102				}
4103			}
4104		},
4105		_flash_volume: function(v) {
4106			try {
4107				this._getMovie().fl_volume(v);
4108			} catch(err) { this._flashError(err); }
4109		},
4110		_flash_mute: function(m) {
4111			try {
4112				this._getMovie().fl_mute(m);
4113			} catch(err) { this._flashError(err); }
4114		},
4115		_getMovie: function() {
4116			return document[this.internal.flash.id];
4117		},
4118		_getFlashPluginVersion: function() {
4119
4120			// _getFlashPluginVersion() code influenced by:
4121			// - FlashReplace 1.01: http://code.google.com/p/flashreplace/
4122			// - SWFObject 2.2: http://code.google.com/p/swfobject/
4123
4124			var version = 0,
4125				flash;
4126			if(window.ActiveXObject) {
4127				try {
4128					flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
4129					if (flash) { // flash will return null when ActiveX is disabled
4130						var v = flash.GetVariable("$version");
4131						if(v) {
4132							v = v.split(" ")[1].split(",");
4133							version = parseInt(v[0], 10) + "." + parseInt(v[1], 10);
4134						}
4135					}
4136				} catch(e) {}
4137			}
4138			else if(navigator.plugins && navigator.mimeTypes.length > 0) {
4139				flash = navigator.plugins["Shockwave Flash"];
4140				if(flash) {
4141					version = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1");
4142				}
4143			}
4144			return version * 1; // Converts to a number
4145		},
4146		_checkForFlash: function (version) {
4147			var flashOk = false;
4148			if(this._getFlashPluginVersion() >= version) {
4149				flashOk = true;
4150			}
4151			return flashOk;
4152		},
4153		_validString: function(url) {
4154			return (url && typeof url === "string"); // Empty strings return false
4155		},
4156		_limitValue: function(value, min, max) {
4157			return (value < min) ? min : ((value > max) ? max : value);
4158		},
4159		_urlNotSetError: function(context) {
4160			this._error( {
4161				type: $.jPlayer.error.URL_NOT_SET,
4162				context: context,
4163				message: $.jPlayer.errorMsg.URL_NOT_SET,
4164				hint: $.jPlayer.errorHint.URL_NOT_SET
4165			});
4166		},
4167		_flashError: function(error) {
4168			var errorType;
4169			if(!this.internal.ready) {
4170				errorType = "FLASH";
4171			} else {
4172				errorType = "FLASH_DISABLED";
4173			}
4174			this._error( {
4175				type: $.jPlayer.error[errorType],
4176				context: this.internal.flash.swf,
4177				message: $.jPlayer.errorMsg[errorType] + error.message,
4178				hint: $.jPlayer.errorHint[errorType]
4179			});
4180			// Allow the audio player to recover if display:none and then shown again, or with position:fixed on Firefox.
4181			// This really only affects audio in a media player, as an audio player could easily move the jPlayer element away from such issues.
4182			this.internal.flash.jq.css({'width':'1px', 'height':'1px'});
4183		},
4184		_error: function(error) {
4185			this._trigger($.jPlayer.event.error, error);
4186			if(this.options.errorAlerts) {
4187				this._alert("Error!" + (error.message ? "\n" + error.message : "") + (error.hint ? "\n" + error.hint : "") + "\nContext: " + error.context);
4188			}
4189		},
4190		_warning: function(warning) {
4191			this._trigger($.jPlayer.event.warning, undefined, warning);
4192			if(this.options.warningAlerts) {
4193				this._alert("Warning!" + (warning.message ? "\n" + warning.message : "") + (warning.hint ? "\n" + warning.hint : "") + "\nContext: " + warning.context);
4194			}
4195		},
4196		_alert: function(message) {
4197			var msg = "jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message;
4198			if(!this.options.consoleAlerts) {
4199				alert(msg);
4200			} else if(window.console && window.console.log) {
4201				window.console.log(msg);
4202			}
4203		},
4204		_emulateHtmlBridge: function() {
4205			var self = this;
4206
4207			// Emulate methods on jPlayer's DOM element.
4208			$.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) {
4209				self.internal.domNode[name] = function(arg) {
4210					self[name](arg);
4211				};
4212
4213			});
4214
4215			// Bubble jPlayer events to its DOM element.
4216			$.each($.jPlayer.event, function(eventName,eventType) {
4217				var nativeEvent = true;
4218				$.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) {
4219					if(name === eventName) {
4220						nativeEvent = false;
4221						return false;
4222					}
4223				});
4224				if(nativeEvent) {
4225					self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces.
4226						self._emulateHtmlUpdate();
4227						var domEvent = document.createEvent("Event");
4228						domEvent.initEvent(eventName, false, true);
4229						self.internal.domNode.dispatchEvent(domEvent);
4230					});
4231				}
4232				// The error event would require a special case
4233			});
4234
4235			// IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState.
4236		},
4237		_emulateHtmlUpdate: function() {
4238			var self = this;
4239
4240			$.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) {
4241				self.internal.domNode[name] = self.status[name];
4242			});
4243			$.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) {
4244				self.internal.domNode[name] = self.options[name];
4245			});
4246		},
4247		_destroyHtmlBridge: function() {
4248			var self = this;
4249
4250			// Bridge event handlers are also removed by destroy() through .jPlayer namespace.
4251			this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option.
4252
4253			// Remove the methods and properties
4254			var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions;
4255			$.each( emulated.split(/\s+/g), function(i, name) {
4256				delete self.internal.domNode[name];
4257			});
4258		}
4259	};
4260
4261	$.jPlayer.error = {
4262		FLASH: "e_flash",
4263		FLASH_DISABLED: "e_flash_disabled",
4264		NO_SOLUTION: "e_no_solution",
4265		NO_SUPPORT: "e_no_support",
4266		URL: "e_url",
4267		URL_NOT_SET: "e_url_not_set",
4268		VERSION: "e_version"
4269	};
4270
4271	$.jPlayer.errorMsg = {
4272		FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError()
4273		FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError()
4274		NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init()
4275		NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia()
4276		URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners()
4277		URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead()
4278		VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady()
4279	};
4280
4281	$.jPlayer.errorHint = {
4282		FLASH: "Check your swfPath option and that Jplayer.swf is there.",
4283		FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.",
4284		NO_SOLUTION: "Review the jPlayer options: support and supplied.",
4285		NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.",
4286		URL: "Check media URL is valid.",
4287		URL_NOT_SET: "Use setMedia() to set the media URL.",
4288		VERSION: "Update jPlayer files."
4289	};
4290
4291	$.jPlayer.warning = {
4292		CSS_SELECTOR_COUNT: "e_css_selector_count",
4293		CSS_SELECTOR_METHOD: "e_css_selector_method",
4294		CSS_SELECTOR_STRING: "e_css_selector_string",
4295		OPTION_KEY: "e_option_key"
4296	};
4297
4298	$.jPlayer.warningMsg = {
4299		CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ",
4300		CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",
4301		CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
4302		OPTION_KEY: "The option requested in jPlayer('option') is undefined."
4303	};
4304
4305	$.jPlayer.warningHint = {
4306		CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.",
4307		CSS_SELECTOR_METHOD: "Check your method name.",
4308		CSS_SELECTOR_STRING: "Check your css selector is a string.",
4309		OPTION_KEY: "Check your option name."
4310	};
4311}));
4312
4313/*
4314 * Playlist Object for the jPlayer Plugin
4315 * http://www.jplayer.org
4316 *
4317 * Copyright (c) 2009 - 2013 Happyworm Ltd
4318 * Licensed under the MIT license.
4319 * http://www.opensource.org/licenses/MIT
4320 *
4321 * Author: Mark J Panaghiston
4322 * Version: 2.3.0
4323 * Date: 20th April 2013
4324 *
4325 * Requires:
4326 *  - jQuery 1.7.0+
4327 *  - jPlayer 2.3.0+
4328 */
4329
4330/* Code verified using http://www.jshint.com/ */
4331/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false, smarttabs:true */
4332/*global  jPlayerPlaylist:true */
4333
4334(function($, undefined) {
4335
4336	jPlayerPlaylist = function(cssSelector, playlist, options) {
4337		var self = this;
4338
4339		this.current = 0;
4340		this.loop = false; // Flag used with the jPlayer repeat event
4341		this.shuffled = false;
vendor: 8,036 bytes, lines 4342-4581
4342		this.removing = false; // Flag is true during remove animation, disabling the remove() method until complete.
4343
4344		this.cssSelector = $.extend({}, this._cssSelector, cssSelector); // Object: Containing the css selectors for jPlayer and its cssSelectorAncestor
4345		this.options = $.extend(true, {
4346			keyBindings: {
4347				next: {
4348					key: 39, // RIGHT
4349					fn: function() {
4350						self.next();
4351					}
4352				},
4353				previous: {
4354					key: 37, // LEFT
4355					fn: function() {
4356						self.previous();
4357					}
4358				}
4359			}
4360		}, this._options, options); // Object: The jPlayer constructor options for this playlist and the playlist options
4361
4362		this.playlist = []; // Array of Objects: The current playlist displayed (Un-shuffled or Shuffled)
4363		this.original = []; // Array of Objects: The original playlist
4364
4365		this._initPlaylist(playlist); // Copies playlist to this.original. Then mirrors this.original to this.playlist. Creating two arrays, where the element pointers match. (Enables pointer comparison.)
4366
4367		// Setup the css selectors for the extra interface items used by the playlist.
4368		this.cssSelector.title = this.cssSelector.cssSelectorAncestor + " .jp-title"; // Note that the text is written to the decendant li node.
4369		this.cssSelector.playlist = this.cssSelector.cssSelectorAncestor + " .jp-playlist";
4370		this.cssSelector.next = this.cssSelector.cssSelectorAncestor + " .jp-next";
4371		this.cssSelector.previous = this.cssSelector.cssSelectorAncestor + " .jp-previous";
4372		this.cssSelector.shuffle = this.cssSelector.cssSelectorAncestor + " .jp-shuffle";
4373		this.cssSelector.shuffleOff = this.cssSelector.cssSelectorAncestor + " .jp-shuffle-off";
4374
4375		// Override the cssSelectorAncestor given in options
4376		this.options.cssSelectorAncestor = this.cssSelector.cssSelectorAncestor;
4377
4378		// Override the default repeat event handler
4379		this.options.repeat = function(event) {
4380			self.loop = event.jPlayer.options.loop;
4381		};
4382
4383		// Create a ready event handler to initialize the playlist
4384		$(this.cssSelector.jPlayer).bind($.jPlayer.event.ready, function() {
4385			self._init();
4386		});
4387
4388		// Create an ended event handler to move to the next item
4389		$(this.cssSelector.jPlayer).bind($.jPlayer.event.ended, function() {
4390			self.next();
4391		});
4392
4393		// Create a play event handler to pause other instances
4394		$(this.cssSelector.jPlayer).bind($.jPlayer.event.play, function() {
4395			$(this).jPlayer("pauseOthers");
4396		});
4397
4398		// Create a resize event handler to show the title in full screen mode.
4399		$(this.cssSelector.jPlayer).bind($.jPlayer.event.resize, function(event) {
4400			if(event.jPlayer.options.fullScreen) {
4401				$(self.cssSelector.title).show();
4402			} else {
4403				$(self.cssSelector.title).hide();
4404			}
4405		});
4406
4407		// Create click handlers for the extra buttons that do playlist functions.
4408		$(this.cssSelector.previous).click(function() {
4409			self.previous();
4410			$(this).blur();
4411			return false;
4412		});
4413
4414		$(this.cssSelector.next).click(function() {
4415			self.next();
4416			$(this).blur();
4417			return false;
4418		});
4419
4420		$(this.cssSelector.shuffle).click(function() {
4421			self.shuffle(true);
4422			return false;
4423		});
4424		$(this.cssSelector.shuffleOff).click(function() {
4425			self.shuffle(false);
4426			return false;
4427		}).hide();
4428
4429		// Put the title in its initial display state
4430		if(!this.options.fullScreen) {
4431			$(this.cssSelector.title).hide();
4432		}
4433
4434		// Remove the empty <li> from the page HTML. Allows page to be valid HTML, while not interfereing with display animations
4435		$(this.cssSelector.playlist + " ul").empty();
4436
4437		// Create .on() handlers for the playlist items along with the free media and remove controls.
4438		this._createItemHandlers();
4439
4440		// Instance jPlayer
4441		$(this.cssSelector.jPlayer).jPlayer(this.options);
4442	};
4443
4444	jPlayerPlaylist.prototype = {
4445		_cssSelector: { // static object, instanced in constructor
4446			jPlayer: "#jquery_jplayer_1",
4447			cssSelectorAncestor: "#jp_container_1"
4448		},
4449		_options: { // static object, instanced in constructor
4450			playlistOptions: {
4451				autoPlay: false,
4452				loopOnPrevious: false,
4453				shuffleOnLoop: true,
4454				enableRemoveControls: false,
4455				displayTime: 'slow',
4456				addTime: 'fast',
4457				removeTime: 'fast',
4458				shuffleTime: 'slow',
4459				itemClass: "jp-playlist-item",
4460				freeGroupClass: "jp-free-media",
4461				freeItemClass: "jp-playlist-item-free",
4462				removeItemClass: "jp-playlist-item-remove"
4463			}
4464		},
4465		option: function(option, value) { // For changing playlist options only
4466			if(value === undefined) {
4467				return this.options.playlistOptions[option];
4468			}
4469
4470			this.options.playlistOptions[option] = value;
4471
4472			switch(option) {
4473				case "enableRemoveControls":
4474					this._updateControls();
4475					break;
4476				case "itemClass":
4477				case "freeGroupClass":
4478				case "freeItemClass":
4479				case "removeItemClass":
4480					this._refresh(true); // Instant
4481					this._createItemHandlers();
4482					break;
4483			}
4484			return this;
4485		},
4486		_init: function() {
4487			var self = this;
4488			this._refresh(function() {
4489				if(self.options.playlistOptions.autoPlay) {
4490					self.play(self.current);
4491				} else {
4492					self.select(self.current);
4493				}
4494			});
4495		},
4496		_initPlaylist: function(playlist) {
4497			this.current = 0;
4498			this.shuffled = false;
4499			this.removing = false;
4500			this.original = $.extend(true, [], playlist); // Copy the Array of Objects
4501			this._originalPlaylist();
4502		},
4503		_originalPlaylist: function() {
4504			var self = this;
4505			this.playlist = [];
4506			// Make both arrays point to the same object elements. Gives us 2 different arrays, each pointing to the same actual object. ie., Not copies of the object.
4507			$.each(this.original, function(i) {
4508				self.playlist[i] = self.original[i];
4509			});
4510		},
4511		_refresh: function(instant) {
4512			/* instant: Can be undefined, true or a function.
4513			 *	undefined -> use animation timings
4514			 *	true -> no animation
4515			 *	function -> use animation timings and excute function at half way point.
4516			 */
4517			var self = this;
4518
4519			if(instant && !$.isFunction(instant)) {
4520				$(this.cssSelector.playlist + " ul").empty();
4521				$.each(this.playlist, function(i) {
4522					$(self.cssSelector.playlist + " ul").append(self._createListItem(self.playlist[i]));
4523				});
4524				this._updateControls();
4525			} else {
4526				var displayTime = $(this.cssSelector.playlist + " ul").children().length ? this.options.playlistOptions.displayTime : 0;
4527
4528				$(this.cssSelector.playlist + " ul").slideUp(displayTime, function() {
4529					var $this = $(this);
4530					$(this).empty();
4531
4532					$.each(self.playlist, function(i) {
4533						$this.append(self._createListItem(self.playlist[i]));
4534					});
4535					self._updateControls();
4536					if($.isFunction(instant)) {
4537						instant();
4538					}
4539					if(self.playlist.length) {
4540						$(this).slideDown(self.options.playlistOptions.displayTime);
4541					} else {
4542						$(this).show();
4543					}
4544				});
4545			}
4546		},
4547		_createListItem: function(media) {
4548			var self = this;
4549
4550			// Wrap the <li> contents in a <div>
4551			var listItem = "<li><div>";
4552
4553			// Create remove control
4554			listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.removeItemClass + "'>&times;</a>";
4555
4556			// Create links to free media
4557			if(media.free) {
4558				var first = true;
4559				listItem += "<span class='" + this.options.playlistOptions.freeGroupClass + "'>(";
4560				$.each(media, function(property,value) {
4561					if($.jPlayer.prototype.format[property]) { // Check property is a media format.
4562						if(first) {
4563							first = false;
4564						} else {
4565							listItem += " | ";
4566						}
4567						listItem += "<a class='" + self.options.playlistOptions.freeItemClass + "' href='" + value + "' tabindex='1'>" + property + "</a>";
4568					}
4569				});
4570				listItem += ")</span>";
4571			}
4572
4573			// The title is given next in the HTML otherwise the float:right on the free media corrupts in IE6/7
4574			listItem += "<a href='javascript:;' class='" + this.options.playlistOptions.itemClass + "' tabindex='1'>" + media.title + (media.artist ? " <span class='jp-artist'>by " + media.artist + "</span>" : "") + "</a>";
4575			listItem += "</div></li>";
4576
4577			return listItem;
4578		},
4579		_createItemHandlers: function() {
4580			var self = this;
4581			// Create live handlers for the playlist items
4582			$(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.itemClass).on("click", "a." + this.options.playlistOptions.itemClass, function() {
4583				var index = $(this).parent().parent().index();
4584				if(self.current !== index) {
4585					self.play(index);
4586				} else {
4587					$(self.cssSelector.jPlayer).jPlayer("play");
4588				}
4589				$(this).blur();
4590				return false;
4591			});
4592
4593			// Create live handlers that disable free media links to force access via right click
4594			$(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.freeItemClass).on("click", "a." + this.options.playlistOptions.freeItemClass, function() {
4595				$(this).parent().parent().find("." + self.options.playlistOptions.itemClass).click();
4596				$(this).blur();
4597				return false;
4598			});
4599
4600			// Create live handlers for the remove controls
4601			$(this.cssSelector.playlist).off("click", "a." + this.options.playlistOptions.removeItemClass).on("click", "a." + this.options.playlistOptions.removeItemClass, function() {
4602				var index = $(this).parent().parent().index();
4603				self.remove(index);
4604				$(this).blur();
4605				return false;
4606			});
4607		},
4608		_updateControls: function() {
4609			if(this.options.playlistOptions.enableRemoveControls) {
4610				$(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).show();
4611			} else {
4612				$(this.cssSelector.playlist + " ." + this.options.playlistOptions.removeItemClass).hide();
4613			}
4614			if(this.shuffled) {
4615				$(this.cssSelector.shuffleOff).show();
4616				$(this.cssSelector.shuffle).hide();
4617			} else {
4618				$(this.cssSelector.shuffleOff).hide();
4619				$(this.cssSelector.shuffle).show();
4620			}
4621		},
4622		_highlight: function(index) {
4623			if(this.playlist.length && index !== undefined) {
4624				$(this.cssSelector.playlist + " .jp-playlist-current").removeClass("jp-playlist-current");
4625				$(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current");
4626				$(this.cssSelector.title + " li").html(this.playlist[index].title + (this.playlist[index].artist ? " <span class='jp-artist'>by " + this.playlist[index].artist + "</span>" : ""));
4627			}
4628		},
4629		setPlaylist: function(playlist) {
4630			this._initPlaylist(playlist);
4631			this._init();
4632		},
4633		add: function(media, playNow) {
4634			$(this.cssSelector.playlist + " ul").append(this._createListItem(media)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);
4635			this._updateControls();
4636			this.original.push(media);
4637			this.playlist.push(media); // Both array elements share the same object pointer. Comforms with _initPlaylist(p) system.
4638
4639			if(playNow) {
4640				this.play(this.playlist.length - 1);
4641			} else {
4642				if(this.original.length === 1) {
4643					this.select(0);
4644				}
4645			}
4646		},
4647		remove: function(index) {
4648			var self = this;
4649
4650			if(index === undefined) {
4651				this._initPlaylist([]);
4652				this._refresh(function() {
4653					$(self.cssSelector.jPlayer).jPlayer("clearMedia");
4654				});
4655				return true;
4656			} else {
4657
4658				if(this.removing) {
4659					return false;
4660				} else {
4661					index = (index < 0) ? self.original.length + index : index; // Negative index relates to end of array.
4662					if(0 <= index && index < this.playlist.length) {
4663						this.removing = true;
4664
4665						$(this.cssSelector.playlist + " li:nth-child(" + (index + 1) + ")").slide
4665Up(this.options.playlistOptions.removeTime, function() {
4666							$(this).remove();
4667
4668							if(self.shuffled) {
4669								var item = self.playlist[index];
4670								$.each(self.original, function(i) {
4671									if(self.original[i] === item) {
4672										self.original.splice(i, 1);
4673										return false; // Exit $.each
4674									}
4675								});
4676								self.playlist.splice(index, 1);
4677							} else {
4678								self.original.splice(index, 1);
4679								self.playlist.splice(index, 1);
4680							}
4681
4682							if(self.original.length) {
4683								if(index === self.current) {
4684									self.current = (index < self.original.length) ? self.current : self.original.length - 1; // To cope when last element being selected when it was removed
4685									self.select(self.current);
4686								} else if(index < self.current) {
4687									self.current--;
4688								}
4689							} else {
4690								$(self.cssSelector.jPlayer).jPlayer("clearMedia");
4691								self.current = 0;
4692								self.shuffled = false;
4693								self._updateControls();
4694							}
4695
4696							self.removing = false;
4697						});
4698					}
4699					return true;
4700				}
4701			}
4702		},
4703		select: function(index) {
4704			index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
4705			if(0 <= index && index < this.playlist.length) {
4706				this.current = index;
4707				this._highlight(index);
4708				$(this.cssSelector.jPlayer).jPlayer("setMedia", this.playlist[this.current]);
4709			} else {
4710				this.current = 0;
4711			}
4712		},
4713		play: function(index) {
4714			index = (index < 0) ? this.original.length + index : index; // Negative index relates to end of array.
4715			if(0 <= index && index < this.playlist.length) {
4716				if(this.playlist.length) {
4717					this.select(index);
4718					$(this.cssSelector.jPlayer).jPlayer("play");
4719				}
4720			} else if(index === undefined) {
4721				$(this.cssSelector.jPlayer).jPlayer("play");
4722			}
4723		},
4724		pause: function() {
4725			$(this.cssSelector.jPlayer).jPlayer("pause");
4726		},
4727		next: function() {
4728			var index = (this.current + 1 < this.playlist.length) ? this.current + 1 : 0;
4729
4730			if(this.loop) {
4731				// See if we need to shuffle before looping to start, and only shuffle if more than 1 item.
4732				if(index === 0 && this.shuffled && this.options.playlistOptions.shuffleOnLoop && this.playlist.length > 1) {
4733					this.shuffle(true, true); // playNow
4734				} else {
4735					this.play(index);
4736				}
4737			} else {
4738				// The index will be zero if it just looped round
4739				if(index > 0) {
4740					this.play(index);
4741				}
4742			}
4743		},
4744		previous: function() {
4745			var index = (this.current - 1 >= 0) ? this.current - 1 : this.playlist.length - 1;
4746
4747			if(this.loop && this.options.playlistOptions.loopOnPrevious || index < this.playlist.length - 1) {
4748				this.play(index);
4749			}
4750		},
4751		shuffle: function(shuffled, playNow) {
4752			var self = this;
4753
4754			if(shuffled === undefined) {
4755				shuffled = !this.shuffled;
4756			}
4757
4758			if(shuffled || shuffled !== this.shuffled) {
4759
4760				$(this.cssSelector.playlist + " ul").slideUp(this.options.playlistOptions.shuffleTime, function() {
4761					self.shuffled = shuffled;
4762					if(shuffled) {
4763						self.playlist.sort(function() {
4764							return 0.5 - Math.random();
4765						});
4766					} else {
4767						self._originalPlaylist();
4768					}
4769					self._refresh(true); // Instant
4770
4771					if(playNow || !$(self.cssSelector.jPlayer).data("jPlayer").status.paused) {
4772						self.play(0);
4773					} else {
4774						self.select(0);
4775					}
4776
4777					$(this).slideDown(self.options.playlistOptions.shuffleTime);
4778				});
4779			}
4780		}
4781	};
4782})(jQuery);
4783;
4784/*global _soundcheckSettings:true, jPlayerPlaylist:false */
4785
4786window.soundcheck = window.soundcheck || {};
4787
4788(function( window, $, undefined ) {
4789	'use strict';
4790
4791	var $body = $( 'body' ),
4792	    soundcheck = window.soundcheck;
4793
4794	$.extend( soundcheck, {
4795		config: {},
4796
4797		init: function() {
4798			$body.addClass( 'ontouchstart' in window || 'onmsgesturechange' in window ? 'touch' : 'no-touch' );
4799
4800			// Scrolls down to content area on pages that are not the home/blog page.
4801			if ( ! $body.hasClass( 'home' ) && ! $body.hasClass( 'blog' ) ) {
4802				var headerHeight = $( '#header' ).height(),
4803				    navigationHeight = $( '#primary-nav' ).height();
4804
4805				$( 'html, body' ).animate({
4806					scrollTop: headerHeight - navigationHeight
4807				}, 500 );
4808			}
4809		},
4810
4811		getParameterByName: function( name ) {
4812			name = name.replace( /[\[]/, '\\\[' ).replace( /[\]]/, '\\\]' );
4813
4814			var regexS  = '[\\?&]' + name + '=([^&#]*)',
4815			    regex   = new RegExp( regexS ),
4816			    results = regex.exec( window.location.search );
4817
4818			if ( results == null ) {
4819				return '';
4820			} else {
4821				return decodeURIComponent( results[1].replace( /\+/g, ' ' ) );
4822			}
4823		},
4824
4825		/**
4826		 * Set up featured image carousel.
4827		 */
4828		setupAudioPlayer: function() {
4829			// Misc (localized in includes/hooks.php)
4830			var audio = $.parseJSON( _soundcheckSettings.audioPlayer.tracks.replace( /&quot;/g, '"' ) );
4831
4832			// Check if playlist has a value
4833			if( audio.playlist ) {
4834				$( '[id^="jp_container_"]' ).each( function() {
4835					// Player vars
4836					var newID       = this.id.replace( /jp_container_/, '' ),
4837					    randID      = newID.substr(0,4),
4838					    theID       = newID.substr(5),
4839					    theTracks   = audio.playlist[theID],
4840					    thePlayer   = $( '#jp_container_' + randID + '_' + theID ),
4841					    Tracklist   = 'playlist' + randID + '_' + theID;
4842
4843					// Player display vars
4844					var jpPlaylist     = $( '.jp-type-playlist', thePlayer ),
4845					    jpPlaylistView = $( '.jp-playlist-view', thePlayer ),
4846					    jpPlaylistNav  = $( '.jp-playlist', thePlayer ),
4847					    jpContent      = $( '.jp-content', thePlayer ),
4848					    jpContentView  = $( '.jp-content-view', thePlayer ),
4849					    jpTrack        = $( '.jp-current-track span', thePlayer ),
4850					    jpArtist       = $( '.jp-current-artist span', thePlayer ),
4851					    jpAlbum        = $( '.jp-current-album span', thePlayer ),
4852					    jpArtwork      = $( '.jp-current-artwork img.artwork', thePlayer ),
4853					    jpCurrentTime  = $( '.jp-current-time-wrap', thePlayer ),
4854					    jpNowPlaying   = $( '.jp-now-playing', thePlayer ),
4855					    jpNotifictions = $( '.jp-notification', thePlayer );
4856
4857					// Used for playlist_view() to only effect the content area and not the players in the sidebar.
4858					var jpPlaylistNavContent  = $( '.single #content .jp-playlist' );
4859
4860					// Update current track information
4861					function update_current_track_info() {
4862						var currentItem   = Tracklist.playlist[Tracklist.current],
4863						    currentTrack  = ( currentItem.title )  ? currentItem.title : '',
4864						    currentArtist = ( currentItem.artist ) ? currentItem.artist : '',
4865						    currentAlbum  = ( currentItem.album )  ? currentItem.album : '',
4866						    currentPoster = ( currentItem.poster ) ? currentItem.poster : '';
4867
4868						jpTrack.html( currentTrack );
4869						jpArtist.html( currentArtist );
4870						jpAlbum.html( currentAlbum );
4871						jpArtwork.attr( 'src', currentPoster );
4872					}
4873
4874					function is_widget() {
4875						if ( thePlayer.parent().parent().hasClass( 'widget' ) ) {
4876							return 1;
4877						} else {
4878							return 0;
4879						}
4880					}
4881
4882					// Show and Hide playlist
4883					function show_hide_playlist(shouldShow) {
4884						if ( 1 === is_widget() ) {
4885							if( shouldShow ) {
4886								thePlayer.removeClass( 'hide-playlist' );
4887								jpPlaylistNav.fadeIn( 'fast' );
4888							} else {
4889								jpPlaylistNav.fadeOut( 'fast', function() {
4890									thePlayer.addClass( 'hide-playlist' );
4891								});
4892							}
4893						} else {
4894							if( shouldShow ) {
4895								thePlayer.removeClass( 'hide-playlist');
4896								jpPlaylistNav.slideDown( 'fast' );
4897							} else {
4898								jpPlaylistNav.slideUp( 'fast', function() {
4899									thePlayer.addClass( 'hide-playlist' );
4900								});
4901							}
4902						}
4903					}
4904
4905					// Show and Hide player content
4906					function show_hide_content( shouldShow ) {
4907						if ( shouldShow ) {
4908							thePlayer.removeClass( 'hide-content');
4909							jpContent.slideDown( 'fast' );
4910						} else {
4911							jpContent.slideUp( 'fast', function() {
4912								thePlayer.addClass( 'hide-content');
4913							});
4914						}
4915					}
4916
4917					// Show playlist if option is checked in Theme Options
4918					function playlist_view() {
4919						if ( _soundcheckSettings.audioPlayer.options.showPlaylist ) {
4920							jpPlaylistNavContent.hide();
4921						} else {
4922							jpPlaylistNavContent.show();
4923						}
4924					}
4925
4926					// Hide notification messages - Loading & Updated Info
4927					function on_ready() {
4928						jpNotifictions.hide();
4929						jpNowPlaying.fadeTo( 200, 1 );
4930						playlist_view();
4931						update_current_track_info();
4932						jpPlaylist.removeClass( 'preloading' ).addClass( 'loaded' );
4933
4934						if( jpPlaylistNav.is( ':visible' ) ) {
4935							jpPlaylistView.addClass( 'open' );
4936						} else {
4937							jpPlaylistView.removeClass( 'open' );
4938						}
4939					}
4940
4941					// Performed each time a track is played.
4942					function on_play() {
4943						update_current_track_info();
4944						jpCurrentTime.fadeTo( 'fast', 1 );
4945						thePlayer.addClass( 'playing' );
4946					}
4947
4948					// Performed each time a track is paused.
4949					function on_pause() {
4950						jpCurrentTime.fadeTo( 'fast', 0 );
4951						thePlayer.removeClass( 'playing' );
4952					}
4953
4954					// Add track number
4955					function add_track_number() {
4956						var jpTrackNumber = $('.jp-track-number', thePlayer );
4957
4958						jpTrackNumber.remove();
4959
4960						$('.tracks li', thePlayer ).each( function() {
4961							var trackNumber = $( this ).index() + 1;
4962
4963							$( this ).find( 'a.jp-playlist-item').wrapInner( '<span class="jp-track-title" />' );
4964							$( this ).find( 'a.jp-playlist-item').prepend( '<span class="jp-track-number">' + trackNumber + '.</span>');
4965						});
4966					}
4967
4968					// Update buttons
4969					$( '.jp-next, .jp-previous, .jp-playlist-item' ).click( function() {
4970						update_current_track_info();
4971					});
4972
4973					// Show and Hide playlist
4974					jpPlaylistView.click(function(e){
4975						e.preventDefault();
4976
4977						if( jpPlaylistNav.is( ':visible' ) ) {
4978							show_hide_playlist();
4979							jpPlaylistView.removeClass( 'open' );
4980						} else {
4981							show_hide_playlist(true);
4982							jpPlaylistView.addClass( 'open' );
4983						}
4984					});
4985
4986					// Show and Hide playlist
4987					jpContentView.click( function(e){
4988						e.preventDefault();
4989
4990						if ( jpContent.is( ':visible' ) ) {
4991							show_hide_content();
4992							jpContentView.removeClass( 'open' );
4993						} else {
4994							show_hide_content( true );
4995							jpContentView.addClass( 'open' );
4996						}
4997					});
4998
4999
5000					Tracklist = new jPlayerPlaylist({
5001							jPlayer: '#jquery_jplayer_' + randID + '_' + theID,
5002							cssSelectorAncestor: '#jp_container_' + randID + '_' + theID
5003						},
5004							theTracks, // track list
5005						{
5006						playlistOptions: {
5007							enableRemoveControls: false,
5008							autoPlay: ( 1 === is_widget() ) ? 0 : _soundcheckSettings.audioPlayer.options.autoplay
5009						},
5010						supplied: 'mp3',
5011						wmode: 'window',
5012						solution: 'html',
5013						ready: function() {
5014						    on_ready();
5015						    add_track_number();
5016						},
5017						play: function() {
5018							on_play();
5019						},
5020						pause: function() {
5021							on_pause();
5022						},
5023						ended: function() {
5024							update_current_track_info();
5025						}
5026					});
5027				});
5028			}
5029		},
5030
5031		/**
5032		 * Set up featured image carousel.
5033		 */
5034		setupEvents: function() {
5035			var filterLink = $( '.events-filter-list .filter-list-items-container a' ),
5036			    filterTitleWidth = $( '.events-list-items .event:first .event-date' ).width(),
5037			    event_id = soundcheck.getParameterByName( 'event_id' );
5038
5039			filterLink.click( function() {
5040				$( 'li.event' ).removeClass( 'inactive' );
5041
5042				filterLink.not( this ).removeClass( 'active' );
5043				$( this ).addClass('active');
5044
5045				var activeCat = $( this ).attr( 'href' ).replace( '#', '' ).toLowerCase();
5046
5047				$( '#content li.event' ).not( 'li.' + activeCat ).addClass( 'inactive' ).children().stop( true, true ).animate({ opacity: '.3' }, 350 );
5048				$( '#content li.' + activeCat ).children().stop( true, true ).animate({ opacity: '1' }, 350 );
5049
5050				return false;
5051			});
5052
5053			// Make filter title width the same as the first date
5054			$( '.events-list-container .filter-title' ).css( 'width', filterTitleWidth );
5055
5056			// Event Description Display
5057			$( '.page-template-template-events-php .event' ).each( function() {
5058				var event = this;
5059
5060				$( '.event-title', event ).click( function() {
5061					$( event ).toggleClass( 'active' );
5062					$( '.event-description', event ).slideToggle( 'fast' );
5063				});
5064			});
5065
5066			// Widget Settings
5067			if ( event_id ) {
5068				var id = '#content #post-' + event_id;
5069
5070				$( id ).addClass( 'active' );
5071				$( '.event-description', id ).slideDown( 'fast' );
5072			}
5073		},
5074
5075		/**
5076		 * Set up hero slider
5077		 *
5078		 * - Displays featured content in an conent slider.
5079		 * - Adds click events to active, next, and prevous slides. Next and
5080		 *   previous slides will trigger the sliders directional nav events,
5081		 *   advancing the slider in either direction.
5082		 */
5083		setupHeroSlider: function() {
5084			var $hero = $( '.hero-container' ),
5085			    hero  = _soundcheckSettings.heroSlider;
5086
5087			$hero.flexslider({
5088				namespace      : hero.namespace,
5089				animation      : hero.animation,
5090				direction      : hero.direction,
5091				slideshowSpeed : parseInt( hero.slideshowSpeed, 10 ),
5092				animationSpeed : parseInt( hero.animationSpeed, 10 ),
5093				prevText       : hero.prevText,
5094				nextText       : hero.nextText
5095			});
5096		},
5097
5098		/**
5099		 * Set up featured image carousel.
5100		 */
5101		setupImageCarousel: function() {
5102			var $carousel = $( '#image-carousel-container' );
5103
5104			$carousel.flexslider({
5105				namespace: 'image-carousel-',
5106				selector: '.image-carousel-items > li',
5107				animation: 'slide',
5108				animationLoop: false,
5109				itemWidth: 134,
5110				itemMargin: 20,
5111				slideshow: false
5112			});
5113		},
5114
5115		/**
5116		 * Set up videos.
5117		 *
5118		 * - Makes videos responsive.
5119		 * - Moves videos embedded in page content to an '.entry-video'
5120		 *   container. Used primarily with the WPCOM single video templates.
5121		 */
5122		setupVideos: function() {
5123			$( '.hentry' ).fitVids({
5124				customSelector: 'iframe[src^="http://dailymotion.com"], embed[src^="http://v.wordpress.com"]'
5125			});
5126
5127			$( '.site-content .format-video' ).each( function() {
5128				var $this = $( this ),
5129				    video = $this.find( '.wp-embed' ).first();
5130
5131				if ( video.length ) {
5132					// Remove video paragraph wrapper.
5133					if ( video.parent().is( 'p' ) ) {
5134						video.unwrap();
5135					}
5136
5137					$( '.entry-video', $this ).append( video ).addClass( 'has-video' );
5138				}
5139			});
5140		}
5141	});
5142
5143	// Document ready.
5144	jQuery( function() {
5145		soundcheck.init();
5146		soundcheck.setupAudioPlayer();
5147		soundcheck.setupEvents();
5148		soundcheck.setupHeroSlider();
5149		soundcheck.setupImageCarousel();
5150		soundcheck.setupVideos();
5151	});
5152
5153})( this, jQuery );
5154;
5155!function(){"use strict";var e,t={noop:function(){},texturize:function(e){return(e=(e=(e=(e+="").replace(/'/g,"&#8217;").replace(/&#039;/g,"&#8217;")).replace(/"/g,"&#8221;").replace(/&#034;/g,"&#8221;").replace(/&quot;/g,"&#8221;").replace(/[\u201D]/g,"&#8221;")).replace(/([\w]+)=&#[\d]+;(.+?)&#[\d]+;/g,'$1="$2"')).trim()},applyReplacements:function(e,t){if(e)return t?e.replace(/{(\d+)}/g,function(e,r){return void 0!==t[r]?t[r]:e}):e},getBackgroundImage:function(e){var t=document.createElement("canvas"),r=t.getContext&&t.getContext("2d");if(e){r.filter="blur(20px) ",r.drawImage(e,0,0);var o=t.toDataURL("image/png");return t=null,o}}},r=function(){function e(e,t){return Element.prototype.matches?e.matches(t):Element.prototype.msMatchesSelector?e.msMatchesSelector(t):void 0}function r(e,t,r,o){if(!e)return o();e.jpCarouselCancelFade&&e.jpCarouselCancelFade(),e.classList.remove("jp-carousel-fade"),e.style.removeProperty("display"),e.style.opacity=t,e.style.pointerEvents="none",e.offsetWidth,e.classList.add("jp-carousel-fade"),e.style.opacity=r;var a=1e3*parseFloat(getComputedStyle(e).transitionDuration)||0,i=setTimeout(function(){e.jpCarouselCancelFade=null,e.style.removeProperty("pointer-events"),o()},a+50);e.jpCarouselCancelFade=function(){clearTimeout(i),e.jpCarouselCancelFade=null}}return{closest:function(t,r){if(t.closest)return t.closest(r);var o=t;do{if(e(o,r))return o;o=o.parentElement||o.parentNode}while(null!==o&&1===o.nodeType);return null},matches:e,hide:function(e){e&&(e.style.display="none")},show:function(e){e&&(e.style.display="block")},fadeIn:function(e,o){r(e,0,1,o=o||t.noop)},fadeOut:function(e,o){o=o||t.noop,r(e,1,0,function(){e&&(e.style.display="none"),o()})},scrollToElement:function(e,t,r){if(!e||!t)return r?r():void 0;var o=t.querySelector(".jp-carousel-info-extra");o&&(o.style.minHeight=window.innerHeight-64+"px");var a=!0,i=Date.now(),n=t.scrollTop,l=Math.max(0,e.offsetTop-Math.max(0,window.innerHeight-function(e){var t=e.querySelector(".jp-carousel-info-footer"),r=e.querySelector(".jp-carousel-info-extra"),o=e.querySelector(".jp-carousel-info-content-wrapper");if(t&&r&&o){var a=window.getComputedStyle(r),i=parseInt(a.paddingTop,10)+parseInt(a.paddingBottom,10);return i=isNaN(i)?0:i,o.offsetHeight+t.offsetHeight+i}return 0}(t)))-t.scrollTop;function s(){a=!1}
5155l=Math.min(l,t.scrollHeight-window.innerHeight),t.addEventListener("wheel",s),function e(){var c,u=Date.now(),d=(c=(u-i)/300)<.5?2*c*c:1-Math.pow(-2*c+2,2)/2,p=(d=d>1?1:d)*l;if(t.scrollTop=n+p,u<=i+300&&a)return requestAnimationFrame(e);r&&r(),o&&(o.style.minHeight=""),a=!1,t.removeEventListener("wheel",s)}()},getJSONAttribute:function(e,t){if(e&&e.hasAttribute(t))try{return JSON.parse(e.getAttribute(t))}catch{return}},convertToPlainText:function(e){var t=document.createElement("div");return t.textContent=e,t.innerHTML},stripHTML:function(e){var t=document.createElement("div");return t.innerHTML=e.replace(/<[^>]*>?/gm,""),t.textContent},emitEvent:function(e,t,r){var o;try{o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:r||null})}catch{(o=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,r||null)}e.dispatchEvent(o)},isTouch:function(){return"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch}}}();function o(){var o,a,i,n,l="",s=!1,c="div.gallery, div.tiled-gallery, ul.wp-block-gallery, ul.blocks-gallery-grid, figure.wp-block-gallery.has-nested-images, div.wp-block-jetpack-tiled-gallery, a.single-image-gallery",u=".gallery-item, .tiled-gallery-item, .blocks-gallery-item,  .tiled-gallery__item",d=u+", .wp-block-image",p={},m="undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.stat?wpcom.carousel.stat:t.noop,g="undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.pageview?wpcom.carousel.pageview:t.noop;function h(t){if(!s)switch(t.which){case 38:t.preventDefault(),p.overlay.scrollTop-=100;break;case 40:t.preventDefault(),p.overlay.scrollTop+=100;break;case 39:t.preventDefault(),e.slideNext();break;case 37:case 8:t.preventDefault(),e.slidePrev();break;case 27:t.preventDefault(),x()}}function f(){s=!0}function v(){s=!1}function y(e){e.role="button",e.tabIndex=0,e.ariaLabel=jetpackCarouselStrings.image_label}function w(){p.overlay||(p.overlay=document.querySelector(".jp-carousel-overlay"),p.container=p.overlay.querySelector(".jp-carousel-wrap"),p.gallery=p.container.querySelector(".jp-carousel"),p.info=p.overlay.querySelector(".jp-carousel-info"),p.caption=p.info.querySelector(".jp-carousel-caption"),p.commentField=p.overlay.querySelector("#jp-carousel-comment-form-comment-field"),p.emailField=p.overlay.querySelector("#jp-carousel-comment-form-email-field"),p.authorField=p.overlay.querySelector("#jp-carousel-comment-form-author-field"),p.urlField=p.overlay.querySelector("#jp-carousel-comment-form-url-field"),window.innerWidth<=760&&Math.round(window.innerWidth/760*110)<40&&r.isTouch(),[p.commentField,p.emailField,p.authorField,p.urlField].forEach(function(e){e&&(e.addEventListener("focus",f),e.addEventListener("blur",v))}),p.overlay.addEventListener("click",function(e){var t,o,a=e.target,i=!!r.closest(a,".jp-carousel-close-hint"),n=!!window.matchMedia("(max-device-width: 760px)").matches;a===p.overlay?n||x():i?x():a.classList.contains("jp-carousel-image-download")?m("download_original_click"):a.classList.contains("jp-carousel-comment-login")?(t=p.currentSlide,o=t?t.attrs.attachmentId:"0",window.location.href=jetpackCarouselStrings.login_url+"%23jp-carousel-"+o):r.closest(a,"#jp-carousel-comment-form-container")?function(e){var t=e.target,o=r.getJSONAttribute(p.container,"data-carousel-extra")||{},a=p.currentSlide.attrs.attachmentId,i=document.querySelector("#jp-carousel-comment-form-submit-and-info-wrapper"),n=document.querySelector("#jp-carousel-comment-form-spinner"),l=document.querySelector("#jp-carousel-comment-form-button-submit"),s=document.querySelector("#jp-carousel-comment-form");if(p.commentField&&p.commentField.getAttribute("id")===t.getAttribute("id"))f(),r.show(i);else if(r.matches(t,'input[type="submit"]')){e.preventDefault(),e.stopPropagation(),r.show(n),s.classList.add("jp-carousel-is-disabled");var c={action:"post_attachment_comment",nonce:jetpackCarouselStrings.nonce,blog_id:o.blog_id,id:a,comment:p.commentField.value};if(!c.comment.length)return void j(jetpackCarouselStrings.no_comment_text,!1);if(1!==Number(jetpackCarouselStrings.is_logged_in)&&(c.email=p.emailField.value,c.author=p.authorField.value,c.url=p.urlField.value,1===Number(jetpackCarouselStrings.require_name_email))){if(!c.email.length||!c.email.match("@"))return void j(jetpackCarouselStrings.no_comment_email,!1);if(!c.author.length)return void j(jetpackCarouselStrings.no_comment_author,!1)}var u=new XMLHttpRequest;u.open("POST",jetpackCarouselStrings.ajaxurl,!0),u.setRequestHeader("X-Requested-With","XMLHttpRequest"),u.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"),u.onreadystatechange=function(){if(this.readyState===XMLHttpRequest.DONE&&this.status>=200&&this.status<300){var e;try{e=JSON.parse(this.response)}catch{return void j(jetpackCarouselStrings.comment_post_error,!1)}"approved"===e.comment_status?j(jetpackCarouselStrings.comment_approved,!0):"unapproved"===e.comment_status?j(jetpackCarouselStrings.comment_unapproved,!0):j(jetpackCarouselStrings.comment_post_error,!1),H(),q(a),l.value=jetpackCarouselStrings.post_comment,r.hide(n),s.classList.remove("jp-carousel-is-disabled")}else j(jetpackCarouselStrings.comment_post_error,!1)};var d=[];for(var m in c)if(m){var g=encodeURIComponent(m)+"="+encodeURIComponent(c[m]);d.push(g.replace(/%20/g,"+"))}var h=d.join("&");u.send(h)}}(e):(r.closest(a,".jp-carousel-photo-icons-container")||a.classList.contains("jp-carousel-photo-title"))&&function(e){e.preventDefault();var t=e.target,o=p.info.querySelector(".jp-carousel-info-extra"),a=p.info.querySelector(".jp-carousel-image-meta"),i=p.info.querySelector(".jp-carousel-comments-wrapper"),n=p.info.querySelector(".jp-carousel-icon-info"),l=p.info.querySelector(".jp-carousel-icon-comments");function s(){l&&l.classList.remove("jp-carousel-selected"),n.classList.toggle("jp-carousel-selected"),i&&i.classList.remove("jp-carousel-show"),a&&(a.classList.toggle("jp-carousel-show"),a.classList.contains("jp-carousel-show")?o.classList.add("jp-carousel-show"):o.classList.remove("jp-carousel-show"))}function c(){n&&n.classList.remove("jp-carousel-selected"),l.classList.toggle("jp-carousel-selected"),a&&a.classList.remove("jp-carousel-show"),i&&(i.classList.toggle("jp-carousel-show"),i.classList.contains("jp-carousel-show")?o.classList.add("jp-carousel-show"):o.classList.remove("jp-carousel-show"))}(r.closest(t,".jp-carousel-icon-info")||t.classList.contains("jp-carousel-photo-title"))&&(a&&a.classList.contains("jp-carousel-show")?r.scrollToElement(p.overlay,p.overlay,s):(s(),r.scrollToElement(p.info,p.overlay))),r.closest(t,".jp-carousel-icon-comments")&&(i&&i.classList.contains("jp-carousel-show")?r.scrollToElement(p.overlay,p.overlay,c):(c(),r.scrollToElement(p.info,p.overlay)))}(e)}),window.addEventListener("keydown",h),p.overlay.addEventListener("jp_carousel.afterOpen",function(){v(),p.slides.length<=1||(p.slides.length<=5?r.show(p.info.querySelector(".jp-swiper-pagination")):r.show(p.info.querySelector(".jp-carousel-pagination")))}),p.overlay.addEventListener("jp_carousel.beforeClose",function(){f(),document.documentElement.style.removeProperty("height"),e&&e.enable(),r.hide(p.info.querySelector(".jp-swiper-pagination")),r.hide(p.info.querySelector(".jp-carousel-pagination"))}),p.overlay.addEventListener("jp_carousel.afterClose",function(){window.history.pushState?history.pushState("",document.title,window.location.pathname+window.location.search):window.location.href="",l="",p.isOpen=!1}),p.overlay.addEventListener("touchstart",function(e){e.touches.length>1&&e.preventDefault()}))}function j(e,t){var o=p.overlay.querySelector("#jp-carousel-comment-post-results"),a="jp-carousel-comment-post-"+(t?"success":"error");o.innerHTML='<span class="'+a+'">'+e+"</span>",r.hide(p.overlay.querySelector("#jp-carousel-comment-form-spinner")),p.overlay.querySelector("#jp-carousel-comment-form").classList.remove("jp-carousel-is-disabled"),r.show(o)}function b(){var e=document.querySelectorAll("a img[data-attachment-id]");Array.prototype.forEach.call(e,function(e){var t=e.parentElement,o=t.parentElement;if(!o.classList.contains("gallery-icon")&&!r.closest(o,u)&&t.hasAttribute("href")){var a=!1;t.getAttribute("href").split("?")[0]===e.getAttribute("data-orig-file").split("?")[0]&&1===Number(jetpackCarouselStrings.single_image_gallery_media_file)&&(a=!0),t.getAttribute("href")===e.getAttribute("data-permalink")&&(a=!0),a&&(y(e),t.classList.add("single-image-gallery"),t.setAttribute("data-carousel-extra",JSON.stringify({blog_id:Number(jetpackCarouselStrings.blog_id)})))}})}function S(t,r){p.isOpen?(L(r),e.slideTo(r+1)):M(t,{startIndex:r})}function L(e){(!e||e<0||e>p.slides.length)&&(e=0),p.currentSlide=p.slides[e];var o,a,i=p.currentSlide,n=i.attrs.attachmentId;A(p.slides[e]),function(e){var t=[],r=p.slides.length;if(r>1){var o=e>0?e-1:r-1;t.push(o);var a=e<r-1?e+1:0;t.push(a)}t.forEach(function(e){var t=p.slides[e];t&&(A(t),1!==Number(jetpackCarouselStrings.display_background_image)||t.backgroundImage||_(t))})}(e),1!==Number(jetpackCarouselStrings.display_background_image)||p.slides[e].backgroundImage||_(p.slides[e]),r.hide(p.caption),function(e){var t,o,a,i,n,l,s;if(i=p.overlay.querySelector(".jp-carousel-photo-caption"),n=p.overlay.querySelector(".jp-carousel-caption"),l=p.overlay.querySelector(".jp-carousel-photo-title"),s=p.overlay.querySelector(".jp-carousel-photo-description"),r.hide(i),r.hide(n),r.hide(l),r.hide(s),t=E(e.caption)||"",o=E(e.title)||"",a=E(e.desc)||"",(t||o||a)&&(t&&(i.innerHTML=t,n.innerHTML=t,r.show(i),r.show(n)),r.stripHTML(t)===r.stripHTML(o)&&(o=""),r.stripHTML(t)===r.stripHTML(a)&&(a=""),r.stripHTML(o)===r.stripHTML(a)&&(a=""),a&&(s.innerHTML=a,r.show(s),o||t||(i.textContent=r.stripHTML(a),r.show(i))),o)){var c=r.stripHTML(o);l.textContent=c,t||(i.textContent=c,n.textContent=c,r.show(i)),r.show(l)}}
5155({caption:i.attrs.caption,title:i.attrs.title,desc:i.attrs.desc}),function(e){if(!e||1!==Number(jetpackCarouselStrings.display_exif))return!1;var t=p.info.querySelector(".jp-carousel-image-meta");if(!t)return!1;var r="";for(var o in e){var a=e[o],i=jetpackCarouselStrings.meta_data||[];if(0!==parseFloat(a)&&a.length&&-1!==i.indexOf(o)){switch(o){case"focal_length":a+="mm";break;case"shutter_speed":a=C(a);break;case"aperture":a="f/"+a}r+="<li><h5>"+jetpackCarouselStrings[o]+"</h5>"+a+"</li>"}}var n=t.querySelector("ul.jp-carousel-image-exif");if(""!==r){if(!n){(n=document.createElement("ul")).className="jp-carousel-image-exif";var l=t.querySelector(".jp-carousel-title-and-caption");l&&l.nextSibling?t.insertBefore(n,l.nextSibling):t.insertBefore(n,t.firstChild)}n.innerHTML=r,n.style.removeProperty("display")}else n&&n.parentNode.removeChild(n)}(p.slides[e].attrs.imageMeta),function(e){if(!e)return!1;var r,o=[e.attrs.origWidth,e.attrs.origHeight],a=document.createElement("a");a.href=e.attrs.src.replace(/\?.+$/,""),r=null!==a.hostname.match(/^i[\d]{1}\.wp\.com$/i)?a.href:e.attrs.origFile.replace(/\?.+$/,"");var i=p.info.querySelector(".jp-carousel-download-text"),n=p.info.querySelector(".jp-carousel-image-download");i.innerHTML=t.applyReplacements(jetpackCarouselStrings.download_original,o),n.setAttribute("href",r),n.style.removeProperty("display")}(i),1===Number(jetpackCarouselStrings.display_comments)&&(o=p.slides[e].attrs.commentsOpened,a=p.info.querySelector("#jp-carousel-comment-form-container"),1===parseInt(o,10)?r.fadeIn(a):r.fadeOut(a),q(n),r.hide(p.info.querySelector("#jp-carousel-comment-post-results")));var s=p.info.querySelector(".jp-carousel-pagination");if(s&&p.slides.length>5){var c=e+1;s.innerHTML="<span>"+c+" / "+p.slides.length+"</span>"}jetpackCarouselStrings.stats&&p.isOpen&&((new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?"+jetpackCarouselStrings.stats+"&post="+encodeURIComponent(n)+"&rand="+Math.random()),p.isOpen&&g(n),l="#jp-carousel-"+n,window.location.hash=l}function x(){document.body.style.overflow=a,document.documentElement.style.overflow=i,H(),f(),r.emitEvent(p.overlay,"jp_carousel.beforeClose"),window.scrollTo(window.scrollX||window.pageXOffset||0,n||0),p.isOpen=!1,e.destroy(),p.slides=[],p.currentSlide=void 0,p.gallery.innerHTML="",r.fadeOut(p.overlay,function(){r.emitEvent(p.overlay,"jp_carousel.afterClose")})}function k(e){if("object"!=typeof e&&(e={}),void 0===e.origFile)return"";if(void 0===e.origWidth||void 0===e.maxWidth)return e.origFile;if(!e.largeFile)return e.origFile;var t=document.createElement("a");t.href=e.largeFile;var r=/^i[0-2]\.wp\.com$/i.test(t.hostname),o=function(e,t,r){var o,a=r?e.replace(/.*=([\d]+%2C[\d]+).*$/,"$1"):e.replace(/.*-([\d]+x[\d]+)\..+$/,"$1");return"9999"===(o=a!==e?r?a.split("%2C"):a.split("x"):[t,0])[0]&&(o[0]="0"),"9999"===o[1]&&(o[1]="0"),o}(e.largeFile,e.origWidth,r),a=parseInt(o[0],10),i=parseInt(o[1],10);if(e.origMaxWidth=e.maxWidth,e.origMaxHeight=e.maxHeight,void 0!==window.devicePixelRatio&&window.devicePixelRatio>1&&(e.maxWidth=e.maxWidth*window.devicePixelRatio,e.maxHeight=e.maxHeight*window.devicePixelRatio),a>=e.maxWidth||i>=e.maxHeight)return e.largeFile;if(r){if(-1===e.largeFile.lastIndexOf("?"))return e.largeFile;var n=function(e){var t;try{t=new URL(e)}catch(t){return e}var r=["quality","ssl","filter","brightness","contrast","colorize","smooth"],o=Array.from(t.searchParams.entries());return t.search="",o.forEach(([e,o])=>{r.includes(e)&&t.searchParams.append(e,o)}),t}(e.largeFile);return(e.origWidth>e.maxWidth||e.origHeight>e.maxHeight)&&(e.origMaxWidth=2*e.maxWidth,e.origMaxHeight=2*e.maxHeight,n.searchParams.set("fit",e.origMaxWidth+","+e.origMaxHeight)),n.toString()}return e.origFile}function C(e){return e>=1?Math.round(10*e)/10+"s":"1/"+Math.round(1/e)+"s"}function E(e){return!e.match(" ")&&e.match("_")?"":e}function q(e,t){var a=void 0===t,i=p.info.querySelector(".jp-carousel-icon-comments .jp-carousel-has-comments-indicator");if(i.classList.remove("jp-carousel-show"),clearInterval(o),e){(!t||t<1)&&(t=0);var n=p.info.querySelector(".jp-carousel-comments"),l=p.info.querySelector("#jp-carousel-comments-loading");r.show(l),a&&(r.hide(n),n.innerHTML="");var s=new XMLHttpRequest,c=jetpackCarouselStrings.ajaxurl+"?action=get_attachment_comments&nonce="+jetpackCarouselStrings.nonce+"&id="+e+"&offset="+t;s.open("GET",c),s.setRequestHeader("X-Requested-With","XMLHttpRequest");var u=function(){r.fadeIn(n),r.fadeOut(l)};s.onload=function(){if(p.currentSlide&&p.currentSlide.attrs.attachmentId===e){var c,d=s.status>=200&&s.status<300;try{c=JSON.parse(s.responseText)}catch{}if(!d||!c||!Array.isArray(c))return u();a&&(n.innerHTML="");for(var m=0;m<c.length;m++){var g=c[m],h=document.createElement("div");h.classList.add("jp-carousel-comment"),h.setAttribute("id","jp-carousel-comment-"+g.id),h.innerHTML='<div class="comment-gravatar">'+g.gravatar_markup+'</div><div class="comment-content"><div class="comment-author">'+g.author_markup+'</div><div class="comment-date">'+g.date_gmt+"</div>"+g.content+"</div>",n.appendChild(h),clearInterval(o),o=setInterval(function(){p.container.scrollTop+150>window.innerHeight&&(q(e,t+10),clearInterval(o))},300)}c.length>0&&(r.show(n),i.innerText=c.length,i.classList.add("jp-carousel-show")),r.hide(l)}},s.onerror=u,s.send()}}function A(e){var t=e.attrs,r=e.el.querySelector("img");if(!r.hasAttribute("data-loaded"))if(r.setAttribute("itemprop","image"),r.setAttribute("data-loaded",1),t.previewImage&&t.previewImage!==t.src){r.src=t.previewImage,r.style.filter="blur(8px)";var o=new window.Image;o.addEventListener("load",function(){r.src=t.src,r.style.filter=""},{once:!0}),o.addEventListener("error",function(){r.style.filter=""},{once:!0}),o.src=t.src}else r.src=t.src}function _(e){var t=e.attrs.originalElement;if(t)if(t.complete&&0!==t.naturalHeight)T(e,t);else{var r=function(){t.removeEventListener("error",o),T(e,t)},o=function(){t.removeEventListener("load",r)};t.addEventListener("load",r,{once:!0}),t.addEventListener("error",o,{once:!0})}}
5155function T(e,r){var o=t.getBackgroundImage(r);o&&(e.backgroundImage=o,e.el.style.backgroundImage="url("+o+")",e.el.style.backgroundSize="cover",e.el.style.backgroundPosition="center")}function H(){p.commentField&&(p.commentField.value="")}function I(e,o){p.slides=[];var a={width:window.innerWidth,height:window.innerHeight-64};0!==o&&null!==e[o].getAttribute("data-gallery-src")&&((new Image).src=e[o].getAttribute("data-gallery-src")),Array.prototype.forEach.call(e,function(e,o){var i=r.closest(e,"a"),n=e.getAttribute("data-orig-file")||e.getAttribute("src-orig"),l=e.getAttribute("data-attachment-id")||e.getAttribute("data-id")||"0",s=document.querySelector('img[data-attachment-id="'+l+'"] + figcaption');s=s?s.innerHTML:e.getAttribute("data-image-caption");var c={originalElement:e,attachmentId:l,commentsOpened:e.getAttribute("data-comments-opened")||"0",imageMeta:r.getJSONAttribute(e,"data-image-meta")||{},title:e.getAttribute("data-image-title")||"",desc:e.getAttribute("data-image-description")||"",largeFile:e.getAttribute("data-large-file")||"",origFile:n||"",thumbSize:{width:e.naturalWidth,height:e.naturalHeight},caption:s||"",permalink:i&&i.getAttribute("href"),src:n||e.getAttribute("src")||""},u=r.closest(e,".tiled-gallery-item"),d=u&&u.querySelector(".tiled-gallery-caption"),m=d&&d.innerHTML;m&&(c.caption=m);var g=function(e){var t=e.getAttribute("data-orig-size")||"";if(t){var r=t.split(",");return{width:parseInt(r[0],10),height:parseInt(r[1],10)}}return{width:e.getAttribute("data-original-width")||e.getAttribute("width")||void 0,height:e.getAttribute("data-original-height")||e.getAttribute("height")||void 0}}(e);if(c.origWidth=g.width||c.thumbSize.width,c.origHeight=g.height||c.thumbSize.height,"undefined"!=typeof wpcom&&wpcom.carousel&&wpcom.carousel.generateImgSrc?c.src=wpcom.carousel.generateImgSrc(e,a):c.src=k({origFile:c.src,origWidth:c.origWidth,origHeight:c.origHeight,maxWidth:a.width,maxHeight:a.height,largeFile:c.largeFile}),e.setAttribute("data-gallery-src",c.src),"0"!==c.attachmentId){c.title=t.texturize(c.title),c.desc=t.texturize(c.desc),c.caption=t.texturize(c.caption);var h=new Image,f=document.createElement("div");f.classList.add("swiper-slide"),f.setAttribute("itemprop","associatedMedia"),f.setAttribute("itemscope",""),f.setAttribute("itemtype","https://schema.org/ImageObject");var v=document.createElement("div");v.classList.add("swiper-zoom-container"),p.gallery.appendChild(f),f.appendChild(v),v.appendChild(h),f.setAttribute("data-attachment-id",c.attachmentId),f.setAttribute("data-permalink",c.permalink),f.setAttribute("data-orig-file",c.origFile),c.previewImage=e.currentSrc||e.getAttribute("src")||"";var y={el:f,attrs:c,index:o};p.slides.push(y)}})}function M(e,t){if(!window.JetpackSwiper){var o=document.querySelector("#jp-carousel-loading-overlay");r.show(o);var a=document.createElement("script");return a.id="jetpack-carousel-swiper-js",a.src=window.jetpackSwiperLibraryPath.url,a.async=!0,a.onload=function(){r.hide(o),F(e,t)},a.onerror=function(){r.hide(o)},void document.head.appendChild(a)}F(e,t)}function F(t,o){var l,s={imgSelector:".gallery-item [data-attachment-id], .tiled-gallery-item [data-attachment-id], img[data-attachment-id], img[data-id]",startIndex:0},c=r.getJSONAttribute(t,"data-carousel-extra");if(!c)return;const u=t.querySelectorAll(s.imgSelector);if(u.length&&(w(),!p.isOpen)){for(var d in p.isOpen=!0,a=getComputedStyle(document.body).overflow,document.body.style.overflow="hidden",i=getComputedStyle(document.documentElement).overflow,document.documentElement.style.overflow="hidden",n=window.scrollY||window.pageYOffset||0,p.container.setAttribute("data-carousel-extra",JSON.stringify(c)),m(["open","view_image"]),o||{})s[d]=o[d];-1===s.startIndex&&(s.startIndex=0),r.emitEvent(p.overlay,"jp_carousel.beforeOpen"),p.gallery.innerHTML="",p.overlay.style.opacity=1,p.overlay.style.display="block",I(u,s.startIndex),(e=new window.JetpackSwiper(".jp-carousel-swiper-container",{centeredSlides:!0,zoom:!0,loop:p.slides.length>1,enabled:p.slides.length>1,pagination:{el:".jp-swiper-pagination",clickable:!0},navigation:{nextEl:".jp-swiper-button-next",prevEl:".jp-swiper-button-prev"},initialSlide:s.startIndex,on:{init:function(){L(s.startIndex)}},preventClicks:!1,preventClicksPropagation:!1,preventInteractionOnTransition:!r.isTouch(),threshold:5})).on("slideChange",function(e){p.isOpen&&(L(e.realIndex),p.overlay.classList.remove("jp-carousel-hide-control
5155s"))}),e.on("zoomChange",function(e,t){t>1&&p.overlay.classList.add("jp-carousel-hide-controls"),1===t&&p.overlay.classList.remove("jp-carousel-hide-controls")}),e.on("doubleTap",function(e){if(clearTimeout(l),1===e.zoom.scale)var t=setTimeout(function(){p.overlay.classList.remove("jp-carousel-hide-controls"),clearTimeout(t)},150)}),e.on("tap",function(){e.zoom.scale>1&&(l=setTimeout(function(){p.overlay.classList.toggle("jp-carousel-hide-controls")},150))}),r.fadeIn(p.overlay,function(){r.emitEvent(p.overlay,"jp_carousel.afterOpen")})}}function O(e){if("click"!==e.type){if("keydown"===e.type){const t=document.activeElement.parentElement,r=t&&t.classList.contains("tiled-gallery__item");" "!==e.key&&"Enter"!==e.key||!r||R(e)}}else R(e)}function N(e){return(e||"").split("?")[0].replace(/\/$/,"")}function W(e){"A"===e.tagName&&(e=e.querySelector("img")||e);var t=e.parentElement,o=t?t.parentElement:null,a=null;if(o&&o.classList.contains("wp-block-image")?a=t.getAttribute("href"):t&&t.classList.contains("wp-block-image")&&t.querySelector(":scope > a")&&(a=t.querySelector(":scope > a").getAttribute("href")),a){var i=N(a),n=N(e.getAttribute("data-orig-file")),l=N(e.getAttribute("data-permalink"));if(i!==n&&i!==l)return!1}return!(t&&t.classList.contains("gallery-caption")||r.matches(t,"figcaption"))}function R(e){if(window.CSS&&window.CSS.supports&&window.CSS.supports("display","grid")){var t,o=e.target,a=r.closest(o,c);if(a){if(!(t=a)||!t.getAttribute("data-carousel-extra"))return;if(!W(o))return;document.documentElement.style.height="auto",e.preventDefault(),e.stopPropagation();var i=r.closest(o,d),n=Array.prototype.indexOf.call(a.querySelectorAll(d),i);M(a,{startIndex:n})}}}document.body.addEventListener("click",O),document.body.addEventListener("keydown",O),document.querySelectorAll(u+"img").forEach(function(e){W(e)&&y(e)}),1===Number(jetpackCarouselStrings.single_image_gallery)&&(b(),document.body.addEventListener("is.post-load",function(){b()})),window.addEventListener("hashchange",function(){var e=/jp-carousel-(\d+)/;if(window.location.hash&&e.test(window.location.hash)){if(window.location.hash!==l||!p.isOpen)if(window.location.hash&&p.gallery&&!p.isOpen&&history.back)history.back();else{l=window.location.hash;for(var t=window.location.hash.match(e),r=parseInt(t[1],10),o=document.querySelectorAll(c),a=0;a<o.length;a++){for(var i,n=o[a],s=n.querySelectorAll("img"),u=0;u<s.length;u++)if(parseInt(s[u].getAttribute("data-attachment-id"),10)===r||parseInt(s[u].getAttribute("data-id"),10)===r){i=u;break}if(void 0!==i){S(n,i);break}}}}else p.isOpen&&x()}),window.location.hash&&r.emitEvent(window,"hashchange")}"loading"!==document.readyState?o():document.addEventListener("DOMContentLoaded",o)}();;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.