diff -r e5421b704368 -r 6cd5bc3dc7a2 web/static/res/js/popcorn-complete.js --- a/web/static/res/js/popcorn-complete.js Fri Nov 16 12:53:58 2012 +0100 +++ b/web/static/res/js/popcorn-complete.js Sun Dec 09 19:59:03 2012 +0100 @@ -2218,542 +2218,542 @@ global.Popcorn = Popcorn; })(window, window.document); -/*! - * Popcorn.sequence - * - * Copyright 2011, Rick Waldron - * Licensed under MIT license. - * - */ - -/* jslint forin: true, maxerr: 50, indent: 4, es5: true */ -/* global Popcorn: true */ - -// Requires Popcorn.js -(function( global, Popcorn ) { - - // TODO: as support increases, migrate to element.dataset - var doc = global.document, - location = global.location, - rprotocol = /:\/\//, - // TODO: better solution to this sucky stop-gap - lochref = location.href.replace( location.href.split("/").slice(-1)[0], "" ), - // privately held - range = function(start, stop, step) { - - start = start || 0; - stop = ( stop || start || 0 ) + 1; - step = step || 1; - - var len = Math.ceil((stop - start) / step) || 0, - idx = 0, - range = []; - - range.length = len; - - while (idx < len) { - range[idx++] = start; - start += step; - } - return range; - }; - - Popcorn.sequence = function( parent, list ) { - return new Popcorn.sequence.init( parent, list ); - }; - - Popcorn.sequence.init = function( parent, list ) { - - // Video element - this.parent = doc.getElementById( parent ); - - // Store ref to a special ID - this.seqId = Popcorn.guid( "__sequenced" ); - - // List of HTMLVideoElements - this.queue = []; - - // List of Popcorn objects - this.playlist = []; - - // Lists of in/out points - this.inOuts = { - - // Stores the video in/out times for each video in sequence - ofVideos: [], - - // Stores the clip in/out times for each clip in sequences - ofClips: [] - - }; - - // Store first video dimensions - this.dims = { - width: 0, //this.video.videoWidth, - height: 0 //this.video.videoHeight - }; - - this.active = 0; - this.cycling = false; - this.playing = false; - - this.times = { - last: 0 - }; - - // Store event pointers and queues - this.events = { - - }; - - var self = this, - clipOffset = 0; - - // Create `video` elements - Popcorn.forEach( list, function( media, idx ) { - - var video = doc.createElement( "video" ); - - video.preload = "auto"; - - // Setup newly created video element - video.controls = true; - - // If the first, show it, if the after, hide it - video.style.display = ( idx && "none" ) || "" ; - - // Seta registered sequence id - video.id = self.seqId + "-" + idx ; - - // Push this video into the sequence queue - self.queue.push( video ); - - var //satisfy lint - mIn = media["in"], - mOut = media["out"]; - - // Push the in/out points into sequence ioVideos - self.inOuts.ofVideos.push({ - "in": ( mIn !== undefined && mIn ) || 1, - "out": ( mOut !== undefined && mOut ) || 0 - }); - - self.inOuts.ofVideos[ idx ]["out"] = self.inOuts.ofVideos[ idx ]["out"] || self.inOuts.ofVideos[ idx ]["in"] + 2; - - // Set the sources - video.src = !rprotocol.test( media.src ) ? lochref + media.src : media.src; - - // Set some squence specific data vars - video.setAttribute("data-sequence-owner", parent ); - video.setAttribute("data-sequence-guid", self.seqId ); - video.setAttribute("data-sequence-id", idx ); - video.setAttribute("data-sequence-clip", [ self.inOuts.ofVideos[ idx ]["in"], self.inOuts.ofVideos[ idx ]["out"] ].join(":") ); - - // Append the video to the parent element - self.parent.appendChild( video ); - - - self.playlist.push( Popcorn("#" + video.id ) ); - - }); - - self.inOuts.ofVideos.forEach(function( obj ) { - - var clipDuration = obj["out"] - obj["in"], - offs = { - "in": clipOffset, - "out": clipOffset + clipDuration - }; - - self.inOuts.ofClips.push( offs ); - - clipOffset = offs["out"] + 1; - }); - - Popcorn.forEach( this.queue, function( media, idx ) { - - function canPlayThrough( event ) { - - // If this is idx zero, use it as dimension for all - if ( !idx ) { - self.dims.width = media.videoWidth; - self.dims.height = media.videoHeight; - } - - media.currentTime = self.inOuts.ofVideos[ idx ]["in"] - 0.5; - - media.removeEventListener( "canplaythrough", canPlayThrough, false ); - - return true; - } - - // Hook up event listeners for managing special playback - media.addEventListener( "canplaythrough", canPlayThrough, false ); - - // TODO: consolidate & DRY - media.addEventListener( "play", function( event ) { - - self.playing = true; - - }, false ); - - media.addEventListener( "pause", function( event ) { - - self.playing = false; - - }, false ); - - media.addEventListener( "timeupdate", function( event ) { - - var target = event.srcElement || event.target, - seqIdx = +( (target.dataset && target.dataset.sequenceId) || target.getAttribute("data-sequence-id") ), - floor = Math.floor( media.currentTime ); - - if ( self.times.last !== floor && - seqIdx === self.active ) { - - self.times.last = floor; - - if ( floor === self.inOuts.ofVideos[ seqIdx ]["out"] ) { - - Popcorn.sequence.cycle.call( self, seqIdx ); - } - } - }, false ); - }); - - return this; - }; - - Popcorn.sequence.init.prototype = Popcorn.sequence.prototype; - - // - Popcorn.sequence.cycle = function( idx ) { - - if ( !this.queue ) { - Popcorn.error("Popcorn.sequence.cycle is not a public method"); - } - - var // Localize references - queue = this.queue, - ioVideos = this.inOuts.ofVideos, - current = queue[ idx ], - nextIdx = 0, - next, clip; - - - var // Popcorn instances - $popnext, - $popprev; - - - if ( queue[ idx + 1 ] ) { - nextIdx = idx + 1; - } - - // Reset queue - if ( !queue[ idx + 1 ] ) { - - nextIdx = 0; - this.playlist[ idx ].pause(); - - } else { - - next = queue[ nextIdx ]; - clip = ioVideos[ nextIdx ]; - - // Constrain dimentions - Popcorn.extend( next, { - width: this.dims.width, - height: this.dims.height - }); - - $popnext = this.playlist[ nextIdx ]; - $popprev = this.playlist[ idx ]; - - // When not resetting to 0 - current.pause(); - - this.active = nextIdx; - this.times.last = clip["in"] - 1; - - // Play the next video in the sequence - $popnext.currentTime( clip["in"] ); - - $popnext[ nextIdx ? "play" : "pause" ](); - - // Trigger custom cycling event hook - this.trigger( "cycle", { - - position: { - previous: idx, - current: nextIdx - } - - }); - - // Set the previous back to it's beginning time - // $popprev.currentTime( ioVideos[ idx ].in ); - - if ( nextIdx ) { - // Hide the currently ending video - current.style.display = "none"; - // Show the next video in the sequence - next.style.display = ""; - } - - this.cycling = false; - } - - return this; - }; - - var excludes = [ "timeupdate", "play", "pause" ]; - - // Sequence object prototype - Popcorn.extend( Popcorn.sequence.prototype, { - - // Returns Popcorn object from sequence at index - eq: function( idx ) { - return this.playlist[ idx ]; - }, - // Remove a sequence from it's playback display container - remove: function() { - this.parent.innerHTML = null; - }, - // Returns Clip object from sequence at index - clip: function( idx ) { - return this.inOuts.ofVideos[ idx ]; - }, - // Returns sum duration for all videos in sequence - duration: function() { - - var ret = 0, - seq = this.inOuts.ofClips, - idx = 0; - - for ( ; idx < seq.length; idx++ ) { - ret += seq[ idx ]["out"] - seq[ idx ]["in"] + 1; - } - - return ret - 1; - }, - - play: function() { - - this.playlist[ this.active ].play(); - - return this; - }, - // Attach an event to a single point in time - exec: function ( time, fn ) { - - var index = this.active; - - this.inOuts.ofClips.forEach(function( off, idx ) { - if ( time >= off["in"] && time <= off["out"] ) { - index = idx; - } - }); - - //offsetBy = time - self.inOuts.ofVideos[ index ].in; - - time += this.inOuts.ofVideos[ index ]["in"] - this.inOuts.ofClips[ index ]["in"]; - - // Creating a one second track event with an empty end - Popcorn.addTrackEvent( this.playlist[ index ], { - start: time - 1, - end: time, - _running: false, - _natives: { - start: fn || Popcorn.nop, - end: Popcorn.nop, - type: "exec" - } - }); - - return this; - }, - // Binds event handlers that fire only when all - // videos in sequence have heard the event - listen: function( type, callback ) { - - var self = this, - seq = this.playlist, - total = seq.length, - count = 0, - fnName; - - if ( !callback ) { - callback = Popcorn.nop; - } - - // Handling for DOM and Media events - if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) { - Popcorn.forEach( seq, function( video ) { - - video.listen( type, function( event ) { - - event.active = self; - - if ( excludes.indexOf( type ) > -1 ) { - - callback.call( video, event ); - - } else { - if ( ++count === total ) { - callback.call( video, event ); - } - } - }); - }); - - } else { - - // If no events registered with this name, create a cache - if ( !this.events[ type ] ) { - this.events[ type ] = {}; - } - - // Normalize a callback name key - fnName = callback.name || Popcorn.guid( "__" + type ); - - // Store in event cache - this.events[ type ][ fnName ] = callback; - } - - // Return the sequence object - return this; - }, - unlisten: function( type, name ) { - // TODO: finish implementation - }, - trigger: function( type, data ) { - var self = this; - - // Handling for DOM and Media events - if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) { - - // find the active video and trigger api events on that video. - return; - - } else { - - // Only proceed if there are events of this type - // currently registered on the sequence - if ( this.events[ type ] ) { - - Popcorn.forEach( this.events[ type ], function( callback, name ) { - callback.call( self, { type: type }, data ); - }); - - } - } - - return this; - } - }); - - - Popcorn.forEach( Popcorn.manifest, function( obj, plugin ) { - - // Implement passthrough methods to plugins - Popcorn.sequence.prototype[ plugin ] = function( options ) { - - // console.log( this, options ); - var videos = {}, assignTo = [], - idx, off, inOuts, inIdx, outIdx, keys, clip, clipInOut, clipRange; - - for ( idx = 0; idx < this.inOuts.ofClips.length; idx++ ) { - // store reference - off = this.inOuts.ofClips[ idx ]; - // array to test against - inOuts = range( off["in"], off["out"] ); - - inIdx = inOuts.indexOf( options.start ); - outIdx = inOuts.indexOf( options.end ); - - if ( inIdx > -1 ) { - videos[ idx ] = Popcorn.extend( {}, off, { - start: inOuts[ inIdx ], - clipIdx: inIdx - }); - } - - if ( outIdx > -1 ) { - videos[ idx ] = Popcorn.extend( {}, off, { - end: inOuts[ outIdx ], - clipIdx: outIdx - }); - } - } - - keys = Object.keys( videos ).map(function( val ) { - return +val; - }); - - assignTo = range( keys[ 0 ], keys[ 1 ] ); - - //console.log( "PLUGIN CALL MAPS: ", videos, keys, assignTo ); - for ( idx = 0; idx < assignTo.length; idx++ ) { - - var compile = {}, - play = assignTo[ idx ], - vClip = videos[ play ]; - - if ( vClip ) { - - // has instructions - clip = this.inOuts.ofVideos[ play ]; - clipInOut = vClip.clipIdx; - clipRange = range( clip["in"], clip["out"] ); - - if ( vClip.start ) { - compile.start = clipRange[ clipInOut ]; - compile.end = clipRange[ clipRange.length - 1 ]; - } - - if ( vClip.end ) { - compile.start = clipRange[ 0 ]; - compile.end = clipRange[ clipInOut ]; - } - - //compile.start += 0.1; - //compile.end += 0.9; - - } else { - - compile.start = this.inOuts.ofVideos[ play ]["in"]; - compile.end = this.inOuts.ofVideos[ play ]["out"]; - - //compile.start += 0.1; - //compile.end += 0.9; - - } - - // Handling full clip persistance - //if ( compile.start === compile.end ) { - //compile.start -= 0.1; - //compile.end += 0.9; - //} - - // Call the plugin on the appropriate Popcorn object in the playlist - // Merge original options object & compiled (start/end) object into - // a new fresh object - this.playlist[ play ][ plugin ]( - - Popcorn.extend( {}, options, compile ) - - ); - - } - - // Return the sequence object - return this; - }; - - }); -})( this, Popcorn ); +/*! + * Popcorn.sequence + * + * Copyright 2011, Rick Waldron + * Licensed under MIT license. + * + */ + +/* jslint forin: true, maxerr: 50, indent: 4, es5: true */ +/* global Popcorn: true */ + +// Requires Popcorn.js +(function( global, Popcorn ) { + + // TODO: as support increases, migrate to element.dataset + var doc = global.document, + location = global.location, + rprotocol = /:\/\//, + // TODO: better solution to this sucky stop-gap + lochref = location.href.replace( location.href.split("/").slice(-1)[0], "" ), + // privately held + range = function(start, stop, step) { + + start = start || 0; + stop = ( stop || start || 0 ) + 1; + step = step || 1; + + var len = Math.ceil((stop - start) / step) || 0, + idx = 0, + range = []; + + range.length = len; + + while (idx < len) { + range[idx++] = start; + start += step; + } + return range; + }; + + Popcorn.sequence = function( parent, list ) { + return new Popcorn.sequence.init( parent, list ); + }; + + Popcorn.sequence.init = function( parent, list ) { + + // Video element + this.parent = doc.getElementById( parent ); + + // Store ref to a special ID + this.seqId = Popcorn.guid( "__sequenced" ); + + // List of HTMLVideoElements + this.queue = []; + + // List of Popcorn objects + this.playlist = []; + + // Lists of in/out points + this.inOuts = { + + // Stores the video in/out times for each video in sequence + ofVideos: [], + + // Stores the clip in/out times for each clip in sequences + ofClips: [] + + }; + + // Store first video dimensions + this.dims = { + width: 0, //this.video.videoWidth, + height: 0 //this.video.videoHeight + }; + + this.active = 0; + this.cycling = false; + this.playing = false; + + this.times = { + last: 0 + }; + + // Store event pointers and queues + this.events = { + + }; + + var self = this, + clipOffset = 0; + + // Create `video` elements + Popcorn.forEach( list, function( media, idx ) { + + var video = doc.createElement( "video" ); + + video.preload = "auto"; + + // Setup newly created video element + video.controls = true; + + // If the first, show it, if the after, hide it + video.style.display = ( idx && "none" ) || "" ; + + // Seta registered sequence id + video.id = self.seqId + "-" + idx ; + + // Push this video into the sequence queue + self.queue.push( video ); + + var //satisfy lint + mIn = media["in"], + mOut = media["out"]; + + // Push the in/out points into sequence ioVideos + self.inOuts.ofVideos.push({ + "in": ( mIn !== undefined && mIn ) || 1, + "out": ( mOut !== undefined && mOut ) || 0 + }); + + self.inOuts.ofVideos[ idx ]["out"] = self.inOuts.ofVideos[ idx ]["out"] || self.inOuts.ofVideos[ idx ]["in"] + 2; + + // Set the sources + video.src = !rprotocol.test( media.src ) ? lochref + media.src : media.src; + + // Set some squence specific data vars + video.setAttribute("data-sequence-owner", parent ); + video.setAttribute("data-sequence-guid", self.seqId ); + video.setAttribute("data-sequence-id", idx ); + video.setAttribute("data-sequence-clip", [ self.inOuts.ofVideos[ idx ]["in"], self.inOuts.ofVideos[ idx ]["out"] ].join(":") ); + + // Append the video to the parent element + self.parent.appendChild( video ); + + + self.playlist.push( Popcorn("#" + video.id ) ); + + }); + + self.inOuts.ofVideos.forEach(function( obj ) { + + var clipDuration = obj["out"] - obj["in"], + offs = { + "in": clipOffset, + "out": clipOffset + clipDuration + }; + + self.inOuts.ofClips.push( offs ); + + clipOffset = offs["out"] + 1; + }); + + Popcorn.forEach( this.queue, function( media, idx ) { + + function canPlayThrough( event ) { + + // If this is idx zero, use it as dimension for all + if ( !idx ) { + self.dims.width = media.videoWidth; + self.dims.height = media.videoHeight; + } + + media.currentTime = self.inOuts.ofVideos[ idx ]["in"] - 0.5; + + media.removeEventListener( "canplaythrough", canPlayThrough, false ); + + return true; + } + + // Hook up event listeners for managing special playback + media.addEventListener( "canplaythrough", canPlayThrough, false ); + + // TODO: consolidate & DRY + media.addEventListener( "play", function( event ) { + + self.playing = true; + + }, false ); + + media.addEventListener( "pause", function( event ) { + + self.playing = false; + + }, false ); + + media.addEventListener( "timeupdate", function( event ) { + + var target = event.srcElement || event.target, + seqIdx = +( (target.dataset && target.dataset.sequenceId) || target.getAttribute("data-sequence-id") ), + floor = Math.floor( media.currentTime ); + + if ( self.times.last !== floor && + seqIdx === self.active ) { + + self.times.last = floor; + + if ( floor === self.inOuts.ofVideos[ seqIdx ]["out"] ) { + + Popcorn.sequence.cycle.call( self, seqIdx ); + } + } + }, false ); + }); + + return this; + }; + + Popcorn.sequence.init.prototype = Popcorn.sequence.prototype; + + // + Popcorn.sequence.cycle = function( idx ) { + + if ( !this.queue ) { + Popcorn.error("Popcorn.sequence.cycle is not a public method"); + } + + var // Localize references + queue = this.queue, + ioVideos = this.inOuts.ofVideos, + current = queue[ idx ], + nextIdx = 0, + next, clip; + + + var // Popcorn instances + $popnext, + $popprev; + + + if ( queue[ idx + 1 ] ) { + nextIdx = idx + 1; + } + + // Reset queue + if ( !queue[ idx + 1 ] ) { + + nextIdx = 0; + this.playlist[ idx ].pause(); + + } else { + + next = queue[ nextIdx ]; + clip = ioVideos[ nextIdx ]; + + // Constrain dimentions + Popcorn.extend( next, { + width: this.dims.width, + height: this.dims.height + }); + + $popnext = this.playlist[ nextIdx ]; + $popprev = this.playlist[ idx ]; + + // When not resetting to 0 + current.pause(); + + this.active = nextIdx; + this.times.last = clip["in"] - 1; + + // Play the next video in the sequence + $popnext.currentTime( clip["in"] ); + + $popnext[ nextIdx ? "play" : "pause" ](); + + // Trigger custom cycling event hook + this.trigger( "cycle", { + + position: { + previous: idx, + current: nextIdx + } + + }); + + // Set the previous back to it's beginning time + // $popprev.currentTime( ioVideos[ idx ].in ); + + if ( nextIdx ) { + // Hide the currently ending video + current.style.display = "none"; + // Show the next video in the sequence + next.style.display = ""; + } + + this.cycling = false; + } + + return this; + }; + + var excludes = [ "timeupdate", "play", "pause" ]; + + // Sequence object prototype + Popcorn.extend( Popcorn.sequence.prototype, { + + // Returns Popcorn object from sequence at index + eq: function( idx ) { + return this.playlist[ idx ]; + }, + // Remove a sequence from it's playback display container + remove: function() { + this.parent.innerHTML = null; + }, + // Returns Clip object from sequence at index + clip: function( idx ) { + return this.inOuts.ofVideos[ idx ]; + }, + // Returns sum duration for all videos in sequence + duration: function() { + + var ret = 0, + seq = this.inOuts.ofClips, + idx = 0; + + for ( ; idx < seq.length; idx++ ) { + ret += seq[ idx ]["out"] - seq[ idx ]["in"] + 1; + } + + return ret - 1; + }, + + play: function() { + + this.playlist[ this.active ].play(); + + return this; + }, + // Attach an event to a single point in time + exec: function ( time, fn ) { + + var index = this.active; + + this.inOuts.ofClips.forEach(function( off, idx ) { + if ( time >= off["in"] && time <= off["out"] ) { + index = idx; + } + }); + + //offsetBy = time - self.inOuts.ofVideos[ index ].in; + + time += this.inOuts.ofVideos[ index ]["in"] - this.inOuts.ofClips[ index ]["in"]; + + // Creating a one second track event with an empty end + Popcorn.addTrackEvent( this.playlist[ index ], { + start: time - 1, + end: time, + _running: false, + _natives: { + start: fn || Popcorn.nop, + end: Popcorn.nop, + type: "exec" + } + }); + + return this; + }, + // Binds event handlers that fire only when all + // videos in sequence have heard the event + listen: function( type, callback ) { + + var self = this, + seq = this.playlist, + total = seq.length, + count = 0, + fnName; + + if ( !callback ) { + callback = Popcorn.nop; + } + + // Handling for DOM and Media events + if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) { + Popcorn.forEach( seq, function( video ) { + + video.listen( type, function( event ) { + + event.active = self; + + if ( excludes.indexOf( type ) > -1 ) { + + callback.call( video, event ); + + } else { + if ( ++count === total ) { + callback.call( video, event ); + } + } + }); + }); + + } else { + + // If no events registered with this name, create a cache + if ( !this.events[ type ] ) { + this.events[ type ] = {}; + } + + // Normalize a callback name key + fnName = callback.name || Popcorn.guid( "__" + type ); + + // Store in event cache + this.events[ type ][ fnName ] = callback; + } + + // Return the sequence object + return this; + }, + unlisten: function( type, name ) { + // TODO: finish implementation + }, + trigger: function( type, data ) { + var self = this; + + // Handling for DOM and Media events + if ( Popcorn.Events.Natives.indexOf( type ) > -1 ) { + + // find the active video and trigger api events on that video. + return; + + } else { + + // Only proceed if there are events of this type + // currently registered on the sequence + if ( this.events[ type ] ) { + + Popcorn.forEach( this.events[ type ], function( callback, name ) { + callback.call( self, { type: type }, data ); + }); + + } + } + + return this; + } + }); + + + Popcorn.forEach( Popcorn.manifest, function( obj, plugin ) { + + // Implement passthrough methods to plugins + Popcorn.sequence.prototype[ plugin ] = function( options ) { + + // console.log( this, options ); + var videos = {}, assignTo = [], + idx, off, inOuts, inIdx, outIdx, keys, clip, clipInOut, clipRange; + + for ( idx = 0; idx < this.inOuts.ofClips.length; idx++ ) { + // store reference + off = this.inOuts.ofClips[ idx ]; + // array to test against + inOuts = range( off["in"], off["out"] ); + + inIdx = inOuts.indexOf( options.start ); + outIdx = inOuts.indexOf( options.end ); + + if ( inIdx > -1 ) { + videos[ idx ] = Popcorn.extend( {}, off, { + start: inOuts[ inIdx ], + clipIdx: inIdx + }); + } + + if ( outIdx > -1 ) { + videos[ idx ] = Popcorn.extend( {}, off, { + end: inOuts[ outIdx ], + clipIdx: outIdx + }); + } + } + + keys = Object.keys( videos ).map(function( val ) { + return +val; + }); + + assignTo = range( keys[ 0 ], keys[ 1 ] ); + + //console.log( "PLUGIN CALL MAPS: ", videos, keys, assignTo ); + for ( idx = 0; idx < assignTo.length; idx++ ) { + + var compile = {}, + play = assignTo[ idx ], + vClip = videos[ play ]; + + if ( vClip ) { + + // has instructions + clip = this.inOuts.ofVideos[ play ]; + clipInOut = vClip.clipIdx; + clipRange = range( clip["in"], clip["out"] ); + + if ( vClip.start ) { + compile.start = clipRange[ clipInOut ]; + compile.end = clipRange[ clipRange.length - 1 ]; + } + + if ( vClip.end ) { + compile.start = clipRange[ 0 ]; + compile.end = clipRange[ clipInOut ]; + } + + //compile.start += 0.1; + //compile.end += 0.9; + + } else { + + compile.start = this.inOuts.ofVideos[ play ]["in"]; + compile.end = this.inOuts.ofVideos[ play ]["out"]; + + //compile.start += 0.1; + //compile.end += 0.9; + + } + + // Handling full clip persistance + //if ( compile.start === compile.end ) { + //compile.start -= 0.1; + //compile.end += 0.9; + //} + + // Call the plugin on the appropriate Popcorn object in the playlist + // Merge original options object & compiled (start/end) object into + // a new fresh object + this.playlist[ play ][ plugin ]( + + Popcorn.extend( {}, options, compile ) + + ); + + } + + // Return the sequence object + return this; + }; + + }); +})( this, Popcorn ); (function( Popcorn ) { document.addEventListener( "DOMContentLoaded", function() {