PageSourceSearch

https://dobbysoven.com/libraries/cycle2.js

js dobbysoven.com collected 2026-10-08 23:17:45 UTC 48,969 bytes, 1,538 lines download raw bytes

1/*!
2* jQuery Cycle2; version: 2.1.6 build: 20141007
3* http://jquery.malsup.com/cycle2/
4* Copyright (c) 2014 M. Alsup; Dual licensed: MIT/GPL
5*/
6
7/* Cycle2 core engine */
8;(function($) {
9"use strict";
10
11var version = '2.1.6';
12
13$.fn.cycle = function( options ) {
14    // fix mistakes with the ready state
15    var o;
16    if ( this.length === 0 && !$.isReady ) {
17        o = { s: this.selector, c: this.context };
18        $.fn.cycle.log('requeuing slideshow (dom not ready)');
19        $(function() {
20            $( o.s, o.c ).cycle(options);
21        });
22        return this;
23    }
24
25    return this.each(function() {
26        var data, opts, shortName, val;
27        var container = $(this);
28        var log = $.fn.cycle.log;
29
30        if ( container.data('cycle.opts') )
31            return; // already initialized
32
33        if ( container.data('cycle-log') === false || 
34            ( options && options.log === false ) ||
35            ( opts && opts.log === false) ) {
36            log = $.noop;
37        }
38
39        log('--c2 init--');
40        data = container.data();
41        for (var p in data) {
42            // allow props to be accessed sans 'cycle' prefix and log the overrides
43            if (data.hasOwnProperty(p) && /^cycle[A-Z]+/.test(p) ) {
44                val = data[p];
45                shortName = p.match(/^cycle(.*)/)[1].replace(/^[A-Z]/, lowerCase);
46                log(shortName+':', val, '('+typeof val +')');
47                data[shortName] = val;
48            }
49        }
50
51        opts = $.extend( {}, $.fn.cycle.defaults, data, options || {});
52
53        opts.timeoutId = 0;
54        opts.paused = opts.paused || false; // #57
55        opts.container = container;
56        opts._maxZ = opts.maxZ;
57
58        opts.API = $.extend ( { _container: container }, $.fn.cycle.API );
59        opts.API.log = log;
60        opts.API.trigger = function( eventName, args ) {
61            opts.container.trigger( eventName, args );
62            return opts.API;
63        };
64
65        container.data( 'cycle.opts', opts );
66        container.data( 'cycle.API', opts.API );
67
68        // opportunity for plugins to modify opts and API
69        opts.API.trigger('cycle-bootstrap', [ opts, opts.API ]);
70
71        opts.API.addInitialSlides();
72        opts.API.preInitSlideshow();
73
74        if ( opts.slides.length )
75            opts.API.initSlideshow();
76    });
77};
78
79$.fn.cycle.API = {
80    opts: function() {
81        return this._container.data( 'cycle.opts' );
82    },
83    addInitialSlides: function() {
84        var opts = this.opts();
85        var slides = opts.slides;
86        opts.slideCount = 0;
87        opts.slides = $(); // empty set
88        
89        // add slides that already exist
90        slides = slides.jquery ? slides : opts.container.find( slides );
91
92        if ( opts.random ) {
93            slides.sort(function() {return Math.random() - 0.5;});
94        }
95
96        opts.API.add( slides );
97    },
98
99    preInitSlideshow: function() {
100        var opts = this.opts();
101        opts.API.trigger('cycle-pre-initialize', [ opts ]);
102        var tx = $.fn.cycle.transitions[opts.fx];
103        if (tx && $.isFunction(tx.preInit))
104            tx.preInit( opts );
105        opts._preInitialized = true;
106    },
107
108    postInitSlideshow: function() {
109        var opts = this.opts();
110        opts.API.trigger('cycle-post-initialize', [ opts ]);
111        var tx = $.fn.cycle.transitions[opts.fx];
112        if (tx && $.isFunction(tx.postInit))
113            tx.postInit( opts );
114    },
115
116    initSlideshow: function() {
117        var opts = this.opts();
118        var pauseObj = opts.container;
119        var slideOpts;
120        opts.API.calcFirstSlide();
121
122        if ( opts.container.css('position') == 'static' )
123            opts.container.css('position', 'relative');
124
125        $(opts.slides[opts.currSlide]).css({
126            opacity: 1,
127            display: 'block',
128            visibility: 'visible'
129        });
130        opts.API.stackSlides( opts.slides[opts.currSlide], opts.slides[opts.nextSlide], !opts.reverse );
131
132        if ( opts.pauseOnHover ) {
133            // allow pauseOnHover to specify an element
134            if ( opts.pauseOnHover !== true )
135                pauseObj = $( opts.pauseOnHover );
136
137            pauseObj.hover(
138                function(){ opts.API.pause( true ); }, 
139                function(){ opts.API.resume( true ); }
140            );
141        }
142
143        // stage initial transition
144        if ( opts.timeout ) {
145            slideOpts = opts.API.getSlideOpts( opts.currSlide );
146            opts.API.queueTransition( slideOpts, slideOpts.timeout + opts.delay );
147        }
148
149        opts._initialized = true;
150        opts.API.updateView( true );
151        opts.API.trigger('cycle-initialized', [ opts ]);
152        opts.API.postInitSlideshow();
153    },
154
155    pause: function( hover ) {
156        var opts = this.opts(),
157            slideOpts = opts.API.getSlideOpts(),
158            alreadyPaused = opts.hoverPaused || opts.paused;
159
160        if ( hover )
161            opts.hoverPaused = true; 
162        else
163            opts.paused = true;
164
165        if ( ! alreadyPaused ) {
166            opts.container.addClass('cycle-paused');
167            opts.API.trigger('cycle-paused', [ opts ]).log('cycle-paused');
168
169            if ( slideOpts.timeout ) {
170                clearTimeout( opts.timeoutId );
171                opts.timeoutId = 0;
172                
173                // determine how much time is left for the current slide
174                opts._remainingTimeout -= ( $.now() - opts._lastQueue );
175                if ( opts._remainingTimeout < 0 || isNaN(opts._remainingTimeout) )
176                    opts._remainingTimeout = undefined;
177            }
178        }
179    },
180
181    resume: function( hover ) {
182        var opts = this.opts(),
183            alreadyResumed = !opts.hoverPaused && !opts.paused,
184            remaining;
185
186        if ( hover )
187            opts.hoverPaused = false; 
188        else
189            opts.paused = false;
190
191    
192        if ( ! alreadyResumed ) {
193            opts.container.removeClass('cycle-paused');
194            // #gh-230; if an animation is in progress then don't queue a new transition; it will
195            // happen naturally
196            if ( opts.slides.filter(':animated').length === 0 )
197                opts.API.queueTransition( opts.API.getSlideOpts(), opts._remainingTimeout );
198            opts.API.trigger('cycle-resumed', [ opts, opts._remainingTimeout ] ).log('cycle-resumed');
199        }
200    },
201
202    add: function( slides, prepend ) {
203        var opts = this.opts();
204        var oldSlideCount = opts.slideCount;
205        var startSlideshow = false;
206        var len;
207
208        if ( $.type(slides) == 'string')
209            slides = $.trim( slides );
210
211        $( slides ).each(function(i) {
212            var slideOpts;
213            var slide = $(this);
214
215            if ( prepend )
216                opts.container.prepend( slide );
217            else
218                opts.container.append( slide );
219
220            opts.slideCount++;
221            slideOpts = opts.API.buildSlideOpts( slide );
222
223            if ( prepend )
224                opts.slides = $( slide ).add( opts.slides );
225            else
226                opts.slides = opts.slides.add( slide );
227
228            opts.API.initSlide( slideOpts, slide, --opts._maxZ );
229
230            slide.data('cycle.opts', slideOpts);
231            opts.API.trigger('cycle-slide-added', [ opts, slideOpts, slide ]);
232        });
233
234        opts.API.updateView( true );
235
236        startSlideshow = opts._preInitialized && (oldSlideCount < 2 && opts.slideCount >= 1);
237        if ( startSlideshow ) {
238            if ( !opts._initialized )
239                opts.API.initSlideshow();
240            else if ( opts.timeout ) {
241                len = opts.slides.length;
242                opts.nextSlide = opts.reverse ? len - 1 : 1;
243                if ( !opts.timeoutId ) {
244                    opts.API.queueTransition( opts );
245                }
246            }
247        }
248    },
249
250    calcFirstSlide: function() {
251        var opts = this.opts();
252        var firstSlideIndex;
253        firstSlideIndex = parseInt( opts.startingSlide || 0, 10 );
254        if (firstSlideIndex >= opts.slides.length || firstSlideIndex < 0)
255            firstSlideIndex = 0;
256
257        opts.currSlide = firstSlideIndex;
258        if ( opts.reverse ) {
259            opts.nextSlide = firstSlideIndex - 1;
260            if (opts.nextSlide < 0)
261                opts.nextSlide = opts.slides.length - 1;
262        }
263        else {
264            opts.nextSlide = firstSlideIndex + 1;
265            if (opts.nextSlide == opts.slides.length)
266                opts.nextSlide = 0;
267        }
268    },
269
270    calcNextSlide: function() {
271        var opts = this.opts();
272        var roll;
273        if ( opts.reverse ) {
274            roll = (opts.nextSlide - 1) < 0;
275            opts.nextSlide = roll ? opts.slideCount - 1 : opts.nextSlide-1;
276            opts.currSlide = roll ? 0 : opts.nextSlide+1;
277        }
278        else {
279            roll = (opts.nextSlide + 1) == opts.slides.length;
280            opts.nextSlide = roll ? 0 : opts.nextSlide+1;
281            opts.currSlide = roll ? opts.slides.length-1 : opts.nextSlide-1;
282        }
283    },
284
285    calcTx: function( slideOpts, manual ) {
286        var opts = slideOpts;
287        var tx;
288
289        if ( opts._tempFx )
290            tx = $.fn.cycle.transitions[opts._tempFx];
291        else if ( manual && opts.manualFx )
292            tx = $.fn.cycle.transitions[opts.manualFx];
293
294        if ( !tx )
295            tx = $.fn.cycle.transitions[opts.fx];
296
297        opts._tempFx = null;
298        this.opts()._tempFx = null;
299
300        if (!tx) {
301            tx = $.fn.cycle.transitions.fade;
302            opts.API.log('Transition "' + opts.fx + '" not found.  Using fade.');
303        }
304        return tx;
305    },
306
307    prepareTx: function( manual, fwd ) {
308        var opts = this.opts();
309        var after, curr, next, slideOpts, tx;
310
311        if ( opts.slideCount < 2 ) {
312            opts.timeoutId = 0;
313            return;
314        }
315        if ( manual && ( !opts.busy || opts.manualTrump ) ) {
316            opts.API.stopTransition();
317            opts.busy = false;
318            clearTimeout(opts.timeoutId);
319            opts.timeoutId = 0;
320        }
321        if ( opts.busy )
322            return;
323        if ( opts.timeoutId === 0 && !manual )
324            return;
325
326        curr = opts.slides[opts.currSlide];
327        next = opts.slides[opts.nextSlide];
328        slideOpts = opts.API.getSlideOpts( opts.nextSlide );
329        tx = opts.API.calcTx( slideOpts, manual );
330
331        opts._tx = tx;
332
333        if ( manual && slideOpts.manualSpeed !== undefined )
334            slideOpts.speed = slideOpts.manualSpeed;
335
336        // if ( opts.nextSlide === opts.currSlide )
337        //     opts.API.calcNextSlide();
338
339        // ensure that:
340        //      1. advancing to a different slide
341        //      2. this is either a manual event (prev/next, pager, cmd) or 
342        //              a timer event and slideshow is not paused
343        if ( opts.nextSlide != opts.currSlide && 
344            (manual || (!opts.paused && !opts.hoverPaused && opts.timeout) )) { // #62
345
346            opts.API.trigger('cycle-before', [ slideOpts, curr, next, fwd ]);
347            if ( tx.before )
348                tx.before( slideOpts, curr, next, fwd );
349
350            after = function() {
351                opts.busy = false;
352                // #76; bail if slideshow has been destroyed
353                if (! opts.container.data( 'cycle.opts' ) )
354                    return;
355
356                if (tx.after)
357                    tx.after( slideOpts, curr, next, fwd );
358                opts.API.trigger('cycle-after', [ slideOpts, curr, next, fwd ]);
359                opts.API.queueTransition( slideOpts);
360                opts.API.updateView( true );
361            };
362
363            opts.busy = true;
364            if (tx.transition)
365                tx.transition(slideOpts, curr, next, fwd, after);
366            else
367                opts.API.doTransition( slideOpts, curr, next, fwd, after);
368
369            opts.API.calcNextSlide();
370            opts.API.updateView();
371        } else {
372            opts.API.queueTransition( slideOpts );
373        }
374    },
375
376    // perform the actual animation
377    doTransition: function( slideOpts, currEl, nextEl, fwd, callback) {
378        var opts = slideOpts;
379        var curr = $(currEl), next = $(nextEl);
380        var fn = function() {
381            // make sure animIn has something so that callback doesn't trigger immediately
382            next.animate(opts.animIn || { opacity: 1}, opts.speed, opts.easeIn || opts.easing, callback);
383        };
384
385        next.css(opts.cssBefore || {});
386        curr.animate(opts.animOut || {}, opts.speed, opts.easeOut || opts.easing, function() {
387            curr.css(opts.cssAfter || {});
388            if (!opts.sync) {
389                fn();
390            }
391        });
392        if (opts.sync) {
393            fn();
394        }
395    },
396
397    queueTransition: function( slideOpts, specificTimeout ) {
398        var opts = this.opts();
399        var timeout = specificTimeout !== undefined ? specificTimeout : slideOpts.timeout;
400        if (opts.nextSlide === 0 && --opts.loop === 0) {
401            opts.API.log('terminating; loop=0');
402            opts.timeout = 0;
403            if ( timeout ) {
404                setTimeout(function() {
405                    opts.API.trigger('cycle-finished', [ opts ]);
406                }, timeout);
407            }
408            else {
409                opts.API.trigger('cycle-finished', [ opts ]);
410            }
411            // reset nextSlide
412            opts.nextSlide = opts.currSlide;
413            return;
414        }
415        if ( opts.continueAuto !== undefined ) {
416            if ( opts.continueAuto === false || 
417                ($.isFunction(opts.continueAuto) && opts.continueAuto() === false )) {
418                opts.API.log('terminating automatic transitions');
419                opts.timeout = 0;
420                if ( opts.timeoutId )
421                    clearTimeout(opts.timeoutId);
422                return;
423            }
424        }
425        if ( timeout ) {
426            opts._lastQueue = $.now();
427            if ( specificTimeout === undefined )
428                opts._remainingTimeout = slideOpts.timeout;
429
430            if ( !opts.paused && ! opts.hoverPaused ) {
431                opts.timeoutId = setTimeout(function() { 
432                    opts.API.prepareTx( false, !opts.reverse ); 
433                }, timeout );
434            }
435        }
436    },
437
438    stopTransition: function() {
439        var opts = this.opts();
440        if ( opts.slides.filter(':animated').length ) {
441            opts.slides.stop(false, true);
442            opts.API.trigger('cycle-transition-stopped', [ opts ]);
443        }
444
445        if ( opts._tx && opts._tx.stopTransition )
446            opts._tx.stopTransition( opts );
447    },
448
449    // advance slide forward or back
450    advanceSlide: function( val ) {
451        var opts = this.opts();
452        clearTimeout(opts.timeoutId);
453        opts.timeoutId = 0;
454        opts.nextSlide = opts.currSlide + val;
455        
456        if (opts.nextSlide < 0)
457            opts.nextSlide = opts.slides.length - 1;
458        else if (opts.nextSlide >= opts.slides.length)
459            opts.nextSlide = 0;
460
461        opts.API.prepareTx( true,  val >= 0 );
462        return false;
463    },
464
465    buildSlideOpts: function( slide ) {
466        var opts = this.opts();
467        var val, shortName;
468        var slideOpts = slide.data() || {};
469        for (var p in slideOpts) {
470            // allow props to be accessed sans 'cycle' prefix and log the overrides
471            if (slideOpts.hasOwnProperty(p) && /^cycle[A-Z]+/.test(p) ) {
472                val = slideOpts[p];
473                shortName = p.match(/^cycle(.*)/)[1].replace(/^[A-Z]/, lowerCase);
474                opts.API.log('['+(opts.slideCount-1)+']', shortName+':', val, '('+typeof val +')');
475                slideOpts[shortName] = val;
476            }
477        }
478
479        slideOpts = $.extend( {}, $.fn.cycle.defaults, opts, slideOpts );
480        slideOpts.slideNum = opts.slideCount;
481
482        try {
483            // these props should always be read from the master state object
484            delete slideOpts.API;
485            delete slideOpts.slideCount;
486            delete slideOpts.currSlide;
487            delete slideOpts.nextSlide;
488            delete slideOpts.slides;
489        } catch(e) {
490            // no op
491        }
492        return slideOpts;
493    },
494
495    getSlideOpts: function( index ) {
496        var opts = this.opts();
497        if ( index === undefined )
498            index = opts.currSlide;
499
500        var slide = opts.slides[index];
501        var slideOpts = $(slide).data('cycle.opts');
502        return $.extend( {}, opts, slideOpts );
503    },
504    
505    initSlide: function( slideOpts, slide, suggestedZindex ) {
506        var opts = this.opts();
507        slide.css( slideOpts.slideCss || {} );
508        if ( suggestedZindex > 0 )
509            slide.css( 'zIndex', suggestedZindex );
510
511        // ensure that speed settings are sane
512        if ( isNaN( slideOpts.speed ) )
513            slideOpts.speed = $.fx.speeds[slideOpts.speed] || $.fx.speeds._default;
514        if ( !slideOpts.sync )
515            slideOpts.speed = slideOpts.speed / 2;
516
517        slide.addClass( opts.slideClass );
518    },
519
520    updateView: function( isAfter, isDuring, forceEvent ) {
521        var opts = this.opts();
522        if ( !opts._initialized )
523            return;
524        var slideOpts = opts.API.getSlideOpts();
525        var currSlide = opts.slides[ opts.currSlide ];
526
527        if ( ! isAfter && isDuring !== true ) {
528            opts.API.trigger('cycle-update-view-before', [ opts, slideOpts, currSlide ]);
529            if ( opts.updateView < 0 )
530                return;
531        }
532
533        if ( opts.slideActiveClass ) {
534            opts.slides.removeClass( opts.slideActiveClass )
535                .eq( opts.currSlide ).addClass( opts.slideActiveClass );
536        }
537
538        if ( isAfter && opts.hideNonActive )
539            opts.slides.filter( ':not(.' + opts.slideActiveClass + ')' ).css('visibility', 'hidden');
540
541        if ( opts.updateView === 0 ) {
542            setTimeout(function() {
543                opts.API.trigger('cycle-update-view', [ opts, slideOpts, currSlide, isAfter ]);
544            }, slideOpts.speed / (opts.sync ? 2 : 1) );
545        }
546
547        if ( opts.updateView !== 0 )
548            opts.API.trigger('cycle-update-view', [ opts, slideOpts, currSlide, isAfter ]);
549        
550        if ( isAfter )
551            opts.API.trigger('cycle-update-view-after', [ opts, slideOpts, currSlide ]);
552    },
553
554    getComponent: function( name ) {
555        var opts = this.opts();
556        var selector = opts[name];
557        if (typeof selector === 'string') {
558            // if selector is a child, sibling combinator, adjancent selector then use find, otherwise query full dom
559            return (/^\s*[\>|\+|~]/).test( selector ) ? opts.container.find( selector ) : $( selector );
560        }
561        if (selector.jquery)
562            return selector;
563        
564        return $(selector);
565    },
566
567    stackSlides: function( curr, next, fwd ) {
568        var opts = this.opts();
569        if ( !curr ) {
570            curr = opts.slides[opts.currSlide];
571            next = opts.slides[opts.nextSlide];
572            fwd = !opts.reverse;
573        }
574
575        // reset the zIndex for the common case:
576        // curr slide on top,  next slide beneath, and the rest in order to be shown
577        $(curr).css('zIndex', opts.maxZ);
578
579        var i;
580        var z = opts.maxZ - 2;
581        var len = opts.slideCount;
582        if (fwd) {
583            for ( i = opts.currSlide + 1; i < len; i++ )
584                $( opts.slides[i] ).css( 'zIndex', z-- );
585            for ( i = 0; i < opts.currSlide; i++ )
586                $( opts.slides[i] ).css( 'zIndex', z-- );
587        }
588        else {
589            for ( i = opts.currSlide - 1; i >= 0; i-- )
590                $( opts.slides[i] ).css( 'zIndex', z-- );
591            for ( i = len - 1; i > opts.currSlide; i-- )
592                $( opts.slides[i] ).css( 'zIndex', z-- );
593        }
594
595        $(next).css('zIndex', opts.maxZ - 1);
596    },
597
598    getSlideIndex: function( el ) {
599        return this.opts().slides.index( el );
600    }
601
602}; // API
603
604// default logger
605$.fn.cycle.log = function log() {
606    /*global console:true */
607    // if (window.console && console.log)
608    //     console.log('[cycle2] ' + Array.prototype.join.call(arguments, ' ') );
609};
610
611$.fn.cycle.version = function() { return 'Cycle2: ' + version; };
612
613// helper functions
614
615function lowerCase(s) {
616    return (s || '').toLowerCase();
617}
618
619// expose transition object
620$.fn.cycle.transitions = {
621    custom: {
622    },
623    none: {
624        before: function( opts, curr, next, fwd ) {
625            opts.API.stackSlides( next, curr, fwd );
626            opts.cssBefore = { opacity: 1, visibility: 'visible', display: 'block' };
627        }
628    },
629    fade: {
630        before: function( opts, curr, next, fwd ) {
631            var css = opts.API.getSlideOpts( opts.nextSlide ).slideCss || {};
632            opts.API.stackSlides( curr, next, fwd );
633            opts.cssBefore = $.extend(css, { opacity: 0, visibility: 'visible', display: 'block' });
634            opts.animIn = { opacity: 1 };
635            opts.animOut = { opacity: 0 };
636        }
637    },
638    fadeout: {
639        before: function( opts , curr, next, fwd ) {
640            var css = opts.API.getSlideOpts( opts.nextSlide ).slideCss || {};
641            opts.API.stackSlides( curr, next, fwd );
642            opts.cssBefore = $.extend(css, { opacity: 1, visibility: 'visible', display: 'block' });
643            opts.animOut = { opacity: 0 };
644        }
645    },
646    scrollHorz: {
647        before: function( opts, curr, next, fwd ) {
648            opts.API.stackSlides( curr, next, fwd );
649            var w = opts.container.css('overflow','hidden').width();
650            opts.cssBefore = { left: fwd ? w : - w, top: 0, opacity: 1, visibility: 'visible', display: 'block' };
651            opts.cssAfter = { zIndex: opts._maxZ - 2, left: 0 };
652            opts.animIn = { left: 0 };
653            opts.animOut = { left: fwd ? -w : w };
654        }
655    }
656};
657
658// @see: http://jquery.malsup.com/cycle2/api
659$.fn.cycle.defaults = {
660    allowWrap:        true,
661    autoSelector:     '.cycle-slideshow[data-cycle-auto-init!=false]',
662    delay:            0,
663    easing:           null,
664    fx:              'fade',
665    hideNonActive:    true,
666    loop:             0,
667    manualFx:         undefined,
668    manualSpeed:      undefined,
669    manualTrump:      true,
670    maxZ:             100,
671    pauseOnHover:     false,
672    reverse:          false,
673    slideActiveClass: 'cycle-slide-active',
674    slideClass:       'cycle-slide',
675    slideCss:         { position: 'absolute', top: 0, left: 0 },
676    slides:          '> img',
677    speed:            500,
678    startingSlide:    0,
679    sync:             true,
680    timeout:          4000,
681    updateView:       0
682};
683
684// automatically find and run slideshows
685$(document).ready(function() {
686    $( $.fn.cycle.defaults.autoSelector ).cycle();
687});
688
689})(jQuery);
690
691/*! Cycle2 autoheight plugin; Copyright (c) M.Alsup, 2012; version: 20130913 */
692(function($) {
693"use strict";
694
695$.extend($.fn.cycle.defaults, {
696    autoHeight: 0, // setting this option to false disables autoHeight logic
697    autoHeightSpeed: 250,
698    autoHeightEasing: null
699});    
700
701$(document).on( 'cycle-initialized', function( e, opts ) {
702    var autoHeight = opts.autoHeight;
703    var t = $.type( autoHeight );
704    var resizeThrottle = null;
705    var ratio;
706
707    if ( t !== 'string' && t !== 'number' )
708        return;
709
710    // bind events
711    opts.container.on( 'cycle-slide-added cycle-slide-removed', initAutoHeight );
712    opts.container.on( 'cycle-destroyed', onDestroy );
713
714    if ( autoHeight == 'container' ) {
715        opts.container.on( 'cycle-before', onBefore );
716    }
717    else if ( t === 'string' && /\d+\:\d+/.test( autoHeight ) ) { 
718        // use ratio
719        ratio = autoHeight.match(/(\d+)\:(\d+)/);
720        ratio = ratio[1] / ratio[2];
721        opts._autoHeightRatio = ratio;
722    }
723
724    // if autoHeight is a number then we don't need to recalculate the sentinel
725    // index on resize
726    if ( t !== 'number' ) {
727        // bind unique resize handler per slideshow (so it can be 'off-ed' in onDestroy)
728        opts._autoHeightOnResize = function () {
729            clearTimeout( resizeThrottle );
730            resizeThrottle = setTimeout( onResize, 50 );
731        };
732
733        $(window).on( 'resize orientationchange', opts._autoHeightOnResize );
734    }
735
736    setTimeout( onResize, 30 );
737
738    function onResize() {
739        initAutoHeight( e, opts );
740    }
741});
742
743function initAutoHeight( e, opts ) {
744    var clone, height, sentinelIndex;
745    var autoHeight = opts.autoHeight;
746
747    if ( autoHeight == 'container' ) {
748        height = $( opts.slides[ opts.currSlide ] ).outerHeight();
749        opts.container.height( height );
750    }
751    else if ( opts._autoHeightRatio ) { 
752        opts.container.height( opts.container.width() / opts._autoHeightRatio );
753    }
754    else if ( autoHeight === 'calc' || ( $.type( autoHeight ) == 'number' && autoHeight >= 0 ) ) {
755        if ( autoHeight === 'calc' )
756            sentinelIndex = calcSentinelIndex( e, opts );
757        else if ( autoHeight >= opts.slides.length )
758            sentinelIndex = 0;
759        else 
760            sentinelIndex = autoHeight;
761
762        // only recreate sentinel if index is different
763        if ( sentinelIndex == opts._sentinelIndex )
764            return;
765
766        opts._sentinelIndex = sentinelIndex;
767        if ( opts._sentinel )
768            opts._sentinel.remove();
769
770        // clone existing slide as sentinel
771        clone = $( opts.slides[ sentinelIndex ].cloneNode(true) );
772        
773        // #50; remove special attributes from cloned content
774        clone.removeAttr( 'id name rel' ).find( '[id],[name],[rel]' ).removeAttr( 'id name rel' );
775
776        clone.css({
777            position: 'static',
778            visibility: 'hidden',
779            display: 'block'
780        }).prependTo( opts.container ).addClass('cycle-sentinel cycle-slide').removeClass('cycle-slide-active');
781        clone.find( '*' ).css( 'visibility', 'hidden' );
782
783        opts._sentinel = clone;
784    }
785}    
786
787function calcSentinelIndex( e, opts ) {
788    var index = 0, max = -1;
789
790    // calculate tallest slide index
791    opts.slides.each(function(i) {
792        var h = $(this).height();
793        if ( h > max ) {
794            max = h;
795            index = i;
796        }
797    });
798    return index;
799}
800
801function onBefore( e, opts, outgoing, incoming, forward ) {
802    var h = $(incoming).outerHeight();
803    opts.container.animate( { height: h }, opts.autoHeightSpeed, opts.autoHeightEasing );
804}
805
806function onDestroy( e, opts ) {
807    if ( opts._autoHeightOnResize ) {
808        $(window).off( 'resize orientationchange', opts._autoHeightOnResize );
809        opts._autoHeightOnResize = null;
810    }
811    opts.container.off( 'cycle-slide-added cycle-slide-removed', initAutoHeight );
812    opts.container.off( 'cycle-destroyed', onDestroy );
813    opts.container.off( 'cycle-before', onBefore );
814
815    if ( opts._sentinel ) {
816        opts._sentinel.remove();
817        opts._sentinel = null;
818    }
819}
820
821})(jQuery);
822
823/*! caption plugin for Cycle2;  version: 20130306 */
824(function($) {
825"use strict";
826
827$.extend($.fn.cycle.defaults, {
828    caption:          '> .cycle-caption',
829    captionTemplate:  '{{slideNum}} / {{slideCount}}',
830    overlay:          '> .cycle-overlay',
831    overlayTemplate:  '<div>{{title}}</div><div>{{desc}}</div>',
832    captionModule:    'caption'
833});    
834
835$(document).on( 'cycle-update-view', function( e, opts, slideOpts, currSlide ) {
836    if ( opts.captionModule !== 'caption' )
837        return;
838    var el;
839    $.each(['caption','overlay'], function() {
840        var name = this; 
841        var template = slideOpts[name+'Template'];
842        var el = opts.API.getComponent( name );
843        if( el.length && template ) {
844            el.html( opts.API.tmpl( template, slideOpts, opts, currSlide ) );
845            el.show();
846        }
847        else {
848            el.hide();
849        }
850    });
851});
852
853$(document).on( 'cycle-destroyed', function( e, opts ) {
854    var el;
855    $.each(['caption','overlay'], function() {
856        var name = this, template = opts[name+'Template'];
857        if ( opts[name] && template ) {
858            el = opts.API.getComponent( 'caption' );
859            el.empty();
860        }
861    });
862});
863
864})(jQuery);
865
866/*! command plugin for Cycle2;  version: 20140415 */
867(function($) {
868"use strict";
869
870var c2 = $.fn.cycle;
871
872$.fn.cycle = function( options ) {
873    var cmd, cmdFn, opts;
874    var args = $.makeArray( arguments );
875
876    if ( $.type( options ) == 'number' ) {
877        return this.cycle( 'goto', options );
878    }
879
880    if ( $.type( options ) == 'string' ) {
881        return this.each(function() {
882            var cmdArgs;
883            cmd = options;
884            opts = $(this).data('cycle.opts');
885
886            if ( opts === undefined ) {
887                c2.log('slideshow must be initialized before sending commands; "' + cmd + '" ignored');
888                return;
889            }
890            else {
891                cmd = cmd == 'goto' ? 'jump' : cmd; // issue #3; change 'goto' to 'jump' internally
892                cmdFn = opts.API[ cmd ];
893                if ( $.isFunction( cmdFn )) {
894                    cmdArgs = $.makeArray( args );
895                    cmdArgs.shift();
896                    return cmdFn.apply( opts.API, cmdArgs );
897                }
898                else {
899                    c2.log( 'unknown command: ', cmd );
900                }
901            }
902        });
903    }
904    else {
905        return c2.apply( this, arguments );
906    }
907};
908
909// copy props
910$.extend( $.fn.cycle, c2 );
911
912$.extend( c2.API, {
913    next: function() {
914        var opts = this.opts();
915        if ( opts.busy && ! opts.manualTrump )
916            return;
917
918        var count = opts.reverse ? -1 : 1;
919        if ( opts.allowWrap === false && ( opts.currSlide + count ) >= opts.slideCount )
920            return;
921
922        opts.API.advanceSlide( count );
923        opts.API.trigger('cycle-next', [ opts ]).log('cycle-next');
924    },
925
926    prev: function() {
927        var opts = this.opts();
928        if ( opts.busy && ! opts.manualTrump )
929            return;
930        var count = opts.reverse ? 1 : -1;
931        if ( opts.allowWrap === false && ( opts.currSlide + count ) < 0 )
932            return;
933
934        opts.API.advanceSlide( count );
935        opts.API.trigger('cycle-prev', [ opts ]).log('cycle-prev');
936    },
937
938    destroy: function() {
939        this.stop(); //#204
940
941        var opts = this.opts();
942        var clean = $.isFunction( $._data ) ? $._data : $.noop;  // hack for #184 and #201
943        clearTimeout(opts.timeoutId);
944        opts.timeoutId = 0;
945        opts.API.stop();
946        opts.API.trigger( 'cycle-destroyed', [ opts ] ).log('cycle-destroyed');
947        opts.container.removeData();
948        clean( opts.container[0], 'parsedAttrs', false );
949
950        // #75; remove inline styles
951        if ( ! opts.retainStylesOnDestroy ) {
952            opts.container.removeAttr( 'style' );
953            opts.slides.removeAttr( 'style' );
954            opts.slides.removeClass( opts.slideActiveClass );
955        }
956        opts.slides.each(function() {
957            var slide = $(this);
958            slide.removeData();
959            slide.removeClass( opts.slideClass );
960            clean( this, 'parsedAttrs', false );
961        });
962    },
963
964    jump: function( index, fx ) {
965        // go to the requested slide
966        var fwd;
967        var opts = this.opts();
968        if ( opts.busy && ! opts.manualTrump )
969            return;
970        var num = parseInt( index, 10 );
971        if (isNaN(num) || num < 0 || num >= opts.slides.length) {
972            opts.API.log('goto: invalid slide index: ' + num);
973            return;
974        }
975        if (num == opts.currSlide) {
976            opts.API.log('goto: skipping, already on slide', num);
977            return;
978        }
979        opts.nextSlide = num;
980        clearTimeout(opts.timeoutId);
981        opts.timeoutId = 0;
982        opts.API.log('goto: ', num, ' (zero-index)');
983        fwd = opts.currSlide < opts.nextSlide;
984        opts._tempFx = fx;
985        opts.API.prepareTx( true, fwd );
986    },
987
988    stop: function() {
989        var opts = this.opts();
990        var pauseObj = opts.container;
991        clearTimeout(opts.timeoutId);
992        opts.timeoutId = 0;
993        opts.API.stopTransition();
994        if ( opts.pauseOnHover ) {
995            if ( opts.pauseOnHover !== true )
996                pauseObj = $( opts.pauseOnHover );
997            pauseObj.off('mouseenter mouseleave');
998        }
999        opts.API.trigger('cycle-stopped', [ opts ]).log('cycle-stopped');
1000    },
1001
1002    reinit: function() {
1003        var opts = this.opts();
1004        opts.API.destroy();
1005        opts.container.cycle();
1006    },
1007
1008    remove: function( index ) {
1009        var opts = this.opts();
1010        var slide, slideToRemove, slides = [], slideNum = 1;
1011        for ( var i=0; i < opts.slides.length; i++ ) {
1012            slide = opts.slides[i];
1013            if ( i == index ) {
1014                slideToRemove = slide;
1015            }
1016            else {
1017                slides.push( slide );
1018                $( slide ).data('cycle.opts').slideNum = slideNum;
1019                slideNum++;
1020            }
1021        }
1022        if ( slideToRemove ) {
1023            opts.slides = $( slides );
1024            opts.slideCount--;
1025            $( slideToRemove ).remove();
1026            if (index == opts.currSlide)
1027                opts.API.advanceSlide( 1 );
1028            else if ( index < opts.currSlide )
1029                opts.currSlide--;
1030            else
1031                opts.currSlide++;
1032
1033            opts.API.trigger('cycle-slide-removed', [ opts, index, slideToRemove ]).log('cycle-slide-removed');
1034            opts.API.updateView();
1035        }
1036    }
1037
1038});
1039
1040// listen for clicks on elements with data-cycle-cmd attribute
1041$(document).on('click.cycle', '[data-cycle-cmd]', function(e) {
1042    // issue cycle command
1043    e.preventDefault();
1044    var el = $(this);
1045    var command = el.data('cycle-cmd');
1046    var context = el.data('cycle-context') || '.cycle-slideshow';
1047    $(context).cycle(command, el.data('cycle-arg'));
1048});})(jQuery);
1049
1050/*! hash plugin for Cycle2;  version: 20130905 */
1051(function($) {
1052"use strict";
1053
1054$(document).on( 'cycle-pre-initialize', function( e, opts ) {
1055    onHashChange( opts, true );
1056
1057    opts._onHashChange = function() {
1058        onHashChange( opts, false );
1059    };
1060
1061    $( window ).on( 'hashchange', opts._onHashChange);
1062});
1063
1064$(document).on( 'cycle-update-view', function( e, opts, slideOpts ) {
1065    if ( slideOpts.hash && ( '#' + slideOpts.hash ) != window.location.hash ) {
1066        opts._hashFence = true;
1067        window.location.hash = slideOpts.hash;
1068    }
1069});
1070
1071$(document).on( 'cycle-destroyed', function( e, opts) {
1072    if ( opts._onHashChange ) {
1073        $( window ).off( 'hashchange', opts._onHashChange );
1074    }
1075});
1076
1077function onHashChange( opts, setStartingSlide ) {
1078    var hash;
1079    if ( opts._hashFence ) {
1080        opts._hashFence = false;
1081        return;
1082    }
1083    
1084    hash = window.location.hash.substring(1);
1085
1086    opts.slides.each(function(i) {
1087        if ( $(this).data( 'cycle-hash' ) == hash ) {
1088            if ( setStartingSlide === true ) {
1089                opts.startingSlide = i;
1090            }
1091            else {
1092                var fwd = opts.currSlide < i;
1093                opts.nextSlide = i;
1094                opts.API.prepareTx( true, fwd );
1095            }
1096            return false;
1097        }
1098    });
1099}
1100
1101})(jQuery);
1102
1103/*! loader plugin for Cycle2;  version: 20131121 */
1104(function($) {
1105"use strict";
1106
1107$.extend($.fn.cycle.defaults, {
1108    loader: false
1109});
1110
1111$(document).on( 'cycle-bootstrap', function( e, opts ) {
1112    var addFn;
1113
1114    if ( !opts.loader )
1115        return;
1116
1117    // override API.add for this slideshow
1118    addFn = opts.API.add;
1119    opts.API.add = add;
1120
1121    function add( slides, prepend ) {
1122        var slideArr = [];
1123        if ( $.type( slides ) == 'string' )
1124            slides = $.trim( slides );
1125        else if ( $.type( slides) === 'array' ) {
1126            for (var i=0; i < slides.length; i++ )
1127                slides[i] = $(slides[i])[0];
1128        }
1129
1130        slides = $( slides );
1131        var slideCount = slides.length;
1132
1133        if ( ! slideCount )
1134            return;
1135
1136        slides.css('visibility','hidden').appendTo('body').each(function(i) { // appendTo fixes #56
1137            var count = 0;
1138            var slide = $(this);
1139            var images = slide.is('img') ? slide : slide.find('img');
1140            slide.data('index', i);
1141            // allow some images to be marked as unimportant (and filter out images w/o src value)
1142            images = images.filter(':not(.cycle-loader-ignore)').filter(':not([src=""])');
1143            if ( ! images.length ) {
1144                --slideCount;
1145                slideArr.push( slide );
1146                return;
1147            }
1148
1149            count = images.length;
1150            images.each(function() {
1151                // add images that are already loaded
1152                if ( this.complete ) {
1153                    imageLoaded();
1154                }
1155                else {
1156                    $(this).load(function() {
1157                        imageLoaded();
1158                    }).on("error", function() {
1159                        if ( --count === 0 ) {
1160                            // ignore this slide
1161                            opts.API.log('slide skipped; img not loaded:', this.src);
1162                            if ( --slideCount === 0 && opts.loader == 'wait') {
1163                                addFn.apply( opts.API, [ slideArr, prepend ] );
1164                            }
1165                        }
1166                    });
1167                }
1168            });
1169
1170            function imageLoaded() {
1171                if ( --count === 0 ) {
1172                    --slideCount;
1173                    addSlide( slide );
1174                }
1175            }
1176        });
1177
1178        if ( slideCount )
1179            opts.container.addClass('cycle-loading');
1180        
1181
1182        function addSlide( slide ) {
1183            var curr;
1184            if ( opts.loader == 'wait' ) {
1185                slideArr.push( slide );
1186                if ( slideCount === 0 ) {
1187                    // #59; sort slides into original markup order
1188                    slideArr.sort( sorter );
1189                    addFn.apply( opts.API, [ slideArr, prepend ] );
1190                    opts.container.removeClass('cycle-loading');
1191                }
1192            }
1193            else {
1194                curr = $(opts.slides[opts.currSlide]);
1195                addFn.apply( opts.API, [ slide, prepend ] );
1196                curr.show();
1197                opts.container.removeClass('cycle-loading');
1198            }
1199        }
1200
1201        function sorter(a, b) {
1202            return a.data('index') - b.data('index');
1203        }
1204    }
1205});
1206
1207})(jQuery);
1208
1209/*! pager plugin for Cycle2;  version: 20140415 */
1210(function($) {
1211"use strict";
1212
1213$.extend($.fn.cycle.defaults, {
1214    pager:            '> .cycle-pager',
1215    pagerActiveClass: 'cycle-pager-active',
1216    pagerEvent:       'click.cycle',
1217    pagerEventBubble: undefined,
1218    pagerTemplate:    '<span>&bull;</span>'
1219});
1220
1221$(document).on( 'cycle-bootstrap', function( e, opts, API ) {
1222    // add method to API
1223    API.buildPagerLink = buildPagerLink;
1224});
1225
1226$(document).on( 'cycle-slide-added', function( e, opts, slideOpts, slideAdded ) {
1227    if ( opts.pager ) {
1228        opts.API.buildPagerLink ( opts, slideOpts, slideAdded );
1229        opts.API.page = page;
1230    }
1231});
1232
1233$(document).on( 'cycle-slide-removed', function( e, opts, index, slideRemoved ) {
1234    if ( opts.pager ) {
1235        var pagers = opts.API.getComponent( 'pager' );
1236        pagers.each(function() {
1237            var pager = $(this);
1238            $( pager.children()[index] ).remove();
1239        });
1240    }
1241});
1242
1243$(document).on( 'cycle-update-view', function( e, opts, slideOpts ) {
1244    var pagers;
1245
1246    if ( opts.pager ) {
1247        pagers = opts.API.getComponent( 'pager' );
1248        pagers.each(function() {
1249           $(this).children().removeClass( opts.pagerActiveClass )
1250            .eq( opts.currSlide ).addClass( opts.pagerActiveClass );
1251        });
1252    }
1253});
1254
1255$(document).on( 'cycle-destroyed', function( e, opts ) {
1256    var pager = opts.API.getComponent( 'pager' );
1257
1258    if ( pager ) {
1259        pager.children().off( opts.pagerEvent ); // #202
1260        if ( opts.pagerTemplate )
1261            pager.empty();
1262    }
1263});
1264
1265function buildPagerLink( opts, slideOpts, slide ) {
1266    var pagerLink;
1267    var pagers = opts.API.getComponent( 'pager' );
1268    pagers.each(function() {
1269        var pager = $(this);
1270        if ( slideOpts.pagerTemplate ) {
1271            var markup = opts.API.tmpl( slideOpts.pagerTemplate, slideOpts, opts, slide[0] );
1272            pagerLink = $( markup ).appendTo( pager );
1273        }
1274        else {
1275            pagerLink = pager.children().eq( opts.slideCount - 1 );
1276        }
1277        pagerLink.on( opts.pagerEvent, function(e) {
1278            if ( ! opts.pagerEventBubble )
1279                e.preventDefault();
1280            opts.API.page( pager, e.currentTarget);
1281        });
1282    });
1283}
1284
1285function page( pager, target ) {
1286    /*jshint validthis:true */
1287    var opts = this.opts();
1288    if ( opts.busy && ! opts.manualTrump )
1289        return;
1290
1291    var index = pager.children().index( target );
1292    var nextSlide = index;
1293    var fwd = opts.currSlide < nextSlide;
1294    if (opts.currSlide == nextSlide) {
1295        return; // no op, clicked pager for the currently displayed slide
1296    }
1297    opts.nextSlide = nextSlide;
1298    opts._tempFx = opts.pagerFx;
1299    opts.API.prepareTx( true, fwd );
1300    opts.API.trigger('cycle-pager-activated', [opts, pager, target ]);
1301}
1302
1303})(jQuery);
1304
1305/*! prevnext plugin for Cycle2;  version: 20140408 */
1306(function($) {
1307"use strict";
1308
1309$.extend($.fn.cycle.defaults, {
1310    next:           '> .cycle-next',
1311    nextEvent:      'click.cycle',
1312    disabledClass:  'disabled',
1313    prev:           '> .cycle-prev',
1314    prevEvent:      'click.cycle',
1315    swipe:          false
1316});
1317
1318$(document).on( 'cycle-initialized', function( e, opts ) {
1319    opts.API.getComponent( 'next' ).on( opts.nextEvent, function(e) {
1320        e.preventDefault();
1321        opts.API.next();
1322    });
1323
1324    opts.API.getComponent( 'prev' ).on( opts.prevEvent, function(e) {
1325        e.preventDefault();
1326        opts.API.prev();
1327    });
1328
1329    if ( opts.swipe ) {
1330        var nextEvent = opts.swipeVert ? 'swipeUp.cycle' : 'swipeLeft.cycle swipeleft.cycle';
1331        var prevEvent = opts.swipeVert ? 'swipeDown.cycle' : 'swipeRight.cycle swiperight.cycle';
1332        opts.container.on( nextEvent, function(e) {
1333            opts._tempFx = opts.swipeFx;
1334            opts.API.next();
1335        });
1336        opts.container.on( prevEvent, function() {
1337            opts._tempFx = opts.swipeFx;
1338            opts.API.prev();
1339        });
1340    }
1341});
1342
1343$(document).on( 'cycle-update-view', function( e, opts, slideOpts, currSlide ) {
1344    if ( opts.allowWrap )
1345        return;
1346
1347    var cls = opts.disabledClass;
1348    var next = opts.API.getComponent( 'next' );
1349    var prev = opts.API.getComponent( 'prev' );
1350    var prevBoundry = opts._prevBoundry || 0;
1351    var nextBoundry = (opts._nextBoundry !== undefined)?opts._nextBoundry:opts.slideCount - 1;
1352
1353    if ( opts.currSlide == nextBoundry )
1354        next.addClass( cls ).prop( 'disabled', true );
1355    else
1356        next.removeClass( cls ).prop( 'disabled', false );
1357
1358    if ( opts.currSlide === prevBoundry )
1359        prev.addClass( cls ).prop( 'disabled', true );
1360    else
1361        prev.removeClass( cls ).prop( 'disabled', false );
1362});$(document).on( 'cycle-destroyed', function( e, opts ) {
1363    opts.API.getComponent( 'prev' ).off( opts.nextEvent );
1364    opts.API.getComponent( 'next' ).off( opts.prevEvent );
1365    opts.container.off( 'swipeleft.cycle swiperight.cycle swipeLeft.cycle swipeRight.cycle swipeUp.cycle swipeDown.cycle' );
1366});
1367
1368})(jQuery);
1369
1370/*! progressive loader plugin for Cycle2;  version: 20130315 */
1371(function($) {
1372"use strict";
1373
1374$.extend($.fn.cycle.defaults, {
1375    progressive: false
1376});
1377
1378$(document).on( 'cycle-pre-initialize', function( e, opts ) {
1379    if ( !opts.progressive )
1380        return;
1381
1382    var API = opts.API;
1383    var nextFn = API.next;
1384    var prevFn = API.prev;
1385    var prepareTxFn = API.prepareTx;
1386    var type = $.type( opts.progressive );
1387    var slides, scriptEl;
1388
1389    if ( type == 'array' ) {
1390        slides = opts.progressive;
1391    }
1392    else if ($.isFunction( opts.progressive ) ) {
1393        slides = opts.progressive( opts );
1394    }
1395    else if ( type == 'string' ) {
1396        scriptEl = $( opts.progressive );
1397        slides = $.trim( scriptEl.html() );
1398        if ( !slides )
1399            return;
1400        // is it json array?
1401        if ( /^(\[)/.test( slides ) ) {
1402            try {
1403                slides = $.parseJSON( slides );
1404            }
1405            catch(err) {
1406                API.log( 'error parsing progressive slides', err );
1407                return;
1408            }
1409        }
1410        else {
1411            // plain text, split on delimeter
1412            slides = slides.split( new RegExp( scriptEl.data('cycle-split') || '\n') );
1413            
1414            // #95; look for empty slide
1415            if ( ! slides[ slides.length - 1 ] )
1416                slides.pop();
1417        }
1418    }
1419    if ( prepareTxFn ) {
1420        API.prepareTx = function( manual, fwd ) {
1421            var index, slide;
1422
1423            if ( manual || slides.length === 0 ) {
1424                prepareTxFn.apply( opts.API, [ manual, fwd ] );
1425                return;
1426            }
1427
1428            if ( fwd && opts.currSlide == ( opts.slideCount-1) ) {
1429                slide = slides[ 0 ];
1430                slides = slides.slice( 1 );
1431                opts.container.one('cycle-slide-added', function(e, opts ) {
1432                    setTimeout(function() {
1433                        opts.API.advanceSlide( 1 );
1434                    },50);
1435                });
1436                opts.API.add( slide );
1437            }
1438            else if ( !fwd && opts.currSlide === 0 ) {
1439                index = slides.length-1;
1440                slide = slides[ index ];
1441                slides = slides.slice( 0, index );
1442                opts.container.one('cycle-slide-added', function(e, opts ) {
1443                    setTimeout(function() {
1444                        opts.currSlide = 1;
1445                        opts.API.advanceSlide( -1 );
1446                    },50);
1447                });
1448                opts.API.add( slide, true );
1449            }
1450            else {
1451                prepareTxFn.apply( opts.API, [ manual, fwd ] );
1452            }
1453        };
1454    }
1455
1456    if ( nextFn ) {
1457        API.next = function() {
1458            var opts = this.opts();
1459            if ( slides.length && opts.currSlide == ( opts.slideCount - 1 ) ) {
1460                var slide = slides[ 0 ];
1461                slides = slides.slice( 1 );
1462                opts.container.one('cycle-slide-added', function(e, opts ) {
1463                    nextFn.apply( opts.API );
1464                    opts.container.removeClass('cycle-loading');
1465                });
1466                opts.container.addClass('cycle-loading');
1467                opts.API.add( slide );
1468            }
1469            else {
1470                nextFn.apply( opts.API );    
1471            }
1472        };
1473    }
1474    
1475    if ( prevFn ) {
1476        API.prev = function() {
1477            var opts = this.opts();
1478            if ( slides.length && opts.currSlide === 0 ) {
1479                var index = slides.length-1;
1480                var slide = slides[ index ];
1481                slides = slides.slice( 0, index );
1482                opts.container.one('cycle-slide-added', function(e, opts ) {
1483                    opts.currSlide = 1;
1484                    opts.API.advanceSlide( -1 );
1485                    opts.container.removeClass('cycle-loading');
1486                });
1487                opts.container.addClass('cycle-loading');
1488                opts.API.add( slide, true );
1489            }
1490            else {
1491                prevFn.apply( opts.API );
1492            }
1493        };
1494    }
1495});
1496
1497})(jQuery);
1498
1499/*! tmpl plugin for Cycle2;  version: 20121227 */
1500(function($) {
1501"use strict";
1502
1503$.extend($.fn.cycle.defaults, {
1504    tmplRegex: '{{((.)?.*?)}}'
1505});
1506
1507$.extend($.fn.cycle.API, {
1508    tmpl: function( str, opts /*, ... */) {
1509        var regex = new RegExp( opts.tmplRegex || $.fn.cycle.defaults.tmplRegex, 'g' );
1510        var args = $.makeArray( arguments );
1511        args.shift();
1512        return str.replace(regex, function(_, str) {
1513            var i, j, obj, prop, names = str.split('.');
1514            for (i=0; i < args.length; i++) {
1515                obj = args[i];
1516                if ( ! obj )
1517                    continue;
1518                if (names.length > 1) {
1519                    prop = obj;
1520                    for (j=0; j < names.length; j++) {
1521                        obj = prop;
1522                        prop = prop[ names[j] ] || str;
1523                    }
1524                } else {
1525                    prop = obj[str];
1526                }
1527
1528                if ($.isFunction(prop))
1529                    return prop.apply(obj, args);
1530                if (prop !== undefined && prop !== null && prop != str)
1531                    return prop;
1532            }
1533            return str;
1534        });
1535    }
1536});    
1537
1538})(jQuery);

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.